From: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
To: Intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org
Cc: "Rob Clark" <robdclark@chromium.org>,
Kenny.Ho@amd.com, "Daniel Vetter" <daniel.vetter@ffwll.ch>,
"Eero Tamminen" <eero.t.tamminen@intel.com>,
"Johannes Weiner" <hannes@cmpxchg.org>,
linux-kernel@vger.kernel.org,
"Stéphane Marchesin" <marcheu@chromium.org>,
"Christian König" <christian.koenig@amd.com>,
"Zefan Li" <lizefan.x@bytedance.com>,
"Dave Airlie" <airlied@redhat.com>, "Tejun Heo" <tj@kernel.org>,
cgroups@vger.kernel.org, "T . J . Mercier" <tjmercier@google.com>
Subject: [PATCH 16/17] cgroup/drm: Expose memory stats
Date: Wed, 12 Jul 2023 12:46:04 +0100 [thread overview]
Message-ID: <20230712114605.519432-17-tvrtko.ursulin@linux.intel.com> (raw)
In-Reply-To: <20230712114605.519432-1-tvrtko.ursulin@linux.intel.com>
From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
With a few DRM drivers exposing per client memory stats via the fdinfo
interface already, we can add support for exposing the same data (albeit
aggregated for cgroup hierarchies) via the drm cgroup controller.
Add some driver callbacks and controller code to use them, walking the
sub-tree, collating the numbers, and presenting them in a new field
name drm.memory.stat.
Example file content:
$ cat drm.memory.stat
card0 region=system total=12898304 shared=0 active=0 resident=12111872 purgeable=167936
card0 region=stolen-system total=0 shared=0 active=0 resident=0 purgeable=0
Data is generated on demand for simplicty of implementation ie. no running
totals are kept or accounted during migrations and such. Various
optimisations such as cheaper collection of data are possible but
deliberately left out for now.
Overall, the feature is deemed to be useful to container orchestration
software (and manual management).
Limits, either soft or hard, are not envisaged to be implemented on top of
this approach due on demand nature of collecting the stats.
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Eero Tamminen <eero.t.tamminen@intel.com>
---
Documentation/admin-guide/cgroup-v2.rst | 22 ++++
include/drm/drm_drv.h | 61 ++++++++++
kernel/cgroup/drm.c | 149 ++++++++++++++++++++++++
3 files changed, 232 insertions(+)
diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst
index bbe986366f4a..1891c7d98206 100644
--- a/Documentation/admin-guide/cgroup-v2.rst
+++ b/Documentation/admin-guide/cgroup-v2.rst
@@ -2452,6 +2452,28 @@ DRM scheduling soft limits interface files
Standard cgroup weight based control [1, 10000] used to configure the
relative distributing of GPU time between the sibling groups.
+ drm.memory.stat
+ A nested file containing cumulative memory statistics for the whole
+ sub-hierarchy, broken down into separate GPUs and separate memory
+ regions supported by the latter.
+
+ For example::
+
+ $ cat drm.memory.stat
+ card0 region=system total=12898304 shared=0 active=0 resident=12111872 purgeable=167936
+ card0 region=stolen-system total=0 shared=0 active=0 resident=0 purgeable=0
+
+ Card designation corresponds to the DRM device names and multiple line
+ entries can be present per card.
+
+ Memory region names should be expected to be driver specific with the
+ exception of 'system' which is standardised and applicable for GPUs
+ which can operate on system memory buffers.
+
+ Sub-keys 'resident' and 'purgeable' are optional.
+
+ Per category region usage is reported in bytes.
+
Misc
----
diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h
index 29e11a87bf75..2ea9a46b5031 100644
--- a/include/drm/drm_drv.h
+++ b/include/drm/drm_drv.h
@@ -41,6 +41,7 @@ struct drm_minor;
struct dma_buf;
struct dma_buf_attachment;
struct drm_display_mode;
+struct drm_memory_stats;
struct drm_mode_create_dumb;
struct drm_printer;
struct sg_table;
@@ -175,6 +176,66 @@ struct drm_cgroup_ops {
* messages sent by the DRM cgroup controller.
*/
int (*signal_budget) (struct drm_file *, u64 used, u64 budget);
+
+
+ /**
+ * @num_memory_regions:
+ *
+ * Optional callback reporting the number of memory regions driver
+ * supports.
+ *
+ * Callback is allowed to report a larger number than present memory
+ * regions, but @memory_region_name is then supposed to return NULL for
+ * those indices.
+ *
+ * Used by the DRM core when queried by the DRM cgroup controller.
+ *
+ * All three callbacks of @num_memory_regions, @memory_region_name and
+ * @memory_stats need to be implemented for DRM cgroup memory stats
+ * support.
+ */
+ unsigned int (*num_memory_regions) (const struct drm_device *);
+
+ /**
+ * @memory_region_name:
+ *
+ * Optional callback reporting the name of the queried memory region.
+ *
+ * Can be NULL if the memory region index is not supported by the
+ * passed in device.
+ *
+ * Used by the DRM core when queried by the DRM cgroup controller.
+ *
+ * All three callbacks of @num_memory_regions, @memory_region_name and
+ * @memory_stats need to be implemented for DRM cgroup memory stats
+ * support.
+ */
+ const char * (*memory_region_name) (const struct drm_device *,
+ unsigned int index);
+
+ /**
+ * memory_stats:
+ *
+ * Optional callback adding to the passed in array of struct
+ * drm_memory_stats objects.
+ *
+ * Number of objects in the array is passed in the @num argument.
+ *
+ * Returns a bitmask of supported enum drm_gem_object_status by the
+ * driver instance.
+ *
+ * Callback is only allow to add to the existing fields and should
+ * never clear them.
+ *
+ * Used by the DRM core when queried by the DRM cgroup controller.
+ *
+ * All three callbacks of @num_memory_regions, @memory_region_name and
+ * @memory_stats need to be implemented for DRM cgroup memory stats
+ * support.
+ */
+ unsigned int (*memory_stats) (struct drm_file *,
+ struct drm_memory_stats *,
+ unsigned int num);
};
/**
diff --git a/kernel/cgroup/drm.c b/kernel/cgroup/drm.c
index 7c20d4ebc634..22fc180dd659 100644
--- a/kernel/cgroup/drm.c
+++ b/kernel/cgroup/drm.c
@@ -5,6 +5,7 @@
#include <linux/cgroup.h>
#include <linux/cgroup_drm.h>
+#include <linux/device.h>
#include <linux/list.h>
#include <linux/moduleparam.h>
#include <linux/mutex.h>
@@ -12,6 +13,8 @@
#include <linux/slab.h>
#include <drm/drm_drv.h>
+#include <drm/drm_file.h>
+#include <drm/drm_gem.h>
struct drm_cgroup_state {
struct cgroup_subsys_state css;
@@ -133,6 +136,147 @@ drmcs_read_total_us(struct cgroup_subsys_state *css, struct cftype *cft)
return val;
}
+struct drmcs_stat {
+ const struct drm_device *dev;
+ const struct drm_cgroup_ops *cg_ops;
+ const char *device_name;
+ unsigned int regions;
+ enum drm_gem_object_status flags;
+ struct drm_memory_stats *stats;
+};
+
+static int drmcs_seq_show_memory(struct seq_file *sf, void *v)
+{
+ struct cgroup_subsys_state *node;
+ struct drmcs_stat *stats = NULL;
+ unsigned int num_devices, i;
+ int ret;
+
+ /*
+ * We could avoid taking the cgroup_lock and just walk the tree under
+ * RCU but then allocating temporary storage becomes a problem. So for
+ * now keep it simple and take the lock.
+ */
+ cgroup_lock();
+
+ /* Protect against client migrations and clients disappearing. */
+ ret = mutex_lock_interruptible(&drmcg_mutex);
+ if (ret) {
+ cgroup_unlock();
+ return ret;
+ }
+
+ num_devices = 0;
+ css_for_each_descendant_pre(node, seq_css(sf)) {
+ struct drm_cgroup_state *drmcs = css_to_drmcs(node);
+ struct drm_file *fpriv;
+
+ list_for_each_entry(fpriv, &drmcs->clients, clink) {
+ const struct drm_cgroup_ops *cg_ops =
+ fpriv->minor->dev->driver->cg_ops;
+ const char *device_name = dev_name(fpriv->minor->kdev);
+ struct drmcs_stat *stat;
+ unsigned int regions;
+
+ /* Does this driver supports memory stats? */
+ if (cg_ops &&
+ cg_ops->num_memory_regions &&
+ cg_ops->memory_region_name &&
+ cg_ops->memory_stats)
+ regions =
+ cg_ops->num_memory_regions(fpriv->minor->dev);
+ else
+ regions = 0;
+
+ if (!regions)
+ continue;
+
+ /* Have we seen this device before? */
+ stat = NULL;
+ for (i = 0; i < num_devices; i++) {
+ if (!strcmp(stats[i].device_name,
+ device_name)) {
+ stat = &stats[i];
+ break;
+ }
+ }
+
+ /* If not allocate space for it. */
+ if (!stat) {
+ stats = krealloc_array(stats, num_devices + 1,
+ sizeof(*stats),
+ GFP_USER);
+ if (!stats) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ stat = &stats[num_devices++];
+ stat->dev = fpriv->minor->dev;
+ stat->cg_ops = cg_ops;
+ stat->device_name = device_name;
+ stat->flags = 0;
+ stat->regions = regions;
+ stat->stats =
+ kcalloc(regions,
+ sizeof(struct drm_memory_stats),
+ GFP_USER);
+ if (!stat->stats) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ }
+
+ /* Accumulate the stats for this device+client. */
+ stat->flags |= cg_ops->memory_stats(fpriv,
+ stat->stats,
+ stat->regions);
+ }
+ }
+
+ for (i = 0; i < num_devices; i++) {
+ struct drmcs_stat *stat = &stats[i];
+ unsigned int j;
+
+ for (j = 0; j < stat->regions; j++) {
+ const char *name =
+ stat->cg_ops->memory_region_name(stat->dev, j);
+
+ if (!name)
+ continue;
+
+ seq_printf(sf,
+ "%s region=%s total=%llu shared=%llu active=%llu",
+ stat->device_name,
+ name,
+ stat->stats[j].private +
+ stat->stats[j].shared,
+ stat->stats[j].shared,
+ stat->stats[j].active);
+
+ if (stat->flags & DRM_GEM_OBJECT_RESIDENT)
+ seq_printf(sf, " resident=%llu",
+ stat->stats[j].resident);
+
+ if (stat->flags & DRM_GEM_OBJECT_PURGEABLE)
+ seq_printf(sf, " purgeable=%llu",
+ stat->stats[j].purgeable);
+
+ seq_puts(sf, "\n");
+ }
+ }
+
+out:
+ mutex_unlock(&drmcg_mutex);
+ cgroup_unlock();
+
+ for (i = 0; i < num_devices; i++)
+ kfree(stats[i].stats);
+ kfree(stats);
+
+ return ret;
+}
+
static bool __start_scanning(unsigned int period_us)
{
struct drm_cgroup_state *root = &root_drmcs.drmcs;
@@ -575,6 +719,11 @@ struct cftype files[] = {
.flags = CFTYPE_NOT_ON_ROOT,
.read_u64 = drmcs_read_total_us,
},
+ {
+ .name = "memory.stat",
+ .flags = CFTYPE_NOT_ON_ROOT,
+ .seq_show = drmcs_seq_show_memory,
+ },
{ } /* Zero entry terminates. */
};
--
2.39.2
next prev parent reply other threads:[~2023-07-12 11:46 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-07-12 11:45 [RFC v5 00/17] DRM cgroup controller with scheduling control and memory stats Tvrtko Ursulin
2023-07-12 11:45 ` [PATCH 01/17] drm/i915: Add ability for tracking buffer objects per client Tvrtko Ursulin
2023-07-12 11:45 ` [PATCH 02/17] drm/i915: Record which client owns a VM Tvrtko Ursulin
2023-07-12 11:45 ` [PATCH 03/17] drm/i915: Track page table backing store usage Tvrtko Ursulin
2023-07-12 11:45 ` [PATCH 04/17] drm/i915: Account ring buffer and context state storage Tvrtko Ursulin
2023-07-12 11:45 ` [PATCH 05/17] drm/i915: Implement fdinfo memory stats printing Tvrtko Ursulin
2023-07-12 11:45 ` [PATCH 06/17] drm: Update file owner during use Tvrtko Ursulin
2023-07-12 11:45 ` [PATCH 07/17] cgroup: Add the DRM cgroup controller Tvrtko Ursulin
2023-07-12 11:45 ` [PATCH 08/17] drm/cgroup: Track DRM clients per cgroup Tvrtko Ursulin
2023-07-21 22:14 ` Tejun Heo
2023-07-12 11:45 ` [PATCH 09/17] drm/cgroup: Add ability to query drm cgroup GPU time Tvrtko Ursulin
2023-07-12 11:45 ` [PATCH 10/17] drm/cgroup: Add over budget signalling callback Tvrtko Ursulin
2023-07-12 11:45 ` [PATCH 11/17] drm/cgroup: Only track clients which are providing drm_cgroup_ops Tvrtko Ursulin
2023-07-12 11:46 ` [PATCH 12/17] cgroup/drm: Introduce weight based drm cgroup control Tvrtko Ursulin
2023-07-21 22:17 ` Tejun Heo
[not found] ` <ZLsEEYDFlJZwrJiV-NiLfg/pYEd1N0TnZuCh8vA@public.gmane.org>
2023-07-25 13:46 ` Tvrtko Ursulin
2023-07-12 11:46 ` [PATCH 13/17] drm/i915: Wire up with drm controller GPU time query Tvrtko Ursulin
2023-07-12 11:46 ` [PATCH 14/17] drm/i915: Implement cgroup controller over budget throttling Tvrtko Ursulin
2023-07-12 11:46 ` [PATCH 15/17] cgroup/drm: Expose GPU utilisation Tvrtko Ursulin
[not found] ` <20230712114605.519432-16-tvrtko.ursulin-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2023-07-21 22:19 ` Tejun Heo
[not found] ` <ZLsEdJeEAPYWFunT-NiLfg/pYEd1N0TnZuCh8vA@public.gmane.org>
2023-07-21 22:20 ` Tejun Heo
2023-07-25 14:08 ` Tvrtko Ursulin
[not found] ` <3b96cada-3433-139c-3180-1f050f0f80f3-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2023-07-25 21:44 ` Tejun Heo
2023-07-12 11:46 ` Tvrtko Ursulin [this message]
[not found] ` <20230712114605.519432-17-tvrtko.ursulin-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2023-07-21 22:21 ` [PATCH 16/17] cgroup/drm: Expose memory stats Tejun Heo
2023-07-26 10:14 ` Maarten Lankhorst
2023-07-26 11:41 ` Tvrtko Ursulin
[not found] ` <89d7181c-6830-ca6e-0c39-caa49d14d474-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2023-07-27 11:54 ` Maarten Lankhorst
2023-07-27 17:08 ` Tvrtko Ursulin
[not found] ` <5d65d387-2718-06c3-ee5d-8a7da6e3ddfd-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2023-07-28 14:15 ` Tvrtko Ursulin
[not found] ` <ea64d7bf-c01b-f4ad-a36b-f77e2c2ea931-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2023-07-26 19:44 ` Tejun Heo
2023-07-27 13:42 ` Maarten Lankhorst
[not found] ` <05178cf3-df1c-80a7-12ad-816fafbc2df7-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2023-07-27 16:43 ` Tvrtko Ursulin
2023-07-26 16:44 ` Tvrtko Ursulin
[not found] ` <8959f665-4353-3630-a6c7-5dca60959faa-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2023-07-26 19:49 ` Tejun Heo
2023-07-12 11:46 ` [PATCH 17/17] drm/i915: Wire up to the drm cgroup " Tvrtko Ursulin
2023-07-19 20:31 ` [RFC v5 00/17] DRM cgroup controller with scheduling control and " T.J. Mercier
[not found] ` <CABdmKX1PUF+X897ZMOr0RNiYdoiL_2NkcSt+Eh55BfW-05LopQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2023-07-20 10:55 ` Tvrtko Ursulin
[not found] ` <95de5c1e-f03b-8fb7-b5ef-59ac7ca82f31-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2023-07-20 17:22 ` T.J. Mercier
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230712114605.519432-17-tvrtko.ursulin@linux.intel.com \
--to=tvrtko.ursulin@linux.intel.com \
--cc=Intel-gfx@lists.freedesktop.org \
--cc=Kenny.Ho@amd.com \
--cc=airlied@redhat.com \
--cc=cgroups@vger.kernel.org \
--cc=christian.koenig@amd.com \
--cc=daniel.vetter@ffwll.ch \
--cc=dri-devel@lists.freedesktop.org \
--cc=eero.t.tamminen@intel.com \
--cc=hannes@cmpxchg.org \
--cc=linux-kernel@vger.kernel.org \
--cc=lizefan.x@bytedance.com \
--cc=marcheu@chromium.org \
--cc=robdclark@chromium.org \
--cc=tj@kernel.org \
--cc=tjmercier@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox