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

> 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]>
>>>
> 

Reply via email to