public inbox for drm-ai-reviews@public-inbox.freedesktop.org
 help / color / mirror / Atom feed
* [PATCH v4 0/3] Let userspace know about swapped out panthor GEM objects
@ 2026-05-20 13:04 Nicolas Frattaroli
  2026-05-20 13:04 ` [PATCH v4 1/3] drm/fdinfo: Add "evicted" memory accounting Nicolas Frattaroli
                   ` (3 more replies)
  0 siblings, 4 replies; 12+ messages in thread
From: Nicolas Frattaroli @ 2026-05-20 13:04 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Boris Brezillon, Steven Price, Liviu Dudau,
	Jonathan Corbet, Shuah Khan, Tvrtko Ursulin
  Cc: dri-devel, linux-kernel, kernel, linux-doc, Nicolas Frattaroli

Panthor has recently gained a GEM shrinker. It allows evicting memory
that backs unused GEM objects to swap.

In this series, both fdinfo and Panthor's gems debugfs are extended so
that information on evicted pages can be gathered by users through these
two methods.

---
Changes in v4:
- Change "evicted" memory type documentation to no longer explicitly
  mention swap
- Link to v3: https://patch.msgid.link/20260423-panthor-bo-reclaim-observability-v3-0-60af32164a4f@collabora.com

Changes in v3:
- Add documentation for new "evicted" memory type in fdinfo
- Link to v2: https://patch.msgid.link/20260421-panthor-bo-reclaim-observability-v2-0-c9135eedfb6f@collabora.com

Changes in v2:
- Change reclaimed_count to saturate at INT_MAX
- Add "evictions" column to panthor gems debugfs which prints
  reclaimed_count
- Add a patch to reduce the padding of one panthor gems debugfs column a
  bit
- Link to v1: https://patch.msgid.link/20260420-panthor-bo-reclaim-observability-v1-0-a4d1a36ee84f@collabora.com

To: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
To: Maxime Ripard <mripard@kernel.org>
To: Thomas Zimmermann <tzimmermann@suse.de>
To: David Airlie <airlied@gmail.com>
To: Simona Vetter <simona@ffwll.ch>
To: Boris Brezillon <boris.brezillon@collabora.com>
To: Steven Price <steven.price@arm.com>
To: Liviu Dudau <liviu.dudau@arm.com>
To: Jonathan Corbet <corbet@lwn.net>
To: Shuah Khan <skhan@linuxfoundation.org>
To: Tvrtko Ursulin <tursulin@ursulin.net>
Cc: dri-devel@lists.freedesktop.org
Cc: linux-kernel@vger.kernel.org
Cc: kernel@collabora.com
Cc: linux-doc@vger.kernel.org
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>

---
Nicolas Frattaroli (3):
      drm/fdinfo: Add "evicted" memory accounting
      drm/panthor: Implement evicted status for GEM objects
      drm/panthor: Reduce padding in gems debugfs for refcount

 Documentation/gpu/drm-usage-stats.rst |  6 ++++++
 drivers/gpu/drm/drm_file.c            |  8 ++++++++
 drivers/gpu/drm/panthor/panthor_gem.c | 18 ++++++++++++++----
 drivers/gpu/drm/panthor/panthor_gem.h | 10 ++++++++++
 include/drm/drm_file.h                |  2 ++
 include/drm/drm_gem.h                 |  2 ++
 6 files changed, 42 insertions(+), 4 deletions(-)
---
base-commit: 69c95e4c529297c25503e60acba757fba24fdc95
change-id: 20260420-panthor-bo-reclaim-observability-970679c9533c

Best regards,
--  
Nicolas Frattaroli <nicolas.frattaroli@collabora.com>


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v4 1/3] drm/fdinfo: Add "evicted" memory accounting
  2026-05-20 13:04 [PATCH v4 0/3] Let userspace know about swapped out panthor GEM objects Nicolas Frattaroli
@ 2026-05-20 13:04 ` Nicolas Frattaroli
  2026-05-20 14:19   ` Tvrtko Ursulin
  2026-05-25 11:52   ` Claude review: " Claude Code Review Bot
  2026-05-20 13:04 ` [PATCH v4 2/3] drm/panthor: Implement evicted status for GEM objects Nicolas Frattaroli
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 12+ messages in thread
From: Nicolas Frattaroli @ 2026-05-20 13:04 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Boris Brezillon, Steven Price, Liviu Dudau,
	Jonathan Corbet, Shuah Khan, Tvrtko Ursulin
  Cc: dri-devel, linux-kernel, kernel, linux-doc, Nicolas Frattaroli

Currently, there's no way to know for certain how much GPU memory was
swapped out. The difference between total and resident memory would
include newly allocated pages, which are not resident, but also aren't
swapped out.

Add a new drm_gem_object_status so drivers can signal when an object has
been evicted to swap, and add a new "evicted" counter to
drm_memory_stats.

Due to how the supported_flags bitmask is determined, the "evicted"
count won't be printed to fdinfo if there's no swapped out pages.

Reviewed-by: Steven Price <steven.price@arm.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
 Documentation/gpu/drm-usage-stats.rst | 6 ++++++
 drivers/gpu/drm/drm_file.c            | 8 ++++++++
 include/drm/drm_file.h                | 2 ++
 include/drm/drm_gem.h                 | 2 ++
 4 files changed, 18 insertions(+)

diff --git a/Documentation/gpu/drm-usage-stats.rst b/Documentation/gpu/drm-usage-stats.rst
index 70b7cfcc194f..ac1dbf52d96d 100644
--- a/Documentation/gpu/drm-usage-stats.rst
+++ b/Documentation/gpu/drm-usage-stats.rst
@@ -202,6 +202,12 @@ One practical example of this could be the presence of unsignaled fences in a
 GEM buffer reservation object. Therefore, the active category is a subset of the
 resident category.
 
+- drm-evicted-<region>: <uint> [KiB|MiB]
+
+The total size of buffers that have been evicted and are no longer pinned by the
+device. Only present if there are buffers that are currently evicted, and if the
+driver implements reporting of this type of memory.
+
 Implementation Details
 ======================
 
diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c
index ec820686b302..5078172976c0 100644
--- a/drivers/gpu/drm/drm_file.c
+++ b/drivers/gpu/drm/drm_file.c
@@ -868,6 +868,7 @@ int drm_memory_stats_is_zero(const struct drm_memory_stats *stats)
 		stats->private == 0 &&
 		stats->resident == 0 &&
 		stats->purgeable == 0 &&
+		stats->evicted == 0 &&
 		stats->active == 0);
 }
 EXPORT_SYMBOL(drm_memory_stats_is_zero);
@@ -901,6 +902,10 @@ void drm_print_memory_stats(struct drm_printer *p,
 	if (supported_status & DRM_GEM_OBJECT_PURGEABLE)
 		drm_fdinfo_print_size(p, prefix, "purgeable", region,
 				      stats->purgeable);
+
+	if (supported_status & DRM_GEM_OBJECT_EVICTED)
+		drm_fdinfo_print_size(p, prefix, "evicted", region,
+				      stats->evicted);
 }
 EXPORT_SYMBOL(drm_print_memory_stats);
 
@@ -954,6 +959,9 @@ void drm_show_memory_stats(struct drm_printer *p, struct drm_file *file)
 
 		if (s & DRM_GEM_OBJECT_PURGEABLE)
 			status.purgeable += add_size;
+
+		if (s & DRM_GEM_OBJECT_EVICTED)
+			status.evicted += add_size;
 	}
 	spin_unlock(&file->table_lock);
 
diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h
index 6ee70ad65e1f..7e4cb45a52c3 100644
--- a/include/drm/drm_file.h
+++ b/include/drm/drm_file.h
@@ -500,6 +500,7 @@ void drm_send_event_timestamp_locked(struct drm_device *dev,
  * @resident: Total size of GEM objects backing pages
  * @purgeable: Total size of GEM objects that can be purged (resident and not active)
  * @active: Total size of GEM objects active on one or more engines
+ * @evicted: Total size of GEM objects that have been evicted
  *
  * Used by drm_print_memory_stats()
  */
@@ -509,6 +510,7 @@ struct drm_memory_stats {
 	u64 resident;
 	u64 purgeable;
 	u64 active;
+	u64 evicted;
 };
 
 enum drm_gem_object_status;
diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
index 86f5846154f7..799588a2762a 100644
--- a/include/drm/drm_gem.h
+++ b/include/drm/drm_gem.h
@@ -53,6 +53,7 @@ struct drm_gem_object;
  * @DRM_GEM_OBJECT_RESIDENT: object is resident in memory (ie. not unpinned)
  * @DRM_GEM_OBJECT_PURGEABLE: object marked as purgeable by userspace
  * @DRM_GEM_OBJECT_ACTIVE: object is currently used by an active submission
+ * @DRM_GEM_OBJECT_EVICTED: object is evicted and no longer pinned by driver
  *
  * Bitmask of status used for fdinfo memory stats, see &drm_gem_object_funcs.status
  * and drm_show_fdinfo().  Note that an object can report DRM_GEM_OBJECT_PURGEABLE
@@ -67,6 +68,7 @@ enum drm_gem_object_status {
 	DRM_GEM_OBJECT_RESIDENT  = BIT(0),
 	DRM_GEM_OBJECT_PURGEABLE = BIT(1),
 	DRM_GEM_OBJECT_ACTIVE    = BIT(2),
+	DRM_GEM_OBJECT_EVICTED   = BIT(3),
 };
 
 /**

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v4 2/3] drm/panthor: Implement evicted status for GEM objects
  2026-05-20 13:04 [PATCH v4 0/3] Let userspace know about swapped out panthor GEM objects Nicolas Frattaroli
  2026-05-20 13:04 ` [PATCH v4 1/3] drm/fdinfo: Add "evicted" memory accounting Nicolas Frattaroli
@ 2026-05-20 13:04 ` Nicolas Frattaroli
  2026-05-20 13:24   ` Boris Brezillon
                     ` (2 more replies)
  2026-05-20 13:04 ` [PATCH v4 3/3] drm/panthor: Reduce padding in gems debugfs for refcount Nicolas Frattaroli
  2026-05-25 11:52 ` Claude review: Let userspace know about swapped out panthor GEM objects Claude Code Review Bot
  3 siblings, 3 replies; 12+ messages in thread
From: Nicolas Frattaroli @ 2026-05-20 13:04 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Boris Brezillon, Steven Price, Liviu Dudau,
	Jonathan Corbet, Shuah Khan, Tvrtko Ursulin
  Cc: dri-devel, linux-kernel, kernel, linux-doc, Nicolas Frattaroli

For fdinfo to be able to fill its evicted counter with data, panthor
needs to keep track of whether a GEM object has ever been reclaimed.
Just checking whether the pages are resident isn't enough, as newly
allocated objects also won't be resident.

Do this with a new atomic_t member on panthor_gem_object. It's increased
when an object gets evicted by the shrinker, and saturates at INT_MAX.
This means that once an object has been evicted at least once, its
reclaim counter will never return to 0.

Due to this, it's possible to distinguish evicted non-resident pages
from newly allocated non-resident pages by checking whether
reclaimed_count is != 0

Use this new member to then set the appropriate DRM_GEM_OBJECT_EVICTED
status flag for fdinfo.

Also add a new column and status flag to the panthor gems debugfs: the
column is the number of times an object has been evicted, whereas the
flag indicates whether it currently is evicted.

Reviewed-by: Steven Price <steven.price@arm.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
 drivers/gpu/drm/panthor/panthor_gem.c | 18 ++++++++++++++----
 drivers/gpu/drm/panthor/panthor_gem.h | 10 ++++++++++
 2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c
index 13295d7a593d..068aa935c8fc 100644
--- a/drivers/gpu/drm/panthor/panthor_gem.c
+++ b/drivers/gpu/drm/panthor/panthor_gem.c
@@ -687,6 +687,8 @@ static void panthor_gem_evict_locked(struct panthor_gem_object *bo)
 	if (drm_WARN_ON_ONCE(bo->base.dev, !bo->backing.pages))
 		return;
 
+	atomic_add_unless(&bo->reclaimed_count, 1, INT_MAX);
+
 	panthor_gem_dev_map_cleanup_locked(bo);
 	panthor_gem_backing_cleanup_locked(bo);
 	panthor_gem_update_reclaim_state_locked(bo, NULL);
@@ -788,6 +790,8 @@ static enum drm_gem_object_status panthor_gem_status(struct drm_gem_object *obj)
 
 	if (drm_gem_is_imported(&bo->base) || bo->backing.pages)
 		res |= DRM_GEM_OBJECT_RESIDENT;
+	else if (atomic_read(&bo->reclaimed_count))
+		res |= DRM_GEM_OBJECT_EVICTED;
 
 	return res;
 }
@@ -1595,6 +1599,7 @@ static void panthor_gem_debugfs_print_flag_names(struct seq_file *m)
 	static const char * const gem_state_flags_names[] = {
 		[PANTHOR_DEBUGFS_GEM_STATE_IMPORTED_BIT] = "imported",
 		[PANTHOR_DEBUGFS_GEM_STATE_EXPORTED_BIT] = "exported",
+		[PANTHOR_DEBUGFS_GEM_STATE_EVICTED_BIT] = "evicted",
 	};
 
 	static const char * const gem_usage_flags_names[] = {
@@ -1625,6 +1630,7 @@ static void panthor_gem_debugfs_bo_print(struct panthor_gem_object *bo,
 {
 	enum panthor_gem_reclaim_state reclaim_state = bo->reclaim_state;
 	unsigned int refcount = kref_read(&bo->base.refcount);
+	int reclaimed_count = atomic_read(&bo->reclaimed_count);
 	char creator_info[32] = {};
 	size_t resident_size;
 	u32 gem_usage_flags = bo->debugfs.flags;
@@ -1638,16 +1644,20 @@ static void panthor_gem_debugfs_bo_print(struct panthor_gem_object *bo,
 
 	snprintf(creator_info, sizeof(creator_info),
 		 "%s/%d", bo->debugfs.creator.process_name, bo->debugfs.creator.tgid);
-	seq_printf(m, "%-32s%-16d%-16d%-16zd%-16zd0x%-16lx",
+	seq_printf(m, "%-32s%-16d%-16d%-11d%-16zd%-16zd0x%-16lx",
 		   creator_info,
 		   bo->base.name,
 		   refcount,
+		   reclaimed_count,
 		   bo->base.size,
 		   resident_size,
 		   drm_vma_node_start(&bo->base.vma_node));
 
 	if (drm_gem_is_imported(&bo->base))
 		gem_state_flags |= PANTHOR_DEBUGFS_GEM_STATE_FLAG_IMPORTED;
+	else if (!resident_size && reclaimed_count)
+		gem_state_flags |= PANTHOR_DEBUGFS_GEM_STATE_FLAG_EVICTED;
+
 	if (bo->base.dma_buf)
 		gem_state_flags |= PANTHOR_DEBUGFS_GEM_STATE_FLAG_EXPORTED;
 
@@ -1671,8 +1681,8 @@ static void panthor_gem_debugfs_print_bos(struct panthor_device *ptdev,
 
 	panthor_gem_debugfs_print_flag_names(m);
 
-	seq_puts(m, "created-by                      global-name     refcount        size            resident-size   file-offset       state      usage       label\n");
-	seq_puts(m, "----------------------------------------------------------------------------------------------------------------------------------------------\n");
+	seq_puts(m, "created-by                      global-name     refcount        evictions  size            resident-size   file-offset       state      usage       label\n");
+	seq_puts(m, "---------------------------------------------------------------------------------------------------------------------------------------------------------\n");
 
 	scoped_guard(mutex, &ptdev->gems.lock) {
 		list_for_each_entry(bo, &ptdev->gems.node, debugfs.node) {
@@ -1680,7 +1690,7 @@ static void panthor_gem_debugfs_print_bos(struct panthor_device *ptdev,
 		}
 	}
 
-	seq_puts(m, "==============================================================================================================================================\n");
+	seq_puts(m, "=========================================================================================================================================================\n");
 	seq_printf(m, "Total size: %zd, Total resident: %zd, Total reclaimable: %zd\n",
 		   totals.size, totals.resident, totals.reclaimable);
 }
diff --git a/drivers/gpu/drm/panthor/panthor_gem.h b/drivers/gpu/drm/panthor/panthor_gem.h
index ae0491d0b121..56d63137b4eb 100644
--- a/drivers/gpu/drm/panthor/panthor_gem.h
+++ b/drivers/gpu/drm/panthor/panthor_gem.h
@@ -19,12 +19,16 @@ struct panthor_vm;
 enum panthor_debugfs_gem_state_flags {
 	PANTHOR_DEBUGFS_GEM_STATE_IMPORTED_BIT = 0,
 	PANTHOR_DEBUGFS_GEM_STATE_EXPORTED_BIT = 1,
+	PANTHOR_DEBUGFS_GEM_STATE_EVICTED_BIT = 2,
 
 	/** @PANTHOR_DEBUGFS_GEM_STATE_FLAG_IMPORTED: GEM BO is PRIME imported. */
 	PANTHOR_DEBUGFS_GEM_STATE_FLAG_IMPORTED = BIT(PANTHOR_DEBUGFS_GEM_STATE_IMPORTED_BIT),
 
 	/** @PANTHOR_DEBUGFS_GEM_STATE_FLAG_EXPORTED: GEM BO is PRIME exported. */
 	PANTHOR_DEBUGFS_GEM_STATE_FLAG_EXPORTED = BIT(PANTHOR_DEBUGFS_GEM_STATE_EXPORTED_BIT),
+
+	/** @PANTHOR_DEBUGFS_GEM_STATE_FLAG_EVICTED: GEM BO is evicted to swap. */
+	PANTHOR_DEBUGFS_GEM_STATE_FLAG_EVICTED = BIT(PANTHOR_DEBUGFS_GEM_STATE_EVICTED_BIT),
 };
 
 enum panthor_debugfs_gem_usage_flags {
@@ -172,6 +176,12 @@ struct panthor_gem_object {
 	/** @reclaim_state: Cached reclaim state */
 	enum panthor_gem_reclaim_state reclaim_state;
 
+	/**
+	 * @reclaimed_count: How many times object has been evicted to swap.
+	 * The count saturates at %INT_MAX and will never wrap around to 0.
+	 */
+	atomic_t reclaimed_count;
+
 	/**
 	 * @exclusive_vm_root_gem: Root GEM of the exclusive VM this GEM object
 	 * is attached to.

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v4 3/3] drm/panthor: Reduce padding in gems debugfs for refcount
  2026-05-20 13:04 [PATCH v4 0/3] Let userspace know about swapped out panthor GEM objects Nicolas Frattaroli
  2026-05-20 13:04 ` [PATCH v4 1/3] drm/fdinfo: Add "evicted" memory accounting Nicolas Frattaroli
  2026-05-20 13:04 ` [PATCH v4 2/3] drm/panthor: Implement evicted status for GEM objects Nicolas Frattaroli
@ 2026-05-20 13:04 ` Nicolas Frattaroli
  2026-05-25 11:52   ` Claude review: " Claude Code Review Bot
  2026-05-25 11:52 ` Claude review: Let userspace know about swapped out panthor GEM objects Claude Code Review Bot
  3 siblings, 1 reply; 12+ messages in thread
From: Nicolas Frattaroli @ 2026-05-20 13:04 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Boris Brezillon, Steven Price, Liviu Dudau,
	Jonathan Corbet, Shuah Khan, Tvrtko Ursulin
  Cc: dri-devel, linux-kernel, kernel, linux-doc, Nicolas Frattaroli

The "gems" debugfs file is getting a little too wide for comfort. While
a lot of this is unavoidable due to the theoretical upper limits of
numbers here (e.g. size needs to be 16 chars because 2**48-1 in decimal
is 15 digits, plus one space for separation), the refcount column has a
decent 5 characters to be saved, as it can only ever contain a 10-digit
decimal number.

Reduce the refcount column's width to 11, which fulfils this requirement
with an additional space for separation.

Reviewed-by: Steven Price <steven.price@arm.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
 drivers/gpu/drm/panthor/panthor_gem.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c
index 068aa935c8fc..dfdcda3d0189 100644
--- a/drivers/gpu/drm/panthor/panthor_gem.c
+++ b/drivers/gpu/drm/panthor/panthor_gem.c
@@ -1644,7 +1644,7 @@ static void panthor_gem_debugfs_bo_print(struct panthor_gem_object *bo,
 
 	snprintf(creator_info, sizeof(creator_info),
 		 "%s/%d", bo->debugfs.creator.process_name, bo->debugfs.creator.tgid);
-	seq_printf(m, "%-32s%-16d%-16d%-11d%-16zd%-16zd0x%-16lx",
+	seq_printf(m, "%-32s%-16d%-11d%-11d%-16zd%-16zd0x%-16lx",
 		   creator_info,
 		   bo->base.name,
 		   refcount,
@@ -1681,8 +1681,8 @@ static void panthor_gem_debugfs_print_bos(struct panthor_device *ptdev,
 
 	panthor_gem_debugfs_print_flag_names(m);
 
-	seq_puts(m, "created-by                      global-name     refcount        evictions  size            resident-size   file-offset       state      usage       label\n");
-	seq_puts(m, "---------------------------------------------------------------------------------------------------------------------------------------------------------\n");
+	seq_puts(m, "created-by                      global-name     refcount   evictions  size            resident-size   file-offset       state      usage       label\n");
+	seq_puts(m, "----------------------------------------------------------------------------------------------------------------------------------------------------\n");
 
 	scoped_guard(mutex, &ptdev->gems.lock) {
 		list_for_each_entry(bo, &ptdev->gems.node, debugfs.node) {
@@ -1690,7 +1690,7 @@ static void panthor_gem_debugfs_print_bos(struct panthor_device *ptdev,
 		}
 	}
 
-	seq_puts(m, "=========================================================================================================================================================\n");
+	seq_puts(m, "====================================================================================================================================================\n");
 	seq_printf(m, "Total size: %zd, Total resident: %zd, Total reclaimable: %zd\n",
 		   totals.size, totals.resident, totals.reclaimable);
 }

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v4 2/3] drm/panthor: Implement evicted status for GEM objects
  2026-05-20 13:04 ` [PATCH v4 2/3] drm/panthor: Implement evicted status for GEM objects Nicolas Frattaroli
@ 2026-05-20 13:24   ` Boris Brezillon
  2026-05-20 14:33   ` Boris Brezillon
  2026-05-25 11:52   ` Claude review: " Claude Code Review Bot
  2 siblings, 0 replies; 12+ messages in thread
From: Boris Brezillon @ 2026-05-20 13:24 UTC (permalink / raw)
  To: Nicolas Frattaroli
  Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Steven Price, Liviu Dudau, Jonathan Corbet,
	Shuah Khan, Tvrtko Ursulin, dri-devel, linux-kernel, kernel,
	linux-doc

On Wed, 20 May 2026 15:04:49 +0200
Nicolas Frattaroli <nicolas.frattaroli@collabora.com> wrote:

> For fdinfo to be able to fill its evicted counter with data, panthor
> needs to keep track of whether a GEM object has ever been reclaimed.
> Just checking whether the pages are resident isn't enough, as newly
> allocated objects also won't be resident.
> 
> Do this with a new atomic_t member on panthor_gem_object. It's increased
> when an object gets evicted by the shrinker, and saturates at INT_MAX.
> This means that once an object has been evicted at least once, its
> reclaim counter will never return to 0.
> 
> Due to this, it's possible to distinguish evicted non-resident pages
> from newly allocated non-resident pages by checking whether
> reclaimed_count is != 0
> 
> Use this new member to then set the appropriate DRM_GEM_OBJECT_EVICTED
> status flag for fdinfo.
> 
> Also add a new column and status flag to the panthor gems debugfs: the
> column is the number of times an object has been evicted, whereas the
> flag indicates whether it currently is evicted.
> 
> Reviewed-by: Steven Price <steven.price@arm.com>
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>

Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>

> ---
>  drivers/gpu/drm/panthor/panthor_gem.c | 18 ++++++++++++++----
>  drivers/gpu/drm/panthor/panthor_gem.h | 10 ++++++++++
>  2 files changed, 24 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c
> index 13295d7a593d..068aa935c8fc 100644
> --- a/drivers/gpu/drm/panthor/panthor_gem.c
> +++ b/drivers/gpu/drm/panthor/panthor_gem.c
> @@ -687,6 +687,8 @@ static void panthor_gem_evict_locked(struct panthor_gem_object *bo)
>  	if (drm_WARN_ON_ONCE(bo->base.dev, !bo->backing.pages))
>  		return;
>  
> +	atomic_add_unless(&bo->reclaimed_count, 1, INT_MAX);
> +
>  	panthor_gem_dev_map_cleanup_locked(bo);
>  	panthor_gem_backing_cleanup_locked(bo);
>  	panthor_gem_update_reclaim_state_locked(bo, NULL);
> @@ -788,6 +790,8 @@ static enum drm_gem_object_status panthor_gem_status(struct drm_gem_object *obj)
>  
>  	if (drm_gem_is_imported(&bo->base) || bo->backing.pages)
>  		res |= DRM_GEM_OBJECT_RESIDENT;
> +	else if (atomic_read(&bo->reclaimed_count))
> +		res |= DRM_GEM_OBJECT_EVICTED;
>  
>  	return res;
>  }
> @@ -1595,6 +1599,7 @@ static void panthor_gem_debugfs_print_flag_names(struct seq_file *m)
>  	static const char * const gem_state_flags_names[] = {
>  		[PANTHOR_DEBUGFS_GEM_STATE_IMPORTED_BIT] = "imported",
>  		[PANTHOR_DEBUGFS_GEM_STATE_EXPORTED_BIT] = "exported",
> +		[PANTHOR_DEBUGFS_GEM_STATE_EVICTED_BIT] = "evicted",
>  	};
>  
>  	static const char * const gem_usage_flags_names[] = {
> @@ -1625,6 +1630,7 @@ static void panthor_gem_debugfs_bo_print(struct panthor_gem_object *bo,
>  {
>  	enum panthor_gem_reclaim_state reclaim_state = bo->reclaim_state;
>  	unsigned int refcount = kref_read(&bo->base.refcount);
> +	int reclaimed_count = atomic_read(&bo->reclaimed_count);
>  	char creator_info[32] = {};
>  	size_t resident_size;
>  	u32 gem_usage_flags = bo->debugfs.flags;
> @@ -1638,16 +1644,20 @@ static void panthor_gem_debugfs_bo_print(struct panthor_gem_object *bo,
>  
>  	snprintf(creator_info, sizeof(creator_info),
>  		 "%s/%d", bo->debugfs.creator.process_name, bo->debugfs.creator.tgid);
> -	seq_printf(m, "%-32s%-16d%-16d%-16zd%-16zd0x%-16lx",
> +	seq_printf(m, "%-32s%-16d%-16d%-11d%-16zd%-16zd0x%-16lx",
>  		   creator_info,
>  		   bo->base.name,
>  		   refcount,
> +		   reclaimed_count,
>  		   bo->base.size,
>  		   resident_size,
>  		   drm_vma_node_start(&bo->base.vma_node));
>  
>  	if (drm_gem_is_imported(&bo->base))
>  		gem_state_flags |= PANTHOR_DEBUGFS_GEM_STATE_FLAG_IMPORTED;
> +	else if (!resident_size && reclaimed_count)
> +		gem_state_flags |= PANTHOR_DEBUGFS_GEM_STATE_FLAG_EVICTED;
> +
>  	if (bo->base.dma_buf)
>  		gem_state_flags |= PANTHOR_DEBUGFS_GEM_STATE_FLAG_EXPORTED;
>  
> @@ -1671,8 +1681,8 @@ static void panthor_gem_debugfs_print_bos(struct panthor_device *ptdev,
>  
>  	panthor_gem_debugfs_print_flag_names(m);
>  
> -	seq_puts(m, "created-by                      global-name     refcount        size            resident-size   file-offset       state      usage       label\n");
> -	seq_puts(m, "----------------------------------------------------------------------------------------------------------------------------------------------\n");
> +	seq_puts(m, "created-by                      global-name     refcount        evictions  size            resident-size   file-offset       state      usage       label\n");
> +	seq_puts(m, "---------------------------------------------------------------------------------------------------------------------------------------------------------\n");
>  
>  	scoped_guard(mutex, &ptdev->gems.lock) {
>  		list_for_each_entry(bo, &ptdev->gems.node, debugfs.node) {
> @@ -1680,7 +1690,7 @@ static void panthor_gem_debugfs_print_bos(struct panthor_device *ptdev,
>  		}
>  	}
>  
> -	seq_puts(m, "==============================================================================================================================================\n");
> +	seq_puts(m, "=========================================================================================================================================================\n");
>  	seq_printf(m, "Total size: %zd, Total resident: %zd, Total reclaimable: %zd\n",
>  		   totals.size, totals.resident, totals.reclaimable);
>  }
> diff --git a/drivers/gpu/drm/panthor/panthor_gem.h b/drivers/gpu/drm/panthor/panthor_gem.h
> index ae0491d0b121..56d63137b4eb 100644
> --- a/drivers/gpu/drm/panthor/panthor_gem.h
> +++ b/drivers/gpu/drm/panthor/panthor_gem.h
> @@ -19,12 +19,16 @@ struct panthor_vm;
>  enum panthor_debugfs_gem_state_flags {
>  	PANTHOR_DEBUGFS_GEM_STATE_IMPORTED_BIT = 0,
>  	PANTHOR_DEBUGFS_GEM_STATE_EXPORTED_BIT = 1,
> +	PANTHOR_DEBUGFS_GEM_STATE_EVICTED_BIT = 2,
>  
>  	/** @PANTHOR_DEBUGFS_GEM_STATE_FLAG_IMPORTED: GEM BO is PRIME imported. */
>  	PANTHOR_DEBUGFS_GEM_STATE_FLAG_IMPORTED = BIT(PANTHOR_DEBUGFS_GEM_STATE_IMPORTED_BIT),
>  
>  	/** @PANTHOR_DEBUGFS_GEM_STATE_FLAG_EXPORTED: GEM BO is PRIME exported. */
>  	PANTHOR_DEBUGFS_GEM_STATE_FLAG_EXPORTED = BIT(PANTHOR_DEBUGFS_GEM_STATE_EXPORTED_BIT),
> +
> +	/** @PANTHOR_DEBUGFS_GEM_STATE_FLAG_EVICTED: GEM BO is evicted to swap. */
> +	PANTHOR_DEBUGFS_GEM_STATE_FLAG_EVICTED = BIT(PANTHOR_DEBUGFS_GEM_STATE_EVICTED_BIT),
>  };
>  
>  enum panthor_debugfs_gem_usage_flags {
> @@ -172,6 +176,12 @@ struct panthor_gem_object {
>  	/** @reclaim_state: Cached reclaim state */
>  	enum panthor_gem_reclaim_state reclaim_state;
>  
> +	/**
> +	 * @reclaimed_count: How many times object has been evicted to swap.
> +	 * The count saturates at %INT_MAX and will never wrap around to 0.
> +	 */
> +	atomic_t reclaimed_count;
> +
>  	/**
>  	 * @exclusive_vm_root_gem: Root GEM of the exclusive VM this GEM object
>  	 * is attached to.
> 


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v4 1/3] drm/fdinfo: Add "evicted" memory accounting
  2026-05-20 13:04 ` [PATCH v4 1/3] drm/fdinfo: Add "evicted" memory accounting Nicolas Frattaroli
@ 2026-05-20 14:19   ` Tvrtko Ursulin
  2026-05-20 19:38     ` Nicolas Frattaroli
  2026-05-25 11:52   ` Claude review: " Claude Code Review Bot
  1 sibling, 1 reply; 12+ messages in thread
From: Tvrtko Ursulin @ 2026-05-20 14:19 UTC (permalink / raw)
  To: Nicolas Frattaroli, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Boris Brezillon,
	Steven Price, Liviu Dudau, Jonathan Corbet, Shuah Khan
  Cc: dri-devel, linux-kernel, kernel, linux-doc


On 20/05/2026 14:04, Nicolas Frattaroli wrote:
> Currently, there's no way to know for certain how much GPU memory was
> swapped out. The difference between total and resident memory would
> include newly allocated pages, which are not resident, but also aren't
> swapped out.
> 
> Add a new drm_gem_object_status so drivers can signal when an object has
> been evicted to swap, and add a new "evicted" counter to
> drm_memory_stats.
> 
> Due to how the supported_flags bitmask is determined, the "evicted"
> count won't be printed to fdinfo if there's no swapped out pages.
> 
> Reviewed-by: Steven Price <steven.price@arm.com>
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
> ---
>   Documentation/gpu/drm-usage-stats.rst | 6 ++++++
>   drivers/gpu/drm/drm_file.c            | 8 ++++++++
>   include/drm/drm_file.h                | 2 ++
>   include/drm/drm_gem.h                 | 2 ++
>   4 files changed, 18 insertions(+)
> 
> diff --git a/Documentation/gpu/drm-usage-stats.rst b/Documentation/gpu/drm-usage-stats.rst
> index 70b7cfcc194f..ac1dbf52d96d 100644
> --- a/Documentation/gpu/drm-usage-stats.rst
> +++ b/Documentation/gpu/drm-usage-stats.rst
> @@ -202,6 +202,12 @@ One practical example of this could be the presence of unsignaled fences in a
>   GEM buffer reservation object. Therefore, the active category is a subset of the
>   resident category.
>   
> +- drm-evicted-<region>: <uint> [KiB|MiB]
> +
> +The total size of buffers that have been evicted and are no longer pinned by the
> +device. Only present if there are buffers that are currently evicted, and if the
> +driver implements reporting of this type of memory.

The semantics as tricky to make work in an obvious way.

On one hand the text above is almost exactly the semantics of 'total' - 
'resident'. Almost meaning it was resident at some point, but isn't any 
more. Whereas raw 'total' - 'resident' can also mean it never has been 
instantiated.

You could even have a "workaround" where you report a 'swap' memory 
region and then don't need to add anything new to the spec.

Next problem - on paper evicted could be useful to replace driver legacy 
keys such as 'amd-evicted-ram'. But that "evicted" is defined as "not in 
a the preferred placement". While your evicted is more like "no current 
placement" (as in, no GPU accessible backing storage).

Is it possible to find a definition of this new category which makes 
sense for different GPUs/drivers, be it integrated or discrete.

Or would simply going for 'drm-total-swap:' (or resident?) work for 
panthor? Advantage being it would also work unambiguously for discrete 
drivers.

Like the ones which support multiple TTM placements, for example VRAM + 
SYSTEM and then next step is swapping out so an extreme example on a 
16GiB GPU + 16GiB RAM machine with a 32GiB gfx workload could be like:

drm-total-vram:		32GiB
drm-resident-vram:	16GiB
drm-resident-system:	15GiB
drm-total-swap:		1GiB

Does this look clear enough? Whereas with the "evicted" category it 
would be:

drm-total-vram:		32GiB
drm-resident-vram:	16GiB
drm-evicted-vram:	16GiB # portion which got demoted to system RAM
drm-resident-system:	15GiB
drm-evicted-system:	1GiB  # portion which got demoted to swap

Where drm-evicted-vram is redundant to "total - resident". And it is 
overloaded semantics as it where does evicted go depending on the 
GPU/driver/region.

Thoughts, opinions?

Regards,

Tvrtko

> +
>   Implementation Details
>   ======================
>   
> diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c
> index ec820686b302..5078172976c0 100644
> --- a/drivers/gpu/drm/drm_file.c
> +++ b/drivers/gpu/drm/drm_file.c
> @@ -868,6 +868,7 @@ int drm_memory_stats_is_zero(const struct drm_memory_stats *stats)
>   		stats->private == 0 &&
>   		stats->resident == 0 &&
>   		stats->purgeable == 0 &&
> +		stats->evicted == 0 &&
>   		stats->active == 0);
>   }
>   EXPORT_SYMBOL(drm_memory_stats_is_zero);
> @@ -901,6 +902,10 @@ void drm_print_memory_stats(struct drm_printer *p,
>   	if (supported_status & DRM_GEM_OBJECT_PURGEABLE)
>   		drm_fdinfo_print_size(p, prefix, "purgeable", region,
>   				      stats->purgeable);
> +
> +	if (supported_status & DRM_GEM_OBJECT_EVICTED)
> +		drm_fdinfo_print_size(p, prefix, "evicted", region,
> +				      stats->evicted);
>   }
>   EXPORT_SYMBOL(drm_print_memory_stats);
>   
> @@ -954,6 +959,9 @@ void drm_show_memory_stats(struct drm_printer *p, struct drm_file *file)
>   
>   		if (s & DRM_GEM_OBJECT_PURGEABLE)
>   			status.purgeable += add_size;
> +
> +		if (s & DRM_GEM_OBJECT_EVICTED)
> +			status.evicted += add_size;
>   	}
>   	spin_unlock(&file->table_lock);
>   
> diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h
> index 6ee70ad65e1f..7e4cb45a52c3 100644
> --- a/include/drm/drm_file.h
> +++ b/include/drm/drm_file.h
> @@ -500,6 +500,7 @@ void drm_send_event_timestamp_locked(struct drm_device *dev,
>    * @resident: Total size of GEM objects backing pages
>    * @purgeable: Total size of GEM objects that can be purged (resident and not active)
>    * @active: Total size of GEM objects active on one or more engines
> + * @evicted: Total size of GEM objects that have been evicted
>    *
>    * Used by drm_print_memory_stats()
>    */
> @@ -509,6 +510,7 @@ struct drm_memory_stats {
>   	u64 resident;
>   	u64 purgeable;
>   	u64 active;
> +	u64 evicted;
>   };
>   
>   enum drm_gem_object_status;
> diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
> index 86f5846154f7..799588a2762a 100644
> --- a/include/drm/drm_gem.h
> +++ b/include/drm/drm_gem.h
> @@ -53,6 +53,7 @@ struct drm_gem_object;
>    * @DRM_GEM_OBJECT_RESIDENT: object is resident in memory (ie. not unpinned)
>    * @DRM_GEM_OBJECT_PURGEABLE: object marked as purgeable by userspace
>    * @DRM_GEM_OBJECT_ACTIVE: object is currently used by an active submission
> + * @DRM_GEM_OBJECT_EVICTED: object is evicted and no longer pinned by driver
>    *
>    * Bitmask of status used for fdinfo memory stats, see &drm_gem_object_funcs.status
>    * and drm_show_fdinfo().  Note that an object can report DRM_GEM_OBJECT_PURGEABLE
> @@ -67,6 +68,7 @@ enum drm_gem_object_status {
>   	DRM_GEM_OBJECT_RESIDENT  = BIT(0),
>   	DRM_GEM_OBJECT_PURGEABLE = BIT(1),
>   	DRM_GEM_OBJECT_ACTIVE    = BIT(2),
> +	DRM_GEM_OBJECT_EVICTED   = BIT(3),
>   };
>   
>   /**
> 


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v4 2/3] drm/panthor: Implement evicted status for GEM objects
  2026-05-20 13:04 ` [PATCH v4 2/3] drm/panthor: Implement evicted status for GEM objects Nicolas Frattaroli
  2026-05-20 13:24   ` Boris Brezillon
@ 2026-05-20 14:33   ` Boris Brezillon
  2026-05-25 11:52   ` Claude review: " Claude Code Review Bot
  2 siblings, 0 replies; 12+ messages in thread
From: Boris Brezillon @ 2026-05-20 14:33 UTC (permalink / raw)
  To: Nicolas Frattaroli
  Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Steven Price, Liviu Dudau, Jonathan Corbet,
	Shuah Khan, Tvrtko Ursulin, dri-devel, linux-kernel, kernel,
	linux-doc

On Wed, 20 May 2026 15:04:49 +0200
Nicolas Frattaroli <nicolas.frattaroli@collabora.com> wrote:

> For fdinfo to be able to fill its evicted counter with data, panthor
> needs to keep track of whether a GEM object has ever been reclaimed.
> Just checking whether the pages are resident isn't enough, as newly
> allocated objects also won't be resident.
> 
> Do this with a new atomic_t member on panthor_gem_object. It's increased
> when an object gets evicted by the shrinker, and saturates at INT_MAX.
> This means that once an object has been evicted at least once, its
> reclaim counter will never return to 0.
> 
> Due to this, it's possible to distinguish evicted non-resident pages
> from newly allocated non-resident pages by checking whether
> reclaimed_count is != 0
> 
> Use this new member to then set the appropriate DRM_GEM_OBJECT_EVICTED
> status flag for fdinfo.
> 
> Also add a new column and status flag to the panthor gems debugfs: the
> column is the number of times an object has been evicted, whereas the
> flag indicates whether it currently is evicted.
> 
> Reviewed-by: Steven Price <steven.price@arm.com>
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
> ---
>  drivers/gpu/drm/panthor/panthor_gem.c | 18 ++++++++++++++----
>  drivers/gpu/drm/panthor/panthor_gem.h | 10 ++++++++++
>  2 files changed, 24 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c
> index 13295d7a593d..068aa935c8fc 100644
> --- a/drivers/gpu/drm/panthor/panthor_gem.c
> +++ b/drivers/gpu/drm/panthor/panthor_gem.c
> @@ -687,6 +687,8 @@ static void panthor_gem_evict_locked(struct panthor_gem_object *bo)
>  	if (drm_WARN_ON_ONCE(bo->base.dev, !bo->backing.pages))
>  		return;
>  
> +	atomic_add_unless(&bo->reclaimed_count, 1, INT_MAX);
> +
>  	panthor_gem_dev_map_cleanup_locked(bo);
>  	panthor_gem_backing_cleanup_locked(bo);
>  	panthor_gem_update_reclaim_state_locked(bo, NULL);
> @@ -788,6 +790,8 @@ static enum drm_gem_object_status panthor_gem_status(struct drm_gem_object *obj)
>  
>  	if (drm_gem_is_imported(&bo->base) || bo->backing.pages)
>  		res |= DRM_GEM_OBJECT_RESIDENT;
> +	else if (atomic_read(&bo->reclaimed_count))
> +		res |= DRM_GEM_OBJECT_EVICTED;

Could we drop that change so we can at least have patch 2 and 3 merged
while the discussion on the fdinfo semantics is going on?

>  
>  	return res;
>  }
> @@ -1595,6 +1599,7 @@ static void panthor_gem_debugfs_print_flag_names(struct seq_file *m)
>  	static const char * const gem_state_flags_names[] = {
>  		[PANTHOR_DEBUGFS_GEM_STATE_IMPORTED_BIT] = "imported",
>  		[PANTHOR_DEBUGFS_GEM_STATE_EXPORTED_BIT] = "exported",
> +		[PANTHOR_DEBUGFS_GEM_STATE_EVICTED_BIT] = "evicted",
>  	};
>  
>  	static const char * const gem_usage_flags_names[] = {
> @@ -1625,6 +1630,7 @@ static void panthor_gem_debugfs_bo_print(struct panthor_gem_object *bo,
>  {
>  	enum panthor_gem_reclaim_state reclaim_state = bo->reclaim_state;
>  	unsigned int refcount = kref_read(&bo->base.refcount);
> +	int reclaimed_count = atomic_read(&bo->reclaimed_count);
>  	char creator_info[32] = {};
>  	size_t resident_size;
>  	u32 gem_usage_flags = bo->debugfs.flags;
> @@ -1638,16 +1644,20 @@ static void panthor_gem_debugfs_bo_print(struct panthor_gem_object *bo,
>  
>  	snprintf(creator_info, sizeof(creator_info),
>  		 "%s/%d", bo->debugfs.creator.process_name, bo->debugfs.creator.tgid);
> -	seq_printf(m, "%-32s%-16d%-16d%-16zd%-16zd0x%-16lx",
> +	seq_printf(m, "%-32s%-16d%-16d%-11d%-16zd%-16zd0x%-16lx",
>  		   creator_info,
>  		   bo->base.name,
>  		   refcount,
> +		   reclaimed_count,
>  		   bo->base.size,
>  		   resident_size,
>  		   drm_vma_node_start(&bo->base.vma_node));
>  
>  	if (drm_gem_is_imported(&bo->base))
>  		gem_state_flags |= PANTHOR_DEBUGFS_GEM_STATE_FLAG_IMPORTED;
> +	else if (!resident_size && reclaimed_count)
> +		gem_state_flags |= PANTHOR_DEBUGFS_GEM_STATE_FLAG_EVICTED;
> +
>  	if (bo->base.dma_buf)
>  		gem_state_flags |= PANTHOR_DEBUGFS_GEM_STATE_FLAG_EXPORTED;
>  
> @@ -1671,8 +1681,8 @@ static void panthor_gem_debugfs_print_bos(struct panthor_device *ptdev,
>  
>  	panthor_gem_debugfs_print_flag_names(m);
>  
> -	seq_puts(m, "created-by                      global-name     refcount        size            resident-size   file-offset       state      usage       label\n");
> -	seq_puts(m, "----------------------------------------------------------------------------------------------------------------------------------------------\n");
> +	seq_puts(m, "created-by                      global-name     refcount        evictions  size            resident-size   file-offset       state      usage       label\n");
> +	seq_puts(m, "---------------------------------------------------------------------------------------------------------------------------------------------------------\n");
>  
>  	scoped_guard(mutex, &ptdev->gems.lock) {
>  		list_for_each_entry(bo, &ptdev->gems.node, debugfs.node) {
> @@ -1680,7 +1690,7 @@ static void panthor_gem_debugfs_print_bos(struct panthor_device *ptdev,
>  		}
>  	}
>  
> -	seq_puts(m, "==============================================================================================================================================\n");
> +	seq_puts(m, "=========================================================================================================================================================\n");
>  	seq_printf(m, "Total size: %zd, Total resident: %zd, Total reclaimable: %zd\n",
>  		   totals.size, totals.resident, totals.reclaimable);
>  }
> diff --git a/drivers/gpu/drm/panthor/panthor_gem.h b/drivers/gpu/drm/panthor/panthor_gem.h
> index ae0491d0b121..56d63137b4eb 100644
> --- a/drivers/gpu/drm/panthor/panthor_gem.h
> +++ b/drivers/gpu/drm/panthor/panthor_gem.h
> @@ -19,12 +19,16 @@ struct panthor_vm;
>  enum panthor_debugfs_gem_state_flags {
>  	PANTHOR_DEBUGFS_GEM_STATE_IMPORTED_BIT = 0,
>  	PANTHOR_DEBUGFS_GEM_STATE_EXPORTED_BIT = 1,
> +	PANTHOR_DEBUGFS_GEM_STATE_EVICTED_BIT = 2,
>  
>  	/** @PANTHOR_DEBUGFS_GEM_STATE_FLAG_IMPORTED: GEM BO is PRIME imported. */
>  	PANTHOR_DEBUGFS_GEM_STATE_FLAG_IMPORTED = BIT(PANTHOR_DEBUGFS_GEM_STATE_IMPORTED_BIT),
>  
>  	/** @PANTHOR_DEBUGFS_GEM_STATE_FLAG_EXPORTED: GEM BO is PRIME exported. */
>  	PANTHOR_DEBUGFS_GEM_STATE_FLAG_EXPORTED = BIT(PANTHOR_DEBUGFS_GEM_STATE_EXPORTED_BIT),
> +
> +	/** @PANTHOR_DEBUGFS_GEM_STATE_FLAG_EVICTED: GEM BO is evicted to swap. */
> +	PANTHOR_DEBUGFS_GEM_STATE_FLAG_EVICTED = BIT(PANTHOR_DEBUGFS_GEM_STATE_EVICTED_BIT),
>  };
>  
>  enum panthor_debugfs_gem_usage_flags {
> @@ -172,6 +176,12 @@ struct panthor_gem_object {
>  	/** @reclaim_state: Cached reclaim state */
>  	enum panthor_gem_reclaim_state reclaim_state;
>  
> +	/**
> +	 * @reclaimed_count: How many times object has been evicted to swap.
> +	 * The count saturates at %INT_MAX and will never wrap around to 0.
> +	 */
> +	atomic_t reclaimed_count;
> +
>  	/**
>  	 * @exclusive_vm_root_gem: Root GEM of the exclusive VM this GEM object
>  	 * is attached to.
> 


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v4 1/3] drm/fdinfo: Add "evicted" memory accounting
  2026-05-20 14:19   ` Tvrtko Ursulin
@ 2026-05-20 19:38     ` Nicolas Frattaroli
  0 siblings, 0 replies; 12+ messages in thread
From: Nicolas Frattaroli @ 2026-05-20 19:38 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Boris Brezillon, Steven Price, Liviu Dudau,
	Jonathan Corbet, Shuah Khan, Tvrtko Ursulin
  Cc: dri-devel, linux-kernel, kernel, linux-doc

Hello Tvrtko,

On Wednesday, 20 May 2026 16:19:12 Central European Summer Time Tvrtko Ursulin wrote:
> 
> On 20/05/2026 14:04, Nicolas Frattaroli wrote:
> > Currently, there's no way to know for certain how much GPU memory was
> > swapped out. The difference between total and resident memory would
> > include newly allocated pages, which are not resident, but also aren't
> > swapped out.
> > 
> > Add a new drm_gem_object_status so drivers can signal when an object has
> > been evicted to swap, and add a new "evicted" counter to
> > drm_memory_stats.
> > 
> > Due to how the supported_flags bitmask is determined, the "evicted"
> > count won't be printed to fdinfo if there's no swapped out pages.
> > 
> > Reviewed-by: Steven Price <steven.price@arm.com>
> > Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
> > ---
> >   Documentation/gpu/drm-usage-stats.rst | 6 ++++++
> >   drivers/gpu/drm/drm_file.c            | 8 ++++++++
> >   include/drm/drm_file.h                | 2 ++
> >   include/drm/drm_gem.h                 | 2 ++
> >   4 files changed, 18 insertions(+)
> > 
> > diff --git a/Documentation/gpu/drm-usage-stats.rst b/Documentation/gpu/drm-usage-stats.rst
> > index 70b7cfcc194f..ac1dbf52d96d 100644
> > --- a/Documentation/gpu/drm-usage-stats.rst
> > +++ b/Documentation/gpu/drm-usage-stats.rst
> > @@ -202,6 +202,12 @@ One practical example of this could be the presence of unsignaled fences in a
> >   GEM buffer reservation object. Therefore, the active category is a subset of the
> >   resident category.
> >   
> > +- drm-evicted-<region>: <uint> [KiB|MiB]
> > +
> > +The total size of buffers that have been evicted and are no longer pinned by the
> > +device. Only present if there are buffers that are currently evicted, and if the
> > +driver implements reporting of this type of memory.
> 
> The semantics as tricky to make work in an obvious way.
> 
> On one hand the text above is almost exactly the semantics of 'total' - 
> 'resident'. Almost meaning it was resident at some point, but isn't any 
> more. Whereas raw 'total' - 'resident' can also mean it never has been 
> instantiated.

Yes, that is the difference. You cannot tell them apart otherwise.

> You could even have a "workaround" where you report a 'swap' memory 
> region and then don't need to add anything new to the spec.

I get the idea that technically, swap is its own memory region, but
evicted is counting memory that panthor knows is currently evicted,
not necessarily memory that is in swap. Counting pages that would
*actually* be in swap would probably involve breaking several
abstractions that shouldn't be broken.

> 
> Next problem - on paper evicted could be useful to replace driver legacy 
> keys such as 'amd-evicted-ram'. But that "evicted" is defined as "not in 
> a the preferred placement". While your evicted is more like "no current 
> placement" (as in, no GPU accessible backing storage).
> 
> Is it possible to find a definition of this new category which makes 
> sense for different GPUs/drivers, be it integrated or discrete.

Sure, we can make this definition as loose as you need it to be to use
it in a different driver. I think the difference between "not in a
preferred placement" and "no current placement (but had a placement in
the past)" is not a big one for the users of this information; the goal
is to see how much of the GPU memory of a process has been made non-
resident by a shrinker.

> Or would simply going for 'drm-total-swap:' (or resident?) work for 
> panthor? Advantage being it would also work unambiguously for discrete 
> drivers.

Panthor itself doesn't really know whether something is in swap or
has just been made non-resident by the drm shrinker. It could be
somewhere between swap and resident, as Steven Price pointed out.

> 
> Like the ones which support multiple TTM placements, for example VRAM + 
> SYSTEM and then next step is swapping out so an extreme example on a 
> 16GiB GPU + 16GiB RAM machine with a 32GiB gfx workload could be like:
> 
> drm-total-vram:		32GiB
> drm-resident-vram:	16GiB
> drm-resident-system:	15GiB
> drm-total-swap:		1GiB
> 
> Does this look clear enough? Whereas with the "evicted" category it 
> would be:
> 
> drm-total-vram:		32GiB
> drm-resident-vram:	16GiB
> drm-evicted-vram:	16GiB # portion which got demoted to system RAM
> drm-resident-system:	15GiB
> drm-evicted-system:	1GiB  # portion which got demoted to swap
> 
> Where drm-evicted-vram is redundant to "total - resident". And it is 
> overloaded semantics as it where does evicted go depending on the 
> GPU/driver/region.

"drm-evicted-vram" is only redundant to "total - resident" if objects
that have never been packed by any pages aren't counted in total. This
is not the case, so I'm trying to fix it by adding evicted to it for
pages that were backed at some stage, but now aren't backed anymore.

I think "evicted" solves this problem generally in your second example,
without me having to worry about whether a page is in swap or AMD's
memory model.

So, to summarise:
- Panthor does not know how much of the memory that was reclaimed by the
  shrinker is actually in swap space, so "drm-total-swap" wouldn't work
  here.
- "total - resident" measures the wrong thing. Objects that have never
  been backed are not evicted.
- I am completely fine with AMD not using this fdinfo memory type due
  to having more complex eviction handling, but I don't see why it
  could not be used in this form.

> 
> Thoughts, opinions?
> 
> Regards,
> 
> Tvrtko
> 
> > +
> >   Implementation Details
> >   ======================
> >   
> > diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c
> > index ec820686b302..5078172976c0 100644
> > --- a/drivers/gpu/drm/drm_file.c
> > +++ b/drivers/gpu/drm/drm_file.c
> > @@ -868,6 +868,7 @@ int drm_memory_stats_is_zero(const struct drm_memory_stats *stats)
> >   		stats->private == 0 &&
> >   		stats->resident == 0 &&
> >   		stats->purgeable == 0 &&
> > +		stats->evicted == 0 &&
> >   		stats->active == 0);
> >   }
> >   EXPORT_SYMBOL(drm_memory_stats_is_zero);
> > @@ -901,6 +902,10 @@ void drm_print_memory_stats(struct drm_printer *p,
> >   	if (supported_status & DRM_GEM_OBJECT_PURGEABLE)
> >   		drm_fdinfo_print_size(p, prefix, "purgeable", region,
> >   				      stats->purgeable);
> > +
> > +	if (supported_status & DRM_GEM_OBJECT_EVICTED)
> > +		drm_fdinfo_print_size(p, prefix, "evicted", region,
> > +				      stats->evicted);
> >   }
> >   EXPORT_SYMBOL(drm_print_memory_stats);
> >   
> > @@ -954,6 +959,9 @@ void drm_show_memory_stats(struct drm_printer *p, struct drm_file *file)
> >   
> >   		if (s & DRM_GEM_OBJECT_PURGEABLE)
> >   			status.purgeable += add_size;
> > +
> > +		if (s & DRM_GEM_OBJECT_EVICTED)
> > +			status.evicted += add_size;
> >   	}
> >   	spin_unlock(&file->table_lock);
> >   
> > diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h
> > index 6ee70ad65e1f..7e4cb45a52c3 100644
> > --- a/include/drm/drm_file.h
> > +++ b/include/drm/drm_file.h
> > @@ -500,6 +500,7 @@ void drm_send_event_timestamp_locked(struct drm_device *dev,
> >    * @resident: Total size of GEM objects backing pages
> >    * @purgeable: Total size of GEM objects that can be purged (resident and not active)
> >    * @active: Total size of GEM objects active on one or more engines
> > + * @evicted: Total size of GEM objects that have been evicted
> >    *
> >    * Used by drm_print_memory_stats()
> >    */
> > @@ -509,6 +510,7 @@ struct drm_memory_stats {
> >   	u64 resident;
> >   	u64 purgeable;
> >   	u64 active;
> > +	u64 evicted;
> >   };
> >   
> >   enum drm_gem_object_status;
> > diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
> > index 86f5846154f7..799588a2762a 100644
> > --- a/include/drm/drm_gem.h
> > +++ b/include/drm/drm_gem.h
> > @@ -53,6 +53,7 @@ struct drm_gem_object;
> >    * @DRM_GEM_OBJECT_RESIDENT: object is resident in memory (ie. not unpinned)
> >    * @DRM_GEM_OBJECT_PURGEABLE: object marked as purgeable by userspace
> >    * @DRM_GEM_OBJECT_ACTIVE: object is currently used by an active submission
> > + * @DRM_GEM_OBJECT_EVICTED: object is evicted and no longer pinned by driver
> >    *
> >    * Bitmask of status used for fdinfo memory stats, see &drm_gem_object_funcs.status
> >    * and drm_show_fdinfo().  Note that an object can report DRM_GEM_OBJECT_PURGEABLE
> > @@ -67,6 +68,7 @@ enum drm_gem_object_status {
> >   	DRM_GEM_OBJECT_RESIDENT  = BIT(0),
> >   	DRM_GEM_OBJECT_PURGEABLE = BIT(1),
> >   	DRM_GEM_OBJECT_ACTIVE    = BIT(2),
> > +	DRM_GEM_OBJECT_EVICTED   = BIT(3),
> >   };
> >   
> >   /**
> > 
> 
> 





^ permalink raw reply	[flat|nested] 12+ messages in thread

* Claude review: Let userspace know about swapped out panthor GEM objects
  2026-05-20 13:04 [PATCH v4 0/3] Let userspace know about swapped out panthor GEM objects Nicolas Frattaroli
                   ` (2 preceding siblings ...)
  2026-05-20 13:04 ` [PATCH v4 3/3] drm/panthor: Reduce padding in gems debugfs for refcount Nicolas Frattaroli
@ 2026-05-25 11:52 ` Claude Code Review Bot
  3 siblings, 0 replies; 12+ messages in thread
From: Claude Code Review Bot @ 2026-05-25 11:52 UTC (permalink / raw)
  To: dri-devel-reviews

Overall Series Review

Subject: Let userspace know about swapped out panthor GEM objects
Author: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
Patches: 8
Reviewed: 2026-05-25T21:52:45.981861

---

This is a clean, well-structured 3-patch series that adds eviction observability to the DRM fdinfo framework and implements it in the panthor driver. The motivation is sound — distinguishing evicted-to-swap objects from newly-allocated-but-not-yet-backed objects is genuinely useful for memory debugging. The series is at v4 and already carries Reviewed-by from Steven Price.

The patches are logically ordered: framework first (patch 1), driver implementation (patch 2), cosmetic cleanup (patch 3). The code is straightforward and well-documented.

One design concern exists in the framework code (patch 1) regarding how `add_size` is computed for evicted objects — it's correct for panthor but could be incorrect for future drivers that implement `rss()`. This is a minor concern since panthor is the only user today.

**Verdict:** Series looks good. One minor design concern worth discussing with maintainers, but not a blocker for merging.

---

---
Generated by Claude Code Patch Reviewer

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Claude review: drm/fdinfo: Add "evicted" memory accounting
  2026-05-20 13:04 ` [PATCH v4 1/3] drm/fdinfo: Add "evicted" memory accounting Nicolas Frattaroli
  2026-05-20 14:19   ` Tvrtko Ursulin
@ 2026-05-25 11:52   ` Claude Code Review Bot
  1 sibling, 0 replies; 12+ messages in thread
From: Claude Code Review Bot @ 2026-05-25 11:52 UTC (permalink / raw)
  To: dri-devel-reviews

Patch Review

**Overall:** Clean framework extension that follows the existing patterns for RESIDENT, PURGEABLE, and ACTIVE perfectly.

**Design concern — `add_size` vs `obj->size` for evicted objects:**

In `drm_show_memory_stats()`, the new evicted accounting uses `add_size`:

```c
if (s & DRM_GEM_OBJECT_EVICTED)
    status.evicted += add_size;
```

where `add_size` is computed as:

```c
size_t add_size = (obj->funcs && obj->funcs->rss) ?
    obj->funcs->rss(obj) : obj->size;
```

For panthor (no `rss` callback), `add_size = obj->size`, which is correct. However, for any future driver that implements `rss()`, an evicted object would have `rss() == 0` (since the pages have been freed), making the evicted counter always zero — defeating its purpose. Consider using `obj->size` instead of `add_size` for the evicted counter, since the intent is to report how much data has been evicted, not how much of it is still physically present (which is by definition none).

This isn't a blocker since panthor is the only user, but it would be a trap for the next driver that adds eviction support.

**Documentation:** The new `drm-evicted-<region>` documentation is clear and correctly states the semantics ("Only present if there are buffers that are currently evicted, and if the driver implements reporting of this type of memory."). The v4 change to avoid explicitly mentioning swap is appropriate since eviction is a broader concept.

**Correctness of interaction with existing flags:** The existing framework code already clears `DRM_GEM_OBJECT_PURGEABLE` for non-resident objects (line 944 in the `else` branch), so an evicted object won't double-count as purgeable. Good.

**No issues with:**
- `drm_memory_stats_is_zero()` update — correct addition of `evicted == 0` check.
- `drm_print_memory_stats()` — follows the same conditional pattern as purgeable/active.
- Enum value `BIT(3)` — correct, no collision with existing BIT(0..2).

---

---
Generated by Claude Code Patch Reviewer

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Claude review: drm/panthor: Implement evicted status for GEM objects
  2026-05-20 13:04 ` [PATCH v4 2/3] drm/panthor: Implement evicted status for GEM objects Nicolas Frattaroli
  2026-05-20 13:24   ` Boris Brezillon
  2026-05-20 14:33   ` Boris Brezillon
@ 2026-05-25 11:52   ` Claude Code Review Bot
  2 siblings, 0 replies; 12+ messages in thread
From: Claude Code Review Bot @ 2026-05-25 11:52 UTC (permalink / raw)
  To: dri-devel-reviews

Patch Review

**Overall:** Well-designed implementation using `atomic_t` for the reclaimed counter with INT_MAX saturation.

**`atomic_add_unless` for saturation:** Correct approach.

```c
atomic_add_unless(&bo->reclaimed_count, 1, INT_MAX);
```

This atomically increments unless the value is already INT_MAX, providing clean saturation semantics. Placed correctly before the actual eviction cleanup.

**Status callback logic:**

```c
if (drm_gem_is_imported(&bo->base) || bo->backing.pages)
    res |= DRM_GEM_OBJECT_RESIDENT;
else if (atomic_read(&bo->reclaimed_count))
    res |= DRM_GEM_OBJECT_EVICTED;
```

The `else if` correctly makes RESIDENT and EVICTED mutually exclusive. An object that is swapped back in (`backing.pages` non-NULL again) will show as RESIDENT, not EVICTED — which is the correct current-state semantics. The `reclaimed_count` provides the historical record. The distinction between "never had pages" (reclaimed_count == 0, neither RESIDENT nor EVICTED) and "had pages but were evicted" (reclaimed_count > 0, EVICTED) is exactly the gap this series fills.

**Race between `backing.pages` and `reclaimed_count`:** These are read without holding locks in the status callback (called under `file->table_lock` spinlock, not dma_resv). A concurrent shrinker could evict the object between reading `backing.pages` and `reclaimed_count`. This is acceptable — fdinfo is inherently racy and will be correct on the next poll.

**Zero-initialization:** `reclaimed_count` is implicitly zero-initialized via `kzalloc_obj(*bo)` in `panthor_gem_alloc_object()`, so newly allocated objects correctly start with count 0.

**debugfs state flag:**

```c
if (drm_gem_is_imported(&bo->base))
    gem_state_flags |= PANTHOR_DEBUGFS_GEM_STATE_FLAG_IMPORTED;
else if (!resident_size && reclaimed_count)
    gem_state_flags |= PANTHOR_DEBUGFS_GEM_STATE_FLAG_EVICTED;
```

The `else if` is correct — imported BOs are always considered resident by panthor and are not managed by the shrinker, so they can never be in the evicted state.

**Format string update:** The new `%-11d` for `reclaimed_count` is correct (INT_MAX = 2147483647, 10 digits + 1 space = 11 chars). The column header "evictions" (9 chars) fits within the 11-char field.

**No issues with:** enum definitions, kerneldoc for `reclaimed_count`, debugfs flag name table update.

---

---
Generated by Claude Code Patch Reviewer

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Claude review: drm/panthor: Reduce padding in gems debugfs for refcount
  2026-05-20 13:04 ` [PATCH v4 3/3] drm/panthor: Reduce padding in gems debugfs for refcount Nicolas Frattaroli
@ 2026-05-25 11:52   ` Claude Code Review Bot
  0 siblings, 0 replies; 12+ messages in thread
From: Claude Code Review Bot @ 2026-05-25 11:52 UTC (permalink / raw)
  To: dri-devel-reviews

Patch Review

**Overall:** Trivial formatting improvement, correctly separated from patch 2 for review clarity.

The refcount column width is reduced from 16 to 11 characters. The justification is sound: `kref_read()` returns a 32-bit `unsigned int`, maximum value 4294967295 (10 digits), so 11 characters (10 digits + 1 separator) is sufficient.

Format string change:

```c
// Before (patch 2):
seq_printf(m, "%-32s%-16d%-16d%-11d%-16zd%-16zd0x%-16lx",
// After (patch 3):
seq_printf(m, "%-32s%-16d%-11d%-11d%-16zd%-16zd0x%-16lx",
```

Header, separator, and footer lines are all updated consistently. Total line width reduction is 5 characters.

No issues with this patch.

---
Generated by Claude Code Patch Reviewer

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2026-05-25 11:52 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-20 13:04 [PATCH v4 0/3] Let userspace know about swapped out panthor GEM objects Nicolas Frattaroli
2026-05-20 13:04 ` [PATCH v4 1/3] drm/fdinfo: Add "evicted" memory accounting Nicolas Frattaroli
2026-05-20 14:19   ` Tvrtko Ursulin
2026-05-20 19:38     ` Nicolas Frattaroli
2026-05-25 11:52   ` Claude review: " Claude Code Review Bot
2026-05-20 13:04 ` [PATCH v4 2/3] drm/panthor: Implement evicted status for GEM objects Nicolas Frattaroli
2026-05-20 13:24   ` Boris Brezillon
2026-05-20 14:33   ` Boris Brezillon
2026-05-25 11:52   ` Claude review: " Claude Code Review Bot
2026-05-20 13:04 ` [PATCH v4 3/3] drm/panthor: Reduce padding in gems debugfs for refcount Nicolas Frattaroli
2026-05-25 11:52   ` Claude review: " Claude Code Review Bot
2026-05-25 11:52 ` Claude review: Let userspace know about swapped out panthor GEM objects Claude Code Review Bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox