* [PATCH] drm/panthor: add gpu_load debugfs node
@ 2026-07-08 3:24 Guangliu Ding
2026-07-10 14:52 ` Steven Price
0 siblings, 1 reply; 7+ messages in thread
From: Guangliu Ding @ 2026-07-08 3:24 UTC (permalink / raw)
To: Boris Brezillon, Steven Price, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
Cc: dri-devel, linux-kernel, Guangliu Ding
Expose GPU utilization via /sys/kernel/debug/dri/<N>/gpu_load. The
file reports busy_time_ns, idle_time_ns and gpu_load %.
Values are snapshotted at the end of each devfreq sampling window
(~50 ms) rather than read from live accumulators, avoiding load swings
over short observation intervals.
The snapshot is cleared on suspend to avoid stale data when the GPU
is powered off.
Signed-off-by: Guangliu Ding <guangliu.ding@nxp.com>
---
Add /sys/kernel/debug/dri/<N>/gpu_load to expose GPU utilisation
from the last devfreq sampling window (~50 ms).
The file reports busy_time_ns, idle_time_ns and load percentage.
Tested on NXP i.MX95 EVK (Mali-G310 V2).
---
drivers/gpu/drm/panthor/panthor_devfreq.c | 80 +++++++++++++++++++++++++++++++
drivers/gpu/drm/panthor/panthor_devfreq.h | 6 +++
drivers/gpu/drm/panthor/panthor_drv.c | 2 +
3 files changed, 88 insertions(+)
diff --git a/drivers/gpu/drm/panthor/panthor_devfreq.c b/drivers/gpu/drm/panthor/panthor_devfreq.c
index 2249b41ca4af..1b3f58ddfbd3 100644
--- a/drivers/gpu/drm/panthor/panthor_devfreq.c
+++ b/drivers/gpu/drm/panthor/panthor_devfreq.c
@@ -1,12 +1,16 @@
// SPDX-License-Identifier: GPL-2.0 or MIT
/* Copyright 2019 Collabora ltd. */
+/* Copyright 2026 NXP */
#include <linux/clk.h>
+#include <linux/debugfs.h>
#include <linux/devfreq.h>
#include <linux/devfreq_cooling.h>
+#include <linux/math64.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
+#include <drm/drm_file.h>
#include <drm/drm_managed.h>
#include <drm/drm_print.h>
@@ -43,6 +47,22 @@ struct panthor_devfreq {
* and panthor_devfreq_record_{busy,idle}().
*/
spinlock_t lock;
+
+#ifdef CONFIG_DEBUG_FS
+ /**
+ * @last_busy_ns: Busy time in nanoseconds of the last completed devfreq window.
+ * Updated by panthor_devfreq_get_dev_status() before resetting the counters.
+ * Protected by @lock.
+ */
+ u64 last_busy_ns;
+
+ /**
+ * @last_total_ns: Total time in nanoseconds of the last completed devfreq window.
+ * Updated by panthor_devfreq_get_dev_status() before resetting the counters.
+ * Protected by @lock.
+ */
+ u64 last_total_ns;
+#endif
};
static void panthor_devfreq_update_utilization(struct panthor_devfreq *pdevfreq)
@@ -101,6 +121,11 @@ static int panthor_devfreq_get_dev_status(struct device *dev,
status->busy_time = ktime_to_ns(pdevfreq->busy_time);
+#ifdef CONFIG_DEBUG_FS
+ pdevfreq->last_busy_ns = status->busy_time;
+ pdevfreq->last_total_ns = status->total_time;
+#endif
+
panthor_devfreq_reset(pdevfreq);
spin_unlock_irqrestore(&pdevfreq->lock, irqflags);
@@ -283,6 +308,17 @@ void panthor_devfreq_suspend(struct panthor_device *ptdev)
return;
drm_WARN_ON(&ptdev->base, devfreq_suspend_device(pdevfreq->devfreq));
+
+#ifdef CONFIG_DEBUG_FS
+ {
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&pdevfreq->lock, irqflags);
+ pdevfreq->last_busy_ns = 0;
+ pdevfreq->last_total_ns = 0;
+ spin_unlock_irqrestore(&pdevfreq->lock, irqflags);
+ }
+#endif
}
void panthor_devfreq_record_busy(struct panthor_device *ptdev)
@@ -332,3 +368,47 @@ unsigned long panthor_devfreq_get_freq(struct panthor_device *ptdev)
return freq;
}
+
+#ifdef CONFIG_DEBUG_FS
+static int panthor_devfreq_gpu_load_show(struct seq_file *m, void *unused)
+{
+ struct panthor_device *ptdev = m->private;
+ struct panthor_devfreq *pdevfreq = ptdev->devfreq;
+ unsigned long irqflags;
+ unsigned int gpu_load;
+ u64 total_ns;
+ u64 busy_ns;
+
+ if (!pdevfreq->devfreq) {
+ seq_puts(m, "devfreq not initialized\n");
+ return 0;
+ }
+
+ spin_lock_irqsave(&pdevfreq->lock, irqflags);
+ busy_ns = pdevfreq->last_busy_ns;
+ total_ns = pdevfreq->last_total_ns;
+ spin_unlock_irqrestore(&pdevfreq->lock, irqflags);
+
+ busy_ns = min(busy_ns, total_ns);
+ gpu_load = total_ns ? (unsigned int)div64_u64(busy_ns * 100ULL, total_ns) : 0;
+
+ seq_printf(m, "busy_time_ns: %llu idle_time_ns: %llu gpu_load: %u%%\n",
+ busy_ns, total_ns - busy_ns, gpu_load);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(panthor_devfreq_gpu_load);
+
+/**
+ * panthor_devfreq_debugfs_init() - Initialize devfreq debugfs entries
+ * @minor: DRM minor.
+ */
+void panthor_devfreq_debugfs_init(struct drm_minor *minor)
+{
+ struct panthor_device *ptdev = container_of(minor->dev,
+ struct panthor_device, base);
+
+ debugfs_create_file("gpu_load", 0444, minor->debugfs_root, ptdev,
+ &panthor_devfreq_gpu_load_fops);
+}
+#endif /* CONFIG_DEBUG_FS */
diff --git a/drivers/gpu/drm/panthor/panthor_devfreq.h b/drivers/gpu/drm/panthor/panthor_devfreq.h
index f8e29e02f66c..4552569abfe4 100644
--- a/drivers/gpu/drm/panthor/panthor_devfreq.h
+++ b/drivers/gpu/drm/panthor/panthor_devfreq.h
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 or MIT */
/* Copyright 2019 Collabora ltd. */
+/* Copyright 2026 NXP */
#ifndef __PANTHOR_DEVFREQ_H__
#define __PANTHOR_DEVFREQ_H__
@@ -20,4 +21,9 @@ void panthor_devfreq_record_idle(struct panthor_device *ptdev);
unsigned long panthor_devfreq_get_freq(struct panthor_device *ptdev);
+#ifdef CONFIG_DEBUG_FS
+struct drm_minor;
+void panthor_devfreq_debugfs_init(struct drm_minor *minor);
+#endif
+
#endif /* __PANTHOR_DEVFREQ_H__ */
diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/panthor/panthor_drv.c
index e8dc4096c1d2..4093a6d21337 100644
--- a/drivers/gpu/drm/panthor/panthor_drv.c
+++ b/drivers/gpu/drm/panthor/panthor_drv.c
@@ -2,6 +2,7 @@
/* Copyright 2018 Marty E. Plummer <hanetzer@startmail.com> */
/* Copyright 2019 Linaro, Ltd., Rob Herring <robh@kernel.org> */
/* Copyright 2019 Collabora ltd. */
+/* Copyright 2026 NXP */
#ifdef CONFIG_ARM_ARCH_TIMER
#include <asm/arch_timer.h>
@@ -1761,6 +1762,7 @@ static void panthor_debugfs_init(struct drm_minor *minor)
{
panthor_mmu_debugfs_init(minor);
panthor_gem_debugfs_init(minor);
+ panthor_devfreq_debugfs_init(minor);
}
#endif
---
base-commit: 8cdeaa50eae8dad34885515f62559ee83e7e8dda
change-id: 20260706-master-bd0eef99ca8e
Best regards,
--
Guangliu Ding <guangliu.ding@nxp.com>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] drm/panthor: add gpu_load debugfs node
2026-07-08 3:24 [PATCH] drm/panthor: add gpu_load debugfs node Guangliu Ding
@ 2026-07-10 14:52 ` Steven Price
2026-07-13 3:19 ` Guangliu Ding
0 siblings, 1 reply; 7+ messages in thread
From: Steven Price @ 2026-07-10 14:52 UTC (permalink / raw)
To: Guangliu Ding, Boris Brezillon, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
Cc: dri-devel, linux-kernel
On 08/07/2026 04:24, Guangliu Ding wrote:
> Expose GPU utilization via /sys/kernel/debug/dri/<N>/gpu_load. The
> file reports busy_time_ns, idle_time_ns and gpu_load %.
>
> Values are snapshotted at the end of each devfreq sampling window
> (~50 ms) rather than read from live accumulators, avoiding load swings
> over short observation intervals.
>
> The snapshot is cleared on suspend to avoid stale data when the GPU
> is powered off.
>
> Signed-off-by: Guangliu Ding <guangliu.ding@nxp.com>
Hi Guangliu,
I'm puzzled exactly what you're trying to achieve with this. I can see
that getting the GPU load might be useful, we do already have the
'fdinfo' mechanism to do this in a per-client manner but nothing good
for "whole GPU" measurements.
But stashing it in debugfs and formatting it as a string seems odd. Do
you have a tool which uses this file, or is just for 'cat'ing to see the
instantaneous load?
Ideally we'd have something that would provide this information in a
format that all drivers could implement, and not rely on debugfs files.
Thanks,
Steve
> ---
> Add /sys/kernel/debug/dri/<N>/gpu_load to expose GPU utilisation
> from the last devfreq sampling window (~50 ms).
> The file reports busy_time_ns, idle_time_ns and load percentage.
>
> Tested on NXP i.MX95 EVK (Mali-G310 V2).
> ---
> drivers/gpu/drm/panthor/panthor_devfreq.c | 80 +++++++++++++++++++++++++++++++
> drivers/gpu/drm/panthor/panthor_devfreq.h | 6 +++
> drivers/gpu/drm/panthor/panthor_drv.c | 2 +
> 3 files changed, 88 insertions(+)
>
> diff --git a/drivers/gpu/drm/panthor/panthor_devfreq.c b/drivers/gpu/drm/panthor/panthor_devfreq.c
> index 2249b41ca4af..1b3f58ddfbd3 100644
> --- a/drivers/gpu/drm/panthor/panthor_devfreq.c
> +++ b/drivers/gpu/drm/panthor/panthor_devfreq.c
> @@ -1,12 +1,16 @@
> // SPDX-License-Identifier: GPL-2.0 or MIT
> /* Copyright 2019 Collabora ltd. */
> +/* Copyright 2026 NXP */
>
> #include <linux/clk.h>
> +#include <linux/debugfs.h>
> #include <linux/devfreq.h>
> #include <linux/devfreq_cooling.h>
> +#include <linux/math64.h>
> #include <linux/platform_device.h>
> #include <linux/pm_opp.h>
>
> +#include <drm/drm_file.h>
> #include <drm/drm_managed.h>
> #include <drm/drm_print.h>
>
> @@ -43,6 +47,22 @@ struct panthor_devfreq {
> * and panthor_devfreq_record_{busy,idle}().
> */
> spinlock_t lock;
> +
> +#ifdef CONFIG_DEBUG_FS
> + /**
> + * @last_busy_ns: Busy time in nanoseconds of the last completed devfreq window.
> + * Updated by panthor_devfreq_get_dev_status() before resetting the counters.
> + * Protected by @lock.
> + */
> + u64 last_busy_ns;
> +
> + /**
> + * @last_total_ns: Total time in nanoseconds of the last completed devfreq window.
> + * Updated by panthor_devfreq_get_dev_status() before resetting the counters.
> + * Protected by @lock.
> + */
> + u64 last_total_ns;
> +#endif
> };
>
> static void panthor_devfreq_update_utilization(struct panthor_devfreq *pdevfreq)
> @@ -101,6 +121,11 @@ static int panthor_devfreq_get_dev_status(struct device *dev,
>
> status->busy_time = ktime_to_ns(pdevfreq->busy_time);
>
> +#ifdef CONFIG_DEBUG_FS
> + pdevfreq->last_busy_ns = status->busy_time;
> + pdevfreq->last_total_ns = status->total_time;
> +#endif
> +
> panthor_devfreq_reset(pdevfreq);
>
> spin_unlock_irqrestore(&pdevfreq->lock, irqflags);
> @@ -283,6 +308,17 @@ void panthor_devfreq_suspend(struct panthor_device *ptdev)
> return;
>
> drm_WARN_ON(&ptdev->base, devfreq_suspend_device(pdevfreq->devfreq));
> +
> +#ifdef CONFIG_DEBUG_FS
> + {
> + unsigned long irqflags;
> +
> + spin_lock_irqsave(&pdevfreq->lock, irqflags);
> + pdevfreq->last_busy_ns = 0;
> + pdevfreq->last_total_ns = 0;
> + spin_unlock_irqrestore(&pdevfreq->lock, irqflags);
> + }
> +#endif
> }
>
> void panthor_devfreq_record_busy(struct panthor_device *ptdev)
> @@ -332,3 +368,47 @@ unsigned long panthor_devfreq_get_freq(struct panthor_device *ptdev)
>
> return freq;
> }
> +
> +#ifdef CONFIG_DEBUG_FS
> +static int panthor_devfreq_gpu_load_show(struct seq_file *m, void *unused)
> +{
> + struct panthor_device *ptdev = m->private;
> + struct panthor_devfreq *pdevfreq = ptdev->devfreq;
> + unsigned long irqflags;
> + unsigned int gpu_load;
> + u64 total_ns;
> + u64 busy_ns;
> +
> + if (!pdevfreq->devfreq) {
> + seq_puts(m, "devfreq not initialized\n");
> + return 0;
> + }
> +
> + spin_lock_irqsave(&pdevfreq->lock, irqflags);
> + busy_ns = pdevfreq->last_busy_ns;
> + total_ns = pdevfreq->last_total_ns;
> + spin_unlock_irqrestore(&pdevfreq->lock, irqflags);
> +
> + busy_ns = min(busy_ns, total_ns);
> + gpu_load = total_ns ? (unsigned int)div64_u64(busy_ns * 100ULL, total_ns) : 0;
> +
> + seq_printf(m, "busy_time_ns: %llu idle_time_ns: %llu gpu_load: %u%%\n",
> + busy_ns, total_ns - busy_ns, gpu_load);
> +
> + return 0;
> +}
> +DEFINE_SHOW_ATTRIBUTE(panthor_devfreq_gpu_load);
> +
> +/**
> + * panthor_devfreq_debugfs_init() - Initialize devfreq debugfs entries
> + * @minor: DRM minor.
> + */
> +void panthor_devfreq_debugfs_init(struct drm_minor *minor)
> +{
> + struct panthor_device *ptdev = container_of(minor->dev,
> + struct panthor_device, base);
> +
> + debugfs_create_file("gpu_load", 0444, minor->debugfs_root, ptdev,
> + &panthor_devfreq_gpu_load_fops);
> +}
> +#endif /* CONFIG_DEBUG_FS */
> diff --git a/drivers/gpu/drm/panthor/panthor_devfreq.h b/drivers/gpu/drm/panthor/panthor_devfreq.h
> index f8e29e02f66c..4552569abfe4 100644
> --- a/drivers/gpu/drm/panthor/panthor_devfreq.h
> +++ b/drivers/gpu/drm/panthor/panthor_devfreq.h
> @@ -1,5 +1,6 @@
> /* SPDX-License-Identifier: GPL-2.0 or MIT */
> /* Copyright 2019 Collabora ltd. */
> +/* Copyright 2026 NXP */
>
> #ifndef __PANTHOR_DEVFREQ_H__
> #define __PANTHOR_DEVFREQ_H__
> @@ -20,4 +21,9 @@ void panthor_devfreq_record_idle(struct panthor_device *ptdev);
>
> unsigned long panthor_devfreq_get_freq(struct panthor_device *ptdev);
>
> +#ifdef CONFIG_DEBUG_FS
> +struct drm_minor;
> +void panthor_devfreq_debugfs_init(struct drm_minor *minor);
> +#endif
> +
> #endif /* __PANTHOR_DEVFREQ_H__ */
> diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/panthor/panthor_drv.c
> index e8dc4096c1d2..4093a6d21337 100644
> --- a/drivers/gpu/drm/panthor/panthor_drv.c
> +++ b/drivers/gpu/drm/panthor/panthor_drv.c
> @@ -2,6 +2,7 @@
> /* Copyright 2018 Marty E. Plummer <hanetzer@startmail.com> */
> /* Copyright 2019 Linaro, Ltd., Rob Herring <robh@kernel.org> */
> /* Copyright 2019 Collabora ltd. */
> +/* Copyright 2026 NXP */
>
> #ifdef CONFIG_ARM_ARCH_TIMER
> #include <asm/arch_timer.h>
> @@ -1761,6 +1762,7 @@ static void panthor_debugfs_init(struct drm_minor *minor)
> {
> panthor_mmu_debugfs_init(minor);
> panthor_gem_debugfs_init(minor);
> + panthor_devfreq_debugfs_init(minor);
> }
> #endif
>
>
> ---
> base-commit: 8cdeaa50eae8dad34885515f62559ee83e7e8dda
> change-id: 20260706-master-bd0eef99ca8e
>
> Best regards,
> --
> Guangliu Ding <guangliu.ding@nxp.com>
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* RE: Re: [PATCH] drm/panthor: add gpu_load debugfs node
2026-07-10 14:52 ` Steven Price
@ 2026-07-13 3:19 ` Guangliu Ding
2026-07-15 16:27 ` Steven Price
0 siblings, 1 reply; 7+ messages in thread
From: Guangliu Ding @ 2026-07-13 3:19 UTC (permalink / raw)
To: Steven Price, Boris Brezillon, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
Cc: dri-devel, linux-kernel
> On 08/07/2026 04:24, Guangliu Ding wrote:
> > Expose GPU utilization via /sys/kernel/debug/dri/<N>/gpu_load. The
> > file reports busy_time_ns, idle_time_ns and gpu_load %.
> >
> > Values are snapshotted at the end of each devfreq sampling window
> > (~50 ms) rather than read from live accumulators, avoiding load swings
> > over short observation intervals.
> >
> > The snapshot is cleared on suspend to avoid stale data when the GPU is
> > powered off.
> >
> > Signed-off-by: Guangliu Ding <guangliu.ding@nxp.com>
>
> Hi Guangliu,
>
> I'm puzzled exactly what you're trying to achieve with this. I can see that
> getting the GPU load might be useful, we do already have the 'fdinfo' mechanism
> to do this in a per-client manner but nothing good for "whole GPU"
> measurements.
>
> But stashing it in debugfs and formatting it as a string seems odd. Do you have a
> tool which uses this file, or is just for 'cat'ing to see the instantaneous load?
>
> Ideally we'd have something that would provide this information in a format
> that all drivers could implement, and not rely on debugfs files.
>
> Thanks,
> Steve
>
Hi Steve
Panthor currently exposes very limited runtime telemetry. The intent is to expose utilization in this patch,
together with other device-wide GPU runtime metrics (frequency, shader activity, draw-call counts,
memory usage, etc.) to a userspace tool for monitoring and workload-optimization purposes.
fdinfo is primarily a per-client interface. Since it requires an open DRM fd and
reports information associated with that client, it does not map particularly
well to the global metrics exported by this patch.
If a generic cross-driver interface for this kind of GPU telemetry emerges,
I'm happy to switch to it. However, no such interface currently exists for
devfreq-based device utilization, so debugfs seemed like the most appropriate
existing option. Suggestions for a better interface are welcome.
Best Regards,
Guangliu
> > ---
> > Add /sys/kernel/debug/dri/<N>/gpu_load to expose GPU utilisation from
> > the last devfreq sampling window (~50 ms).
> > The file reports busy_time_ns, idle_time_ns and load percentage.
> >
> > Tested on NXP i.MX95 EVK (Mali-G310 V2).
> > ---
> > drivers/gpu/drm/panthor/panthor_devfreq.c | 80
> > +++++++++++++++++++++++++++++++
> drivers/gpu/drm/panthor/panthor_devfreq.h | 6 +++
> > drivers/gpu/drm/panthor/panthor_drv.c | 2 +
> > 3 files changed, 88 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/panthor/panthor_devfreq.c
> > b/drivers/gpu/drm/panthor/panthor_devfreq.c
> > index 2249b41ca4af..1b3f58ddfbd3 100644
> > --- a/drivers/gpu/drm/panthor/panthor_devfreq.c
> > +++ b/drivers/gpu/drm/panthor/panthor_devfreq.c
> > @@ -1,12 +1,16 @@
> > // SPDX-License-Identifier: GPL-2.0 or MIT
> > /* Copyright 2019 Collabora ltd. */
> > +/* Copyright 2026 NXP */
> >
> > #include <linux/clk.h>
> > +#include <linux/debugfs.h>
> > #include <linux/devfreq.h>
> > #include <linux/devfreq_cooling.h>
> > +#include <linux/math64.h>
> > #include <linux/platform_device.h>
> > #include <linux/pm_opp.h>
> >
> > +#include <drm/drm_file.h>
> > #include <drm/drm_managed.h>
> > #include <drm/drm_print.h>
> >
> > @@ -43,6 +47,22 @@ struct panthor_devfreq {
> > * and panthor_devfreq_record_{busy,idle}().
> > */
> > spinlock_t lock;
> > +
> > +#ifdef CONFIG_DEBUG_FS
> > + /**
> > + * @last_busy_ns: Busy time in nanoseconds of the last completed
> devfreq window.
> > + * Updated by panthor_devfreq_get_dev_status() before resetting the
> counters.
> > + * Protected by @lock.
> > + */
> > + u64 last_busy_ns;
> > +
> > + /**
> > + * @last_total_ns: Total time in nanoseconds of the last completed
> devfreq window.
> > + * Updated by panthor_devfreq_get_dev_status() before resetting the
> counters.
> > + * Protected by @lock.
> > + */
> > + u64 last_total_ns;
> > +#endif
> > };
> >
> > static void panthor_devfreq_update_utilization(struct panthor_devfreq
> > *pdevfreq) @@ -101,6 +121,11 @@ static int
> > panthor_devfreq_get_dev_status(struct device *dev,
> >
> > status->busy_time = ktime_to_ns(pdevfreq->busy_time);
> >
> > +#ifdef CONFIG_DEBUG_FS
> > + pdevfreq->last_busy_ns = status->busy_time;
> > + pdevfreq->last_total_ns = status->total_time; #endif
> > +
> > panthor_devfreq_reset(pdevfreq);
> >
> > spin_unlock_irqrestore(&pdevfreq->lock, irqflags); @@ -283,6
> > +308,17 @@ void panthor_devfreq_suspend(struct panthor_device *ptdev)
> > return;
> >
> > drm_WARN_ON(&ptdev->base,
> > devfreq_suspend_device(pdevfreq->devfreq));
> > +
> > +#ifdef CONFIG_DEBUG_FS
> > + {
> > + unsigned long irqflags;
> > +
> > + spin_lock_irqsave(&pdevfreq->lock, irqflags);
> > + pdevfreq->last_busy_ns = 0;
> > + pdevfreq->last_total_ns = 0;
> > + spin_unlock_irqrestore(&pdevfreq->lock, irqflags);
> > + }
> > +#endif
> > }
> >
> > void panthor_devfreq_record_busy(struct panthor_device *ptdev) @@
> > -332,3 +368,47 @@ unsigned long panthor_devfreq_get_freq(struct
> > panthor_device *ptdev)
> >
> > return freq;
> > }
> > +
> > +#ifdef CONFIG_DEBUG_FS
> > +static int panthor_devfreq_gpu_load_show(struct seq_file *m, void
> > +*unused) {
> > + struct panthor_device *ptdev = m->private;
> > + struct panthor_devfreq *pdevfreq = ptdev->devfreq;
> > + unsigned long irqflags;
> > + unsigned int gpu_load;
> > + u64 total_ns;
> > + u64 busy_ns;
> > +
> > + if (!pdevfreq->devfreq) {
> > + seq_puts(m, "devfreq not initialized\n");
> > + return 0;
> > + }
> > +
> > + spin_lock_irqsave(&pdevfreq->lock, irqflags);
> > + busy_ns = pdevfreq->last_busy_ns;
> > + total_ns = pdevfreq->last_total_ns;
> > + spin_unlock_irqrestore(&pdevfreq->lock, irqflags);
> > +
> > + busy_ns = min(busy_ns, total_ns);
> > + gpu_load = total_ns ? (unsigned int)div64_u64(busy_ns * 100ULL,
> > + total_ns) : 0;
> > +
> > + seq_printf(m, "busy_time_ns: %llu idle_time_ns: %llu
> gpu_load: %u%%\n",
> > + busy_ns, total_ns - busy_ns, gpu_load);
> > +
> > + return 0;
> > +}
> > +DEFINE_SHOW_ATTRIBUTE(panthor_devfreq_gpu_load);
> > +
> > +/**
> > + * panthor_devfreq_debugfs_init() - Initialize devfreq debugfs
> > +entries
> > + * @minor: DRM minor.
> > + */
> > +void panthor_devfreq_debugfs_init(struct drm_minor *minor) {
> > + struct panthor_device *ptdev = container_of(minor->dev,
> > + struct
> > +panthor_device, base);
> > +
> > + debugfs_create_file("gpu_load", 0444, minor->debugfs_root, ptdev,
> > + &panthor_devfreq_gpu_load_fops); } #endif
> /*
> > +CONFIG_DEBUG_FS */
> > diff --git a/drivers/gpu/drm/panthor/panthor_devfreq.h
> > b/drivers/gpu/drm/panthor/panthor_devfreq.h
> > index f8e29e02f66c..4552569abfe4 100644
> > --- a/drivers/gpu/drm/panthor/panthor_devfreq.h
> > +++ b/drivers/gpu/drm/panthor/panthor_devfreq.h
> > @@ -1,5 +1,6 @@
> > /* SPDX-License-Identifier: GPL-2.0 or MIT */
> > /* Copyright 2019 Collabora ltd. */
> > +/* Copyright 2026 NXP */
> >
> > #ifndef __PANTHOR_DEVFREQ_H__
> > #define __PANTHOR_DEVFREQ_H__
> > @@ -20,4 +21,9 @@ void panthor_devfreq_record_idle(struct
> > panthor_device *ptdev);
> >
> > unsigned long panthor_devfreq_get_freq(struct panthor_device *ptdev);
> >
> > +#ifdef CONFIG_DEBUG_FS
> > +struct drm_minor;
> > +void panthor_devfreq_debugfs_init(struct drm_minor *minor); #endif
> > +
> > #endif /* __PANTHOR_DEVFREQ_H__ */
> > diff --git a/drivers/gpu/drm/panthor/panthor_drv.c
> > b/drivers/gpu/drm/panthor/panthor_drv.c
> > index e8dc4096c1d2..4093a6d21337 100644
> > --- a/drivers/gpu/drm/panthor/panthor_drv.c
> > +++ b/drivers/gpu/drm/panthor/panthor_drv.c
> > @@ -2,6 +2,7 @@
> > /* Copyright 2018 Marty E. Plummer <hanetzer@startmail.com> */
> > /* Copyright 2019 Linaro, Ltd., Rob Herring <robh@kernel.org> */
> > /* Copyright 2019 Collabora ltd. */
> > +/* Copyright 2026 NXP */
> >
> > #ifdef CONFIG_ARM_ARCH_TIMER
> > #include <asm/arch_timer.h>
> > @@ -1761,6 +1762,7 @@ static void panthor_debugfs_init(struct
> > drm_minor *minor) {
> > panthor_mmu_debugfs_init(minor);
> > panthor_gem_debugfs_init(minor);
> > + panthor_devfreq_debugfs_init(minor);
> > }
> > #endif
> >
> >
> > ---
> > base-commit: 8cdeaa50eae8dad34885515f62559ee83e7e8dda
> > change-id: 20260706-master-bd0eef99ca8e
> >
> > Best regards,
> > --
> > Guangliu Ding <guangliu.ding@nxp.com>
> >
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] drm/panthor: add gpu_load debugfs node
2026-07-13 3:19 ` Guangliu Ding
@ 2026-07-15 16:27 ` Steven Price
2026-07-16 2:05 ` Guangliu Ding
0 siblings, 1 reply; 7+ messages in thread
From: Steven Price @ 2026-07-15 16:27 UTC (permalink / raw)
To: Guangliu Ding, Boris Brezillon, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
Cc: dri-devel, linux-kernel
On 13/07/2026 04:19, Guangliu Ding wrote:
>> On 08/07/2026 04:24, Guangliu Ding wrote:
>>> Expose GPU utilization via /sys/kernel/debug/dri/<N>/gpu_load. The
>>> file reports busy_time_ns, idle_time_ns and gpu_load %.
>>>
>>> Values are snapshotted at the end of each devfreq sampling window
>>> (~50 ms) rather than read from live accumulators, avoiding load swings
>>> over short observation intervals.
>>>
>>> The snapshot is cleared on suspend to avoid stale data when the GPU is
>>> powered off.
>>>
>>> Signed-off-by: Guangliu Ding <guangliu.ding@nxp.com>
>>
>> Hi Guangliu,
>>
>> I'm puzzled exactly what you're trying to achieve with this. I can see that
>> getting the GPU load might be useful, we do already have the 'fdinfo' mechanism
>> to do this in a per-client manner but nothing good for "whole GPU"
>> measurements.
>>
>> But stashing it in debugfs and formatting it as a string seems odd. Do you have a
>> tool which uses this file, or is just for 'cat'ing to see the instantaneous load?
>>
>> Ideally we'd have something that would provide this information in a format
>> that all drivers could implement, and not rely on debugfs files.
>>
>> Thanks,
>> Steve
>>
>
> Hi Steve
>
> Panthor currently exposes very limited runtime telemetry. The intent is to expose utilization in this patch,
> together with other device-wide GPU runtime metrics (frequency, shader activity, draw-call counts,
> memory usage, etc.) to a userspace tool for monitoring and workload-optimization purposes.
>
> fdinfo is primarily a per-client interface. Since it requires an open DRM fd and
> reports information associated with that client, it does not map particularly
> well to the global metrics exported by this patch.
>
> If a generic cross-driver interface for this kind of GPU telemetry emerges,
> I'm happy to switch to it. However, no such interface currently exists for
> devfreq-based device utilization, so debugfs seemed like the most appropriate
> existing option. Suggestions for a better interface are welcome.
So my point really is someone should ideally implement a better
interface that multiple drivers can use. Having a point hack for one
driver doesn't really help the situation.
Indeed you can get the load information with ftrace already:
cd /sys/kernel/tracing
echo 0 > tracing_on
echo > trace
echo 'dev_name == "fb000000.gpu"' > events/devfreq/devfreq_monitor/filter
echo 1 > events/devfreq/devfreq_monitor/enable
echo 1 > tracing_on
cat trace_pipe
And you'll get a stream of messages when the GPU is in use which
includes a "load=xx" value at the end.
If this is going to be extended to other properties for a user space
tool then we should probably be putting this in sysfs and trying to come
up with a design that other drivers can copy.
Thanks,
Steve
> Best Regards,
> Guangliu
>
>>> ---
>>> Add /sys/kernel/debug/dri/<N>/gpu_load to expose GPU utilisation from
>>> the last devfreq sampling window (~50 ms).
>>> The file reports busy_time_ns, idle_time_ns and load percentage.
>>>
>>> Tested on NXP i.MX95 EVK (Mali-G310 V2).
>>> ---
>>> drivers/gpu/drm/panthor/panthor_devfreq.c | 80
>>> +++++++++++++++++++++++++++++++
>> drivers/gpu/drm/panthor/panthor_devfreq.h | 6 +++
>>> drivers/gpu/drm/panthor/panthor_drv.c | 2 +
>>> 3 files changed, 88 insertions(+)
>>>
>>> diff --git a/drivers/gpu/drm/panthor/panthor_devfreq.c
>>> b/drivers/gpu/drm/panthor/panthor_devfreq.c
>>> index 2249b41ca4af..1b3f58ddfbd3 100644
>>> --- a/drivers/gpu/drm/panthor/panthor_devfreq.c
>>> +++ b/drivers/gpu/drm/panthor/panthor_devfreq.c
>>> @@ -1,12 +1,16 @@
>>> // SPDX-License-Identifier: GPL-2.0 or MIT
>>> /* Copyright 2019 Collabora ltd. */
>>> +/* Copyright 2026 NXP */
>>>
>>> #include <linux/clk.h>
>>> +#include <linux/debugfs.h>
>>> #include <linux/devfreq.h>
>>> #include <linux/devfreq_cooling.h>
>>> +#include <linux/math64.h>
>>> #include <linux/platform_device.h>
>>> #include <linux/pm_opp.h>
>>>
>>> +#include <drm/drm_file.h>
>>> #include <drm/drm_managed.h>
>>> #include <drm/drm_print.h>
>>>
>>> @@ -43,6 +47,22 @@ struct panthor_devfreq {
>>> * and panthor_devfreq_record_{busy,idle}().
>>> */
>>> spinlock_t lock;
>>> +
>>> +#ifdef CONFIG_DEBUG_FS
>>> + /**
>>> + * @last_busy_ns: Busy time in nanoseconds of the last completed
>> devfreq window.
>>> + * Updated by panthor_devfreq_get_dev_status() before resetting the
>> counters.
>>> + * Protected by @lock.
>>> + */
>>> + u64 last_busy_ns;
>>> +
>>> + /**
>>> + * @last_total_ns: Total time in nanoseconds of the last completed
>> devfreq window.
>>> + * Updated by panthor_devfreq_get_dev_status() before resetting the
>> counters.
>>> + * Protected by @lock.
>>> + */
>>> + u64 last_total_ns;
>>> +#endif
>>> };
>>>
>>> static void panthor_devfreq_update_utilization(struct panthor_devfreq
>>> *pdevfreq) @@ -101,6 +121,11 @@ static int
>>> panthor_devfreq_get_dev_status(struct device *dev,
>>>
>>> status->busy_time = ktime_to_ns(pdevfreq->busy_time);
>>>
>>> +#ifdef CONFIG_DEBUG_FS
>>> + pdevfreq->last_busy_ns = status->busy_time;
>>> + pdevfreq->last_total_ns = status->total_time; #endif
>>> +
>>> panthor_devfreq_reset(pdevfreq);
>>>
>>> spin_unlock_irqrestore(&pdevfreq->lock, irqflags); @@ -283,6
>>> +308,17 @@ void panthor_devfreq_suspend(struct panthor_device *ptdev)
>>> return;
>>>
>>> drm_WARN_ON(&ptdev->base,
>>> devfreq_suspend_device(pdevfreq->devfreq));
>>> +
>>> +#ifdef CONFIG_DEBUG_FS
>>> + {
>>> + unsigned long irqflags;
>>> +
>>> + spin_lock_irqsave(&pdevfreq->lock, irqflags);
>>> + pdevfreq->last_busy_ns = 0;
>>> + pdevfreq->last_total_ns = 0;
>>> + spin_unlock_irqrestore(&pdevfreq->lock, irqflags);
>>> + }
>>> +#endif
>>> }
>>>
>>> void panthor_devfreq_record_busy(struct panthor_device *ptdev) @@
>>> -332,3 +368,47 @@ unsigned long panthor_devfreq_get_freq(struct
>>> panthor_device *ptdev)
>>>
>>> return freq;
>>> }
>>> +
>>> +#ifdef CONFIG_DEBUG_FS
>>> +static int panthor_devfreq_gpu_load_show(struct seq_file *m, void
>>> +*unused) {
>>> + struct panthor_device *ptdev = m->private;
>>> + struct panthor_devfreq *pdevfreq = ptdev->devfreq;
>>> + unsigned long irqflags;
>>> + unsigned int gpu_load;
>>> + u64 total_ns;
>>> + u64 busy_ns;
>>> +
>>> + if (!pdevfreq->devfreq) {
>>> + seq_puts(m, "devfreq not initialized\n");
>>> + return 0;
>>> + }
>>> +
>>> + spin_lock_irqsave(&pdevfreq->lock, irqflags);
>>> + busy_ns = pdevfreq->last_busy_ns;
>>> + total_ns = pdevfreq->last_total_ns;
>>> + spin_unlock_irqrestore(&pdevfreq->lock, irqflags);
>>> +
>>> + busy_ns = min(busy_ns, total_ns);
>>> + gpu_load = total_ns ? (unsigned int)div64_u64(busy_ns * 100ULL,
>>> + total_ns) : 0;
>>> +
>>> + seq_printf(m, "busy_time_ns: %llu idle_time_ns: %llu
>> gpu_load: %u%%\n",
>>> + busy_ns, total_ns - busy_ns, gpu_load);
>>> +
>>> + return 0;
>>> +}
>>> +DEFINE_SHOW_ATTRIBUTE(panthor_devfreq_gpu_load);
>>> +
>>> +/**
>>> + * panthor_devfreq_debugfs_init() - Initialize devfreq debugfs
>>> +entries
>>> + * @minor: DRM minor.
>>> + */
>>> +void panthor_devfreq_debugfs_init(struct drm_minor *minor) {
>>> + struct panthor_device *ptdev = container_of(minor->dev,
>>> + struct
>>> +panthor_device, base);
>>> +
>>> + debugfs_create_file("gpu_load", 0444, minor->debugfs_root, ptdev,
>>> + &panthor_devfreq_gpu_load_fops); } #endif
>> /*
>>> +CONFIG_DEBUG_FS */
>>> diff --git a/drivers/gpu/drm/panthor/panthor_devfreq.h
>>> b/drivers/gpu/drm/panthor/panthor_devfreq.h
>>> index f8e29e02f66c..4552569abfe4 100644
>>> --- a/drivers/gpu/drm/panthor/panthor_devfreq.h
>>> +++ b/drivers/gpu/drm/panthor/panthor_devfreq.h
>>> @@ -1,5 +1,6 @@
>>> /* SPDX-License-Identifier: GPL-2.0 or MIT */
>>> /* Copyright 2019 Collabora ltd. */
>>> +/* Copyright 2026 NXP */
>>>
>>> #ifndef __PANTHOR_DEVFREQ_H__
>>> #define __PANTHOR_DEVFREQ_H__
>>> @@ -20,4 +21,9 @@ void panthor_devfreq_record_idle(struct
>>> panthor_device *ptdev);
>>>
>>> unsigned long panthor_devfreq_get_freq(struct panthor_device *ptdev);
>>>
>>> +#ifdef CONFIG_DEBUG_FS
>>> +struct drm_minor;
>>> +void panthor_devfreq_debugfs_init(struct drm_minor *minor); #endif
>>> +
>>> #endif /* __PANTHOR_DEVFREQ_H__ */
>>> diff --git a/drivers/gpu/drm/panthor/panthor_drv.c
>>> b/drivers/gpu/drm/panthor/panthor_drv.c
>>> index e8dc4096c1d2..4093a6d21337 100644
>>> --- a/drivers/gpu/drm/panthor/panthor_drv.c
>>> +++ b/drivers/gpu/drm/panthor/panthor_drv.c
>>> @@ -2,6 +2,7 @@
>>> /* Copyright 2018 Marty E. Plummer <hanetzer@startmail.com> */
>>> /* Copyright 2019 Linaro, Ltd., Rob Herring <robh@kernel.org> */
>>> /* Copyright 2019 Collabora ltd. */
>>> +/* Copyright 2026 NXP */
>>>
>>> #ifdef CONFIG_ARM_ARCH_TIMER
>>> #include <asm/arch_timer.h>
>>> @@ -1761,6 +1762,7 @@ static void panthor_debugfs_init(struct
>>> drm_minor *minor) {
>>> panthor_mmu_debugfs_init(minor);
>>> panthor_gem_debugfs_init(minor);
>>> + panthor_devfreq_debugfs_init(minor);
>>> }
>>> #endif
>>>
>>>
>>> ---
>>> base-commit: 8cdeaa50eae8dad34885515f62559ee83e7e8dda
>>> change-id: 20260706-master-bd0eef99ca8e
>>>
>>> Best regards,
>>> --
>>> Guangliu Ding <guangliu.ding@nxp.com>
>>>
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* RE: Re: [PATCH] drm/panthor: add gpu_load debugfs node
2026-07-15 16:27 ` Steven Price
@ 2026-07-16 2:05 ` Guangliu Ding
2026-07-16 10:44 ` Liviu Dudau
0 siblings, 1 reply; 7+ messages in thread
From: Guangliu Ding @ 2026-07-16 2:05 UTC (permalink / raw)
To: Steven Price, Boris Brezillon, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
Cc: dri-devel, linux-kernel
> On 13/07/2026 04:19, Guangliu Ding wrote:
> >> On 08/07/2026 04:24, Guangliu Ding wrote:
> >>> Expose GPU utilization via /sys/kernel/debug/dri/<N>/gpu_load. The
> >>> file reports busy_time_ns, idle_time_ns and gpu_load %.
> >>>
> >>> Values are snapshotted at the end of each devfreq sampling window
> >>> (~50 ms) rather than read from live accumulators, avoiding load
> >>> swings over short observation intervals.
> >>>
> >>> The snapshot is cleared on suspend to avoid stale data when the GPU
> >>> is powered off.
> >>>
> >>> Signed-off-by: Guangliu Ding <guangliu.ding@nxp.com>
> >>
> >> Hi Guangliu,
> >>
> >> I'm puzzled exactly what you're trying to achieve with this. I can
> >> see that getting the GPU load might be useful, we do already have the
> >> 'fdinfo' mechanism to do this in a per-client manner but nothing good for
> "whole GPU"
> >> measurements.
> >>
> >> But stashing it in debugfs and formatting it as a string seems odd.
> >> Do you have a tool which uses this file, or is just for 'cat'ing to see the
> instantaneous load?
> >>
> >> Ideally we'd have something that would provide this information in a
> >> format that all drivers could implement, and not rely on debugfs files.
> >>
> >> Thanks,
> >> Steve
> >>
> >
> > Hi Steve
> >
> > Panthor currently exposes very limited runtime telemetry. The intent
> > is to expose utilization in this patch, together with other
> > device-wide GPU runtime metrics (frequency, shader activity, draw-call counts,
> memory usage, etc.) to a userspace tool for monitoring and
> workload-optimization purposes.
> >
> > fdinfo is primarily a per-client interface. Since it requires an open
> > DRM fd and reports information associated with that client, it does
> > not map particularly well to the global metrics exported by this patch.
> >
> > If a generic cross-driver interface for this kind of GPU telemetry
> > emerges, I'm happy to switch to it. However, no such interface
> > currently exists for devfreq-based device utilization, so debugfs
> > seemed like the most appropriate existing option. Suggestions for a better
> interface are welcome.
>
> So my point really is someone should ideally implement a better interface that
> multiple drivers can use. Having a point hack for one driver doesn't really help
> the situation.
>
> Indeed you can get the load information with ftrace already:
>
> cd /sys/kernel/tracing
> echo 0 > tracing_on
> echo > trace
> echo 'dev_name == "fb000000.gpu"' > events/devfreq/devfreq_monitor/filter
> echo 1 > events/devfreq/devfreq_monitor/enable
> echo 1 > tracing_on
> cat trace_pipe
>
> And you'll get a stream of messages when the GPU is in use which includes a
> "load=xx" value at the end.
>
> If this is going to be extended to other properties for a user space tool then we
> should probably be putting this in sysfs and trying to come up with a design that
> other drivers can copy.
>
> Thanks,
> Steve
>
Hi Steve,
Thanks for the feedback and sharing.
I agree that a generic interface shared by multiple drivers would be preferable in the long term.
For our use case, we need to provide customers with a simple way to quickly observe GPU
performance metrics from a userspace tuning tool. Even though the devfreq_monitor tracepoint already
exposes the load information, ftrace is typically not enabled or supported in our deployed products,
making it unsuitable as a user-facing interface for the tool.
As far as I know, there is currently no generic DRM/devfreq interface for querying device-wide
GPU utilization on demand. Given that gap, exporting the information through debugfs
seemed like the most practical option for Panthor today.
Thanks,
Guangliu
> > Best Regards,
> > Guangliu
> >
> >>> ---
> >>> Add /sys/kernel/debug/dri/<N>/gpu_load to expose GPU utilisation
> >>> from the last devfreq sampling window (~50 ms).
> >>> The file reports busy_time_ns, idle_time_ns and load percentage.
> >>>
> >>> Tested on NXP i.MX95 EVK (Mali-G310 V2).
> >>> ---
> >>> drivers/gpu/drm/panthor/panthor_devfreq.c | 80
> >>> +++++++++++++++++++++++++++++++
> >> drivers/gpu/drm/panthor/panthor_devfreq.h | 6 +++
> >>> drivers/gpu/drm/panthor/panthor_drv.c | 2 +
> >>> 3 files changed, 88 insertions(+)
> >>>
> >>> diff --git a/drivers/gpu/drm/panthor/panthor_devfreq.c
> >>> b/drivers/gpu/drm/panthor/panthor_devfreq.c
> >>> index 2249b41ca4af..1b3f58ddfbd3 100644
> >>> --- a/drivers/gpu/drm/panthor/panthor_devfreq.c
> >>> +++ b/drivers/gpu/drm/panthor/panthor_devfreq.c
> >>> @@ -1,12 +1,16 @@
> >>> // SPDX-License-Identifier: GPL-2.0 or MIT
> >>> /* Copyright 2019 Collabora ltd. */
> >>> +/* Copyright 2026 NXP */
> >>>
> >>> #include <linux/clk.h>
> >>> +#include <linux/debugfs.h>
> >>> #include <linux/devfreq.h>
> >>> #include <linux/devfreq_cooling.h>
> >>> +#include <linux/math64.h>
> >>> #include <linux/platform_device.h>
> >>> #include <linux/pm_opp.h>
> >>>
> >>> +#include <drm/drm_file.h>
> >>> #include <drm/drm_managed.h>
> >>> #include <drm/drm_print.h>
> >>>
> >>> @@ -43,6 +47,22 @@ struct panthor_devfreq {
> >>> * and panthor_devfreq_record_{busy,idle}().
> >>> */
> >>> spinlock_t lock;
> >>> +
> >>> +#ifdef CONFIG_DEBUG_FS
> >>> + /**
> >>> + * @last_busy_ns: Busy time in nanoseconds of the last
> >>> +completed
> >> devfreq window.
> >>> + * Updated by panthor_devfreq_get_dev_status() before
> >>> + resetting the
> >> counters.
> >>> + * Protected by @lock.
> >>> + */
> >>> + u64 last_busy_ns;
> >>> +
> >>> + /**
> >>> + * @last_total_ns: Total time in nanoseconds of the last
> >>> + completed
> >> devfreq window.
> >>> + * Updated by panthor_devfreq_get_dev_status() before
> >>> + resetting the
> >> counters.
> >>> + * Protected by @lock.
> >>> + */
> >>> + u64 last_total_ns;
> >>> +#endif
> >>> };
> >>>
> >>> static void panthor_devfreq_update_utilization(struct
> >>> panthor_devfreq
> >>> *pdevfreq) @@ -101,6 +121,11 @@ static int
> >>> panthor_devfreq_get_dev_status(struct device *dev,
> >>>
> >>> status->busy_time = ktime_to_ns(pdevfreq->busy_time);
> >>>
> >>> +#ifdef CONFIG_DEBUG_FS
> >>> + pdevfreq->last_busy_ns = status->busy_time;
> >>> + pdevfreq->last_total_ns = status->total_time; #endif
> >>> +
> >>> panthor_devfreq_reset(pdevfreq);
> >>>
> >>> spin_unlock_irqrestore(&pdevfreq->lock, irqflags); @@ -283,6
> >>> +308,17 @@ void panthor_devfreq_suspend(struct panthor_device
> >>> +*ptdev)
> >>> return;
> >>>
> >>> drm_WARN_ON(&ptdev->base,
> >>> devfreq_suspend_device(pdevfreq->devfreq));
> >>> +
> >>> +#ifdef CONFIG_DEBUG_FS
> >>> + {
> >>> + unsigned long irqflags;
> >>> +
> >>> + spin_lock_irqsave(&pdevfreq->lock, irqflags);
> >>> + pdevfreq->last_busy_ns = 0;
> >>> + pdevfreq->last_total_ns = 0;
> >>> + spin_unlock_irqrestore(&pdevfreq->lock, irqflags);
> >>> + }
> >>> +#endif
> >>> }
> >>>
> >>> void panthor_devfreq_record_busy(struct panthor_device *ptdev) @@
> >>> -332,3 +368,47 @@ unsigned long panthor_devfreq_get_freq(struct
> >>> panthor_device *ptdev)
> >>>
> >>> return freq;
> >>> }
> >>> +
> >>> +#ifdef CONFIG_DEBUG_FS
> >>> +static int panthor_devfreq_gpu_load_show(struct seq_file *m, void
> >>> +*unused) {
> >>> + struct panthor_device *ptdev = m->private;
> >>> + struct panthor_devfreq *pdevfreq = ptdev->devfreq;
> >>> + unsigned long irqflags;
> >>> + unsigned int gpu_load;
> >>> + u64 total_ns;
> >>> + u64 busy_ns;
> >>> +
> >>> + if (!pdevfreq->devfreq) {
> >>> + seq_puts(m, "devfreq not initialized\n");
> >>> + return 0;
> >>> + }
> >>> +
> >>> + spin_lock_irqsave(&pdevfreq->lock, irqflags);
> >>> + busy_ns = pdevfreq->last_busy_ns;
> >>> + total_ns = pdevfreq->last_total_ns;
> >>> + spin_unlock_irqrestore(&pdevfreq->lock, irqflags);
> >>> +
> >>> + busy_ns = min(busy_ns, total_ns);
> >>> + gpu_load = total_ns ? (unsigned int)div64_u64(busy_ns *
> >>> + 100ULL,
> >>> + total_ns) : 0;
> >>> +
> >>> + seq_printf(m, "busy_time_ns: %llu idle_time_ns: %llu
> >> gpu_load: %u%%\n",
> >>> + busy_ns, total_ns - busy_ns, gpu_load);
> >>> +
> >>> + return 0;
> >>> +}
> >>> +DEFINE_SHOW_ATTRIBUTE(panthor_devfreq_gpu_load);
> >>> +
> >>> +/**
> >>> + * panthor_devfreq_debugfs_init() - Initialize devfreq debugfs
> >>> +entries
> >>> + * @minor: DRM minor.
> >>> + */
> >>> +void panthor_devfreq_debugfs_init(struct drm_minor *minor) {
> >>> + struct panthor_device *ptdev = container_of(minor->dev,
> >>> + struct
> >>> +panthor_device, base);
> >>> +
> >>> + debugfs_create_file("gpu_load", 0444, minor->debugfs_root, ptdev,
> >>> + &panthor_devfreq_gpu_load_fops); }
> #endif
> >> /*
> >>> +CONFIG_DEBUG_FS */
> >>> diff --git a/drivers/gpu/drm/panthor/panthor_devfreq.h
> >>> b/drivers/gpu/drm/panthor/panthor_devfreq.h
> >>> index f8e29e02f66c..4552569abfe4 100644
> >>> --- a/drivers/gpu/drm/panthor/panthor_devfreq.h
> >>> +++ b/drivers/gpu/drm/panthor/panthor_devfreq.h
> >>> @@ -1,5 +1,6 @@
> >>> /* SPDX-License-Identifier: GPL-2.0 or MIT */
> >>> /* Copyright 2019 Collabora ltd. */
> >>> +/* Copyright 2026 NXP */
> >>>
> >>> #ifndef __PANTHOR_DEVFREQ_H__
> >>> #define __PANTHOR_DEVFREQ_H__
> >>> @@ -20,4 +21,9 @@ void panthor_devfreq_record_idle(struct
> >>> panthor_device *ptdev);
> >>>
> >>> unsigned long panthor_devfreq_get_freq(struct panthor_device
> >>> *ptdev);
> >>>
> >>> +#ifdef CONFIG_DEBUG_FS
> >>> +struct drm_minor;
> >>> +void panthor_devfreq_debugfs_init(struct drm_minor *minor); #endif
> >>> +
> >>> #endif /* __PANTHOR_DEVFREQ_H__ */
> >>> diff --git a/drivers/gpu/drm/panthor/panthor_drv.c
> >>> b/drivers/gpu/drm/panthor/panthor_drv.c
> >>> index e8dc4096c1d2..4093a6d21337 100644
> >>> --- a/drivers/gpu/drm/panthor/panthor_drv.c
> >>> +++ b/drivers/gpu/drm/panthor/panthor_drv.c
> >>> @@ -2,6 +2,7 @@
> >>> /* Copyright 2018 Marty E. Plummer <hanetzer@startmail.com> */
> >>> /* Copyright 2019 Linaro, Ltd., Rob Herring <robh@kernel.org> */
> >>> /* Copyright 2019 Collabora ltd. */
> >>> +/* Copyright 2026 NXP */
> >>>
> >>> #ifdef CONFIG_ARM_ARCH_TIMER
> >>> #include <asm/arch_timer.h>
> >>> @@ -1761,6 +1762,7 @@ static void panthor_debugfs_init(struct
> >>> drm_minor *minor) {
> >>> panthor_mmu_debugfs_init(minor);
> >>> panthor_gem_debugfs_init(minor);
> >>> + panthor_devfreq_debugfs_init(minor);
> >>> }
> >>> #endif
> >>>
> >>>
> >>> ---
> >>> base-commit: 8cdeaa50eae8dad34885515f62559ee83e7e8dda
> >>> change-id: 20260706-master-bd0eef99ca8e
> >>>
> >>> Best regards,
> >>> --
> >>> Guangliu Ding <guangliu.ding@nxp.com>
> >>>
> >
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Re: [PATCH] drm/panthor: add gpu_load debugfs node
2026-07-16 2:05 ` Guangliu Ding
@ 2026-07-16 10:44 ` Liviu Dudau
2026-07-16 16:38 ` Guangliu Ding
0 siblings, 1 reply; 7+ messages in thread
From: Liviu Dudau @ 2026-07-16 10:44 UTC (permalink / raw)
To: Guangliu Ding
Cc: Steven Price, Boris Brezillon, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, dri-devel,
linux-kernel
On Thu, Jul 16, 2026 at 02:05:47AM +0000, Guangliu Ding wrote:
> > On 13/07/2026 04:19, Guangliu Ding wrote:
> > >> On 08/07/2026 04:24, Guangliu Ding wrote:
> > >>> Expose GPU utilization via /sys/kernel/debug/dri/<N>/gpu_load. The
> > >>> file reports busy_time_ns, idle_time_ns and gpu_load %.
> > >>>
> > >>> Values are snapshotted at the end of each devfreq sampling window
> > >>> (~50 ms) rather than read from live accumulators, avoiding load
> > >>> swings over short observation intervals.
> > >>>
> > >>> The snapshot is cleared on suspend to avoid stale data when the GPU
> > >>> is powered off.
> > >>>
> > >>> Signed-off-by: Guangliu Ding <guangliu.ding@nxp.com>
> > >>
> > >> Hi Guangliu,
> > >>
> > >> I'm puzzled exactly what you're trying to achieve with this. I can
> > >> see that getting the GPU load might be useful, we do already have the
> > >> 'fdinfo' mechanism to do this in a per-client manner but nothing good for
> > "whole GPU"
> > >> measurements.
> > >>
> > >> But stashing it in debugfs and formatting it as a string seems odd.
> > >> Do you have a tool which uses this file, or is just for 'cat'ing to see the
> > instantaneous load?
> > >>
> > >> Ideally we'd have something that would provide this information in a
> > >> format that all drivers could implement, and not rely on debugfs files.
> > >>
> > >> Thanks,
> > >> Steve
> > >>
> > >
> > > Hi Steve
> > >
> > > Panthor currently exposes very limited runtime telemetry. The intent
> > > is to expose utilization in this patch, together with other
> > > device-wide GPU runtime metrics (frequency, shader activity, draw-call counts,
> > memory usage, etc.) to a userspace tool for monitoring and
> > workload-optimization purposes.
> > >
> > > fdinfo is primarily a per-client interface. Since it requires an open
> > > DRM fd and reports information associated with that client, it does
> > > not map particularly well to the global metrics exported by this patch.
> > >
> > > If a generic cross-driver interface for this kind of GPU telemetry
> > > emerges, I'm happy to switch to it. However, no such interface
> > > currently exists for devfreq-based device utilization, so debugfs
> > > seemed like the most appropriate existing option. Suggestions for a better
> > interface are welcome.
> >
> > So my point really is someone should ideally implement a better interface that
> > multiple drivers can use. Having a point hack for one driver doesn't really help
> > the situation.
> >
> > Indeed you can get the load information with ftrace already:
> >
> > cd /sys/kernel/tracing
> > echo 0 > tracing_on
> > echo > trace
> > echo 'dev_name == "fb000000.gpu"' > events/devfreq/devfreq_monitor/filter
> > echo 1 > events/devfreq/devfreq_monitor/enable
> > echo 1 > tracing_on
> > cat trace_pipe
> >
> > And you'll get a stream of messages when the GPU is in use which includes a
> > "load=xx" value at the end.
> >
> > If this is going to be extended to other properties for a user space tool then we
> > should probably be putting this in sysfs and trying to come up with a design that
> > other drivers can copy.
> >
> > Thanks,
> > Steve
> >
>
> Hi Steve,
>
> Thanks for the feedback and sharing.
> I agree that a generic interface shared by multiple drivers would be preferable in the long term.
>
> For our use case, we need to provide customers with a simple way to quickly observe GPU
> performance metrics from a userspace tuning tool. Even though the devfreq_monitor tracepoint already
> exposes the load information, ftrace is typically not enabled or supported in our deployed products,
> making it unsuitable as a user-facing interface for the tool.
You are enabling debugfs but not ftrace? Seems like an odd choice if you want to monitor and tune your system.
We are working on adding performance counters support to Panthor that will expose performance metrics in a
more meaningful way.
>
> As far as I know, there is currently no generic DRM/devfreq interface for querying device-wide
> GPU utilization on demand. Given that gap, exporting the information through debugfs
> seemed like the most practical option for Panthor today.
Knowing that the GPU was 80% busy without knowing exactly who was submitting jobs is not a particularly
useful information, in my opinion. I would like to understand better what you are trying to do with the
information and why implementing a devfreq governor for your usecase would not be useful here.
Best regards,
Liviu
>
> Thanks,
> Guangliu
>
> > > Best Regards,
> > > Guangliu
> > >
> > >>> ---
> > >>> Add /sys/kernel/debug/dri/<N>/gpu_load to expose GPU utilisation
> > >>> from the last devfreq sampling window (~50 ms).
> > >>> The file reports busy_time_ns, idle_time_ns and load percentage.
> > >>>
> > >>> Tested on NXP i.MX95 EVK (Mali-G310 V2).
> > >>> ---
> > >>> drivers/gpu/drm/panthor/panthor_devfreq.c | 80
> > >>> +++++++++++++++++++++++++++++++
> > >> drivers/gpu/drm/panthor/panthor_devfreq.h | 6 +++
> > >>> drivers/gpu/drm/panthor/panthor_drv.c | 2 +
> > >>> 3 files changed, 88 insertions(+)
> > >>>
> > >>> diff --git a/drivers/gpu/drm/panthor/panthor_devfreq.c
> > >>> b/drivers/gpu/drm/panthor/panthor_devfreq.c
> > >>> index 2249b41ca4af..1b3f58ddfbd3 100644
> > >>> --- a/drivers/gpu/drm/panthor/panthor_devfreq.c
> > >>> +++ b/drivers/gpu/drm/panthor/panthor_devfreq.c
> > >>> @@ -1,12 +1,16 @@
> > >>> // SPDX-License-Identifier: GPL-2.0 or MIT
> > >>> /* Copyright 2019 Collabora ltd. */
> > >>> +/* Copyright 2026 NXP */
> > >>>
> > >>> #include <linux/clk.h>
> > >>> +#include <linux/debugfs.h>
> > >>> #include <linux/devfreq.h>
> > >>> #include <linux/devfreq_cooling.h>
> > >>> +#include <linux/math64.h>
> > >>> #include <linux/platform_device.h>
> > >>> #include <linux/pm_opp.h>
> > >>>
> > >>> +#include <drm/drm_file.h>
> > >>> #include <drm/drm_managed.h>
> > >>> #include <drm/drm_print.h>
> > >>>
> > >>> @@ -43,6 +47,22 @@ struct panthor_devfreq {
> > >>> * and panthor_devfreq_record_{busy,idle}().
> > >>> */
> > >>> spinlock_t lock;
> > >>> +
> > >>> +#ifdef CONFIG_DEBUG_FS
> > >>> + /**
> > >>> + * @last_busy_ns: Busy time in nanoseconds of the last
> > >>> +completed
> > >> devfreq window.
> > >>> + * Updated by panthor_devfreq_get_dev_status() before
> > >>> + resetting the
> > >> counters.
> > >>> + * Protected by @lock.
> > >>> + */
> > >>> + u64 last_busy_ns;
> > >>> +
> > >>> + /**
> > >>> + * @last_total_ns: Total time in nanoseconds of the last
> > >>> + completed
> > >> devfreq window.
> > >>> + * Updated by panthor_devfreq_get_dev_status() before
> > >>> + resetting the
> > >> counters.
> > >>> + * Protected by @lock.
> > >>> + */
> > >>> + u64 last_total_ns;
> > >>> +#endif
> > >>> };
> > >>>
> > >>> static void panthor_devfreq_update_utilization(struct
> > >>> panthor_devfreq
> > >>> *pdevfreq) @@ -101,6 +121,11 @@ static int
> > >>> panthor_devfreq_get_dev_status(struct device *dev,
> > >>>
> > >>> status->busy_time = ktime_to_ns(pdevfreq->busy_time);
> > >>>
> > >>> +#ifdef CONFIG_DEBUG_FS
> > >>> + pdevfreq->last_busy_ns = status->busy_time;
> > >>> + pdevfreq->last_total_ns = status->total_time; #endif
> > >>> +
> > >>> panthor_devfreq_reset(pdevfreq);
> > >>>
> > >>> spin_unlock_irqrestore(&pdevfreq->lock, irqflags); @@ -283,6
> > >>> +308,17 @@ void panthor_devfreq_suspend(struct panthor_device
> > >>> +*ptdev)
> > >>> return;
> > >>>
> > >>> drm_WARN_ON(&ptdev->base,
> > >>> devfreq_suspend_device(pdevfreq->devfreq));
> > >>> +
> > >>> +#ifdef CONFIG_DEBUG_FS
> > >>> + {
> > >>> + unsigned long irqflags;
> > >>> +
> > >>> + spin_lock_irqsave(&pdevfreq->lock, irqflags);
> > >>> + pdevfreq->last_busy_ns = 0;
> > >>> + pdevfreq->last_total_ns = 0;
> > >>> + spin_unlock_irqrestore(&pdevfreq->lock, irqflags);
> > >>> + }
> > >>> +#endif
> > >>> }
> > >>>
> > >>> void panthor_devfreq_record_busy(struct panthor_device *ptdev) @@
> > >>> -332,3 +368,47 @@ unsigned long panthor_devfreq_get_freq(struct
> > >>> panthor_device *ptdev)
> > >>>
> > >>> return freq;
> > >>> }
> > >>> +
> > >>> +#ifdef CONFIG_DEBUG_FS
> > >>> +static int panthor_devfreq_gpu_load_show(struct seq_file *m, void
> > >>> +*unused) {
> > >>> + struct panthor_device *ptdev = m->private;
> > >>> + struct panthor_devfreq *pdevfreq = ptdev->devfreq;
> > >>> + unsigned long irqflags;
> > >>> + unsigned int gpu_load;
> > >>> + u64 total_ns;
> > >>> + u64 busy_ns;
> > >>> +
> > >>> + if (!pdevfreq->devfreq) {
> > >>> + seq_puts(m, "devfreq not initialized\n");
> > >>> + return 0;
> > >>> + }
> > >>> +
> > >>> + spin_lock_irqsave(&pdevfreq->lock, irqflags);
> > >>> + busy_ns = pdevfreq->last_busy_ns;
> > >>> + total_ns = pdevfreq->last_total_ns;
> > >>> + spin_unlock_irqrestore(&pdevfreq->lock, irqflags);
> > >>> +
> > >>> + busy_ns = min(busy_ns, total_ns);
> > >>> + gpu_load = total_ns ? (unsigned int)div64_u64(busy_ns *
> > >>> + 100ULL,
> > >>> + total_ns) : 0;
> > >>> +
> > >>> + seq_printf(m, "busy_time_ns: %llu idle_time_ns: %llu
> > >> gpu_load: %u%%\n",
> > >>> + busy_ns, total_ns - busy_ns, gpu_load);
> > >>> +
> > >>> + return 0;
> > >>> +}
> > >>> +DEFINE_SHOW_ATTRIBUTE(panthor_devfreq_gpu_load);
> > >>> +
> > >>> +/**
> > >>> + * panthor_devfreq_debugfs_init() - Initialize devfreq debugfs
> > >>> +entries
> > >>> + * @minor: DRM minor.
> > >>> + */
> > >>> +void panthor_devfreq_debugfs_init(struct drm_minor *minor) {
> > >>> + struct panthor_device *ptdev = container_of(minor->dev,
> > >>> + struct
> > >>> +panthor_device, base);
> > >>> +
> > >>> + debugfs_create_file("gpu_load", 0444, minor->debugfs_root, ptdev,
> > >>> + &panthor_devfreq_gpu_load_fops); }
> > #endif
> > >> /*
> > >>> +CONFIG_DEBUG_FS */
> > >>> diff --git a/drivers/gpu/drm/panthor/panthor_devfreq.h
> > >>> b/drivers/gpu/drm/panthor/panthor_devfreq.h
> > >>> index f8e29e02f66c..4552569abfe4 100644
> > >>> --- a/drivers/gpu/drm/panthor/panthor_devfreq.h
> > >>> +++ b/drivers/gpu/drm/panthor/panthor_devfreq.h
> > >>> @@ -1,5 +1,6 @@
> > >>> /* SPDX-License-Identifier: GPL-2.0 or MIT */
> > >>> /* Copyright 2019 Collabora ltd. */
> > >>> +/* Copyright 2026 NXP */
> > >>>
> > >>> #ifndef __PANTHOR_DEVFREQ_H__
> > >>> #define __PANTHOR_DEVFREQ_H__
> > >>> @@ -20,4 +21,9 @@ void panthor_devfreq_record_idle(struct
> > >>> panthor_device *ptdev);
> > >>>
> > >>> unsigned long panthor_devfreq_get_freq(struct panthor_device
> > >>> *ptdev);
> > >>>
> > >>> +#ifdef CONFIG_DEBUG_FS
> > >>> +struct drm_minor;
> > >>> +void panthor_devfreq_debugfs_init(struct drm_minor *minor); #endif
> > >>> +
> > >>> #endif /* __PANTHOR_DEVFREQ_H__ */
> > >>> diff --git a/drivers/gpu/drm/panthor/panthor_drv.c
> > >>> b/drivers/gpu/drm/panthor/panthor_drv.c
> > >>> index e8dc4096c1d2..4093a6d21337 100644
> > >>> --- a/drivers/gpu/drm/panthor/panthor_drv.c
> > >>> +++ b/drivers/gpu/drm/panthor/panthor_drv.c
> > >>> @@ -2,6 +2,7 @@
> > >>> /* Copyright 2018 Marty E. Plummer <hanetzer@startmail.com> */
> > >>> /* Copyright 2019 Linaro, Ltd., Rob Herring <robh@kernel.org> */
> > >>> /* Copyright 2019 Collabora ltd. */
> > >>> +/* Copyright 2026 NXP */
> > >>>
> > >>> #ifdef CONFIG_ARM_ARCH_TIMER
> > >>> #include <asm/arch_timer.h>
> > >>> @@ -1761,6 +1762,7 @@ static void panthor_debugfs_init(struct
> > >>> drm_minor *minor) {
> > >>> panthor_mmu_debugfs_init(minor);
> > >>> panthor_gem_debugfs_init(minor);
> > >>> + panthor_devfreq_debugfs_init(minor);
> > >>> }
> > >>> #endif
> > >>>
> > >>>
> > >>> ---
> > >>> base-commit: 8cdeaa50eae8dad34885515f62559ee83e7e8dda
> > >>> change-id: 20260706-master-bd0eef99ca8e
> > >>>
> > >>> Best regards,
> > >>> --
> > >>> Guangliu Ding <guangliu.ding@nxp.com>
> > >>>
> > >
>
--
====================
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
¯\_(ツ)_/¯
^ permalink raw reply [flat|nested] 7+ messages in thread
* RE: Re: Re: [PATCH] drm/panthor: add gpu_load debugfs node
2026-07-16 10:44 ` Liviu Dudau
@ 2026-07-16 16:38 ` Guangliu Ding
0 siblings, 0 replies; 7+ messages in thread
From: Guangliu Ding @ 2026-07-16 16:38 UTC (permalink / raw)
To: Liviu Dudau
Cc: Steven Price, Boris Brezillon, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, dri-devel,
linux-kernel
> On Thu, Jul 16, 2026 at 02:05:47AM +0000, Guangliu Ding wrote:
> > > On 13/07/2026 04:19, Guangliu Ding wrote:
> > > >> On 08/07/2026 04:24, Guangliu Ding wrote:
> > > >>> Expose GPU utilization via /sys/kernel/debug/dri/<N>/gpu_load.
> > > >>> The file reports busy_time_ns, idle_time_ns and gpu_load %.
> > > >>>
> > > >>> Values are snapshotted at the end of each devfreq sampling
> > > >>> window
> > > >>> (~50 ms) rather than read from live accumulators, avoiding load
> > > >>> swings over short observation intervals.
> > > >>>
> > > >>> The snapshot is cleared on suspend to avoid stale data when the
> > > >>> GPU is powered off.
> > > >>>
> > > >>> Signed-off-by: Guangliu Ding <guangliu.ding@nxp.com>
> > > >>
> > > >> Hi Guangliu,
> > > >>
> > > >> I'm puzzled exactly what you're trying to achieve with this. I
> > > >> can see that getting the GPU load might be useful, we do already
> > > >> have the 'fdinfo' mechanism to do this in a per-client manner but
> > > >> nothing good for
> > > "whole GPU"
> > > >> measurements.
> > > >>
> > > >> But stashing it in debugfs and formatting it as a string seems odd.
> > > >> Do you have a tool which uses this file, or is just for 'cat'ing
> > > >> to see the
> > > instantaneous load?
> > > >>
> > > >> Ideally we'd have something that would provide this information
> > > >> in a format that all drivers could implement, and not rely on debugfs
> files.
> > > >>
> > > >> Thanks,
> > > >> Steve
> > > >>
> > > >
> > > > Hi Steve
> > > >
> > > > Panthor currently exposes very limited runtime telemetry. The
> > > > intent is to expose utilization in this patch, together with other
> > > > device-wide GPU runtime metrics (frequency, shader activity,
> > > > draw-call counts,
> > > memory usage, etc.) to a userspace tool for monitoring and
> > > workload-optimization purposes.
> > > >
> > > > fdinfo is primarily a per-client interface. Since it requires an
> > > > open DRM fd and reports information associated with that client,
> > > > it does not map particularly well to the global metrics exported by this
> patch.
> > > >
> > > > If a generic cross-driver interface for this kind of GPU telemetry
> > > > emerges, I'm happy to switch to it. However, no such interface
> > > > currently exists for devfreq-based device utilization, so debugfs
> > > > seemed like the most appropriate existing option. Suggestions for
> > > > a better
> > > interface are welcome.
> > >
> > > So my point really is someone should ideally implement a better
> > > interface that multiple drivers can use. Having a point hack for one
> > > driver doesn't really help the situation.
> > >
> > > Indeed you can get the load information with ftrace already:
> > >
> > > cd /sys/kernel/tracing
> > > echo 0 > tracing_on
> > > echo > trace
> > > echo 'dev_name == "fb000000.gpu"' >
> events/devfreq/devfreq_monitor/filter
> > > echo 1 > events/devfreq/devfreq_monitor/enable
> > > echo 1 > tracing_on
> > > cat trace_pipe
> > >
> > > And you'll get a stream of messages when the GPU is in use which
> > > includes a "load=xx" value at the end.
> > >
> > > If this is going to be extended to other properties for a user space
> > > tool then we should probably be putting this in sysfs and trying to
> > > come up with a design that other drivers can copy.
> > >
> > > Thanks,
> > > Steve
> > >
> >
> > Hi Steve,
> >
> > Thanks for the feedback and sharing.
> > I agree that a generic interface shared by multiple drivers would be
> preferable in the long term.
> >
> > For our use case, we need to provide customers with a simple way to
> > quickly observe GPU performance metrics from a userspace tuning tool.
> > Even though the devfreq_monitor tracepoint already exposes the load
> > information, ftrace is typically not enabled or supported in our deployed
> products, making it unsuitable as a user-facing interface for the tool.
>
> You are enabling debugfs but not ftrace? Seems like an odd choice if you want
> to monitor and tune your system.
>
> We are working on adding performance counters support to Panthor that will
> expose performance metrics in a more meaningful way.
>
> >
> > As far as I know, there is currently no generic DRM/devfreq interface
> > for querying device-wide GPU utilization on demand. Given that gap,
> > exporting the information through debugfs seemed like the most practical
> option for Panthor today.
>
> Knowing that the GPU was 80% busy without knowing exactly who was
> submitting jobs is not a particularly useful information, in my opinion. I would
> like to understand better what you are trying to do with the information and
> why implementing a devfreq governor for your usecase would not be useful
> here.
>
> Best regards,
> Liviu
>
Hi Liviu
Happy to hear that performance counters will be supported to Panthor.
Are there any plans to expose detailed utilization statistics of gpu device/
fragment shader/non-fragment shader/tiler to panthor debugfs?
If yes, do you have a rough timeline for this?
The userspace tuning tool is developed to gather both overall gpu statistics
(frequency, utilization, etc.) and gpu per-process information (memory usage,
etc.) from debugfs and expose to user for reference.
The original idea of this patch is that performance counters are not available yet,
so obtaining overall gpu utilization from DVFS appears to be the most practical
approach for now.
The tool is also intended to work without ftrace, since ftrace is usually disabled
by default. As a result, debugfs is currently our preferred interface for collecting
such information.
Thanks,
Guangliu
> >
> > Thanks,
> > Guangliu
> >
> > > > Best Regards,
> > > > Guangliu
> > > >
> > > >>> ---
> > > >>> Add /sys/kernel/debug/dri/<N>/gpu_load to expose GPU utilisation
> > > >>> from the last devfreq sampling window (~50 ms).
> > > >>> The file reports busy_time_ns, idle_time_ns and load percentage.
> > > >>>
> > > >>> Tested on NXP i.MX95 EVK (Mali-G310 V2).
> > > >>> ---
> > > >>> drivers/gpu/drm/panthor/panthor_devfreq.c | 80
> > > >>> +++++++++++++++++++++++++++++++
> > > >> drivers/gpu/drm/panthor/panthor_devfreq.h | 6 +++
> > > >>> drivers/gpu/drm/panthor/panthor_drv.c | 2 +
> > > >>> 3 files changed, 88 insertions(+)
> > > >>>
> > > >>> diff --git a/drivers/gpu/drm/panthor/panthor_devfreq.c
> > > >>> b/drivers/gpu/drm/panthor/panthor_devfreq.c
> > > >>> index 2249b41ca4af..1b3f58ddfbd3 100644
> > > >>> --- a/drivers/gpu/drm/panthor/panthor_devfreq.c
> > > >>> +++ b/drivers/gpu/drm/panthor/panthor_devfreq.c
> > > >>> @@ -1,12 +1,16 @@
> > > >>> // SPDX-License-Identifier: GPL-2.0 or MIT
> > > >>> /* Copyright 2019 Collabora ltd. */
> > > >>> +/* Copyright 2026 NXP */
> > > >>>
> > > >>> #include <linux/clk.h>
> > > >>> +#include <linux/debugfs.h>
> > > >>> #include <linux/devfreq.h>
> > > >>> #include <linux/devfreq_cooling.h>
> > > >>> +#include <linux/math64.h>
> > > >>> #include <linux/platform_device.h> #include <linux/pm_opp.h>
> > > >>>
> > > >>> +#include <drm/drm_file.h>
> > > >>> #include <drm/drm_managed.h>
> > > >>> #include <drm/drm_print.h>
> > > >>>
> > > >>> @@ -43,6 +47,22 @@ struct panthor_devfreq {
> > > >>> * and panthor_devfreq_record_{busy,idle}().
> > > >>> */
> > > >>> spinlock_t lock;
> > > >>> +
> > > >>> +#ifdef CONFIG_DEBUG_FS
> > > >>> + /**
> > > >>> + * @last_busy_ns: Busy time in nanoseconds of the last
> > > >>> +completed
> > > >> devfreq window.
> > > >>> + * Updated by panthor_devfreq_get_dev_status() before
> > > >>> + resetting the
> > > >> counters.
> > > >>> + * Protected by @lock.
> > > >>> + */
> > > >>> + u64 last_busy_ns;
> > > >>> +
> > > >>> + /**
> > > >>> + * @last_total_ns: Total time in nanoseconds of the last
> > > >>> + completed
> > > >> devfreq window.
> > > >>> + * Updated by panthor_devfreq_get_dev_status() before
> > > >>> + resetting the
> > > >> counters.
> > > >>> + * Protected by @lock.
> > > >>> + */
> > > >>> + u64 last_total_ns;
> > > >>> +#endif
> > > >>> };
> > > >>>
> > > >>> static void panthor_devfreq_update_utilization(struct
> > > >>> panthor_devfreq
> > > >>> *pdevfreq) @@ -101,6 +121,11 @@ static int
> > > >>> panthor_devfreq_get_dev_status(struct device *dev,
> > > >>>
> > > >>> status->busy_time = ktime_to_ns(pdevfreq->busy_time);
> > > >>>
> > > >>> +#ifdef CONFIG_DEBUG_FS
> > > >>> + pdevfreq->last_busy_ns = status->busy_time;
> > > >>> + pdevfreq->last_total_ns = status->total_time; #endif
> > > >>> +
> > > >>> panthor_devfreq_reset(pdevfreq);
> > > >>>
> > > >>> spin_unlock_irqrestore(&pdevfreq->lock, irqflags); @@
> > > >>> -283,6
> > > >>> +308,17 @@ void panthor_devfreq_suspend(struct panthor_device
> > > >>> +*ptdev)
> > > >>> return;
> > > >>>
> > > >>> drm_WARN_ON(&ptdev->base,
> > > >>> devfreq_suspend_device(pdevfreq->devfreq));
> > > >>> +
> > > >>> +#ifdef CONFIG_DEBUG_FS
> > > >>> + {
> > > >>> + unsigned long irqflags;
> > > >>> +
> > > >>> + spin_lock_irqsave(&pdevfreq->lock, irqflags);
> > > >>> + pdevfreq->last_busy_ns = 0;
> > > >>> + pdevfreq->last_total_ns = 0;
> > > >>> + spin_unlock_irqrestore(&pdevfreq->lock, irqflags);
> > > >>> + }
> > > >>> +#endif
> > > >>> }
> > > >>>
> > > >>> void panthor_devfreq_record_busy(struct panthor_device *ptdev)
> > > >>> @@
> > > >>> -332,3 +368,47 @@ unsigned long panthor_devfreq_get_freq(struct
> > > >>> panthor_device *ptdev)
> > > >>>
> > > >>> return freq;
> > > >>> }
> > > >>> +
> > > >>> +#ifdef CONFIG_DEBUG_FS
> > > >>> +static int panthor_devfreq_gpu_load_show(struct seq_file *m,
> > > >>> +void
> > > >>> +*unused) {
> > > >>> + struct panthor_device *ptdev = m->private;
> > > >>> + struct panthor_devfreq *pdevfreq = ptdev->devfreq;
> > > >>> + unsigned long irqflags;
> > > >>> + unsigned int gpu_load;
> > > >>> + u64 total_ns;
> > > >>> + u64 busy_ns;
> > > >>> +
> > > >>> + if (!pdevfreq->devfreq) {
> > > >>> + seq_puts(m, "devfreq not initialized\n");
> > > >>> + return 0;
> > > >>> + }
> > > >>> +
> > > >>> + spin_lock_irqsave(&pdevfreq->lock, irqflags);
> > > >>> + busy_ns = pdevfreq->last_busy_ns;
> > > >>> + total_ns = pdevfreq->last_total_ns;
> > > >>> + spin_unlock_irqrestore(&pdevfreq->lock, irqflags);
> > > >>> +
> > > >>> + busy_ns = min(busy_ns, total_ns);
> > > >>> + gpu_load = total_ns ? (unsigned int)div64_u64(busy_ns *
> > > >>> + 100ULL,
> > > >>> + total_ns) : 0;
> > > >>> +
> > > >>> + seq_printf(m, "busy_time_ns: %llu idle_time_ns: %llu
> > > >> gpu_load: %u%%\n",
> > > >>> + busy_ns, total_ns - busy_ns, gpu_load);
> > > >>> +
> > > >>> + return 0;
> > > >>> +}
> > > >>> +DEFINE_SHOW_ATTRIBUTE(panthor_devfreq_gpu_load);
> > > >>> +
> > > >>> +/**
> > > >>> + * panthor_devfreq_debugfs_init() - Initialize devfreq debugfs
> > > >>> +entries
> > > >>> + * @minor: DRM minor.
> > > >>> + */
> > > >>> +void panthor_devfreq_debugfs_init(struct drm_minor *minor) {
> > > >>> + struct panthor_device *ptdev = container_of(minor->dev,
> > > >>> + struct
> > > >>> +panthor_device, base);
> > > >>> +
> > > >>> + debugfs_create_file("gpu_load", 0444, minor->debugfs_root,
> ptdev,
> > > >>> + &panthor_devfreq_gpu_load_fops); }
> > > #endif
> > > >> /*
> > > >>> +CONFIG_DEBUG_FS */
> > > >>> diff --git a/drivers/gpu/drm/panthor/panthor_devfreq.h
> > > >>> b/drivers/gpu/drm/panthor/panthor_devfreq.h
> > > >>> index f8e29e02f66c..4552569abfe4 100644
> > > >>> --- a/drivers/gpu/drm/panthor/panthor_devfreq.h
> > > >>> +++ b/drivers/gpu/drm/panthor/panthor_devfreq.h
> > > >>> @@ -1,5 +1,6 @@
> > > >>> /* SPDX-License-Identifier: GPL-2.0 or MIT */
> > > >>> /* Copyright 2019 Collabora ltd. */
> > > >>> +/* Copyright 2026 NXP */
> > > >>>
> > > >>> #ifndef __PANTHOR_DEVFREQ_H__
> > > >>> #define __PANTHOR_DEVFREQ_H__
> > > >>> @@ -20,4 +21,9 @@ void panthor_devfreq_record_idle(struct
> > > >>> panthor_device *ptdev);
> > > >>>
> > > >>> unsigned long panthor_devfreq_get_freq(struct panthor_device
> > > >>> *ptdev);
> > > >>>
> > > >>> +#ifdef CONFIG_DEBUG_FS
> > > >>> +struct drm_minor;
> > > >>> +void panthor_devfreq_debugfs_init(struct drm_minor *minor);
> > > >>> +#endif
> > > >>> +
> > > >>> #endif /* __PANTHOR_DEVFREQ_H__ */ diff --git
> > > >>> a/drivers/gpu/drm/panthor/panthor_drv.c
> > > >>> b/drivers/gpu/drm/panthor/panthor_drv.c
> > > >>> index e8dc4096c1d2..4093a6d21337 100644
> > > >>> --- a/drivers/gpu/drm/panthor/panthor_drv.c
> > > >>> +++ b/drivers/gpu/drm/panthor/panthor_drv.c
> > > >>> @@ -2,6 +2,7 @@
> > > >>> /* Copyright 2018 Marty E. Plummer <hanetzer@startmail.com> */
> > > >>> /* Copyright 2019 Linaro, Ltd., Rob Herring <robh@kernel.org>
> > > >>> */
> > > >>> /* Copyright 2019 Collabora ltd. */
> > > >>> +/* Copyright 2026 NXP */
> > > >>>
> > > >>> #ifdef CONFIG_ARM_ARCH_TIMER
> > > >>> #include <asm/arch_timer.h>
> > > >>> @@ -1761,6 +1762,7 @@ static void panthor_debugfs_init(struct
> > > >>> drm_minor *minor) {
> > > >>> panthor_mmu_debugfs_init(minor);
> > > >>> panthor_gem_debugfs_init(minor);
> > > >>> + panthor_devfreq_debugfs_init(minor);
> > > >>> }
> > > >>> #endif
> > > >>>
> > > >>>
> > > >>> ---
> > > >>> base-commit: 8cdeaa50eae8dad34885515f62559ee83e7e8dda
> > > >>> change-id: 20260706-master-bd0eef99ca8e
> > > >>>
> > > >>> Best regards,
> > > >>> --
> > > >>> Guangliu Ding <guangliu.ding@nxp.com>
> > > >>>
> > > >
> >
>
> --
> ====================
> | I would like to |
> | fix the world, |
> | but they're not |
> | giving me the |
> \ source code! /
> ---------------
> ¯\_(ツ)_/¯
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-07-16 16:38 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-07-08 3:24 [PATCH] drm/panthor: add gpu_load debugfs node Guangliu Ding
2026-07-10 14:52 ` Steven Price
2026-07-13 3:19 ` Guangliu Ding
2026-07-15 16:27 ` Steven Price
2026-07-16 2:05 ` Guangliu Ding
2026-07-16 10:44 ` Liviu Dudau
2026-07-16 16:38 ` Guangliu Ding
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox