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 <[email protected]>
> > >>
> > >> 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 <[email protected]> */
> > >>> /* Copyright 2019 Linaro, Ltd., Rob Herring <[email protected]> */
> > >>> /* 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 <[email protected]>
> > >>>
> > >
>
--
====================
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
¯\_(ツ)_/¯