[PATCH] tools/xe_gputop: Adding GPU frequency support
Disantkumar Mistry
disantkumar.isvarbhai.mistry at intel.com
Thu Jul 17 04:09:17 UTC 2025
XE PMU expose GT frequency events to user space via perf interface.
Reading each GT's frequency using PMU interface(gt-actual-frequency,
gt-requested-frequency). Calculate average frequency of all GT and
showing frequency details in gputop as device description section.
Signed-off-by: Disantkumar Mistry <disantkumar.isvarbhai.mistry at intel.com>
---
tools/gputop/xe_gputop.c | 88 ++++++++++++++++++++++++++++++++++++++--
tools/gputop/xe_gputop.h | 5 +++
2 files changed, 89 insertions(+), 4 deletions(-)
diff --git a/tools/gputop/xe_gputop.c b/tools/gputop/xe_gputop.c
index 9757369a8..bcc08226d 100644
--- a/tools/gputop/xe_gputop.c
+++ b/tools/gputop/xe_gputop.c
@@ -47,6 +47,20 @@ void xe_clean_up(void *obj, int len)
if (gputop_dev[i].card)
free(gputop_dev[i].card);
if (gputop_dev[i].pmu_device_obj) {
+ /* Free FDs from GT Frequency PMU counter */
+ for (int j = 0; j < gputop_dev[i].pmu_device_obj->num_gts; j++) {
+ pmu_counter = gputop_dev[i].pmu_device_obj->gt_act_freq[i];
+ if (pmu_counter.present)
+ close(pmu_counter.fd);
+
+ pmu_counter = gputop_dev[i].pmu_device_obj->gt_req_freq[i];
+ if (pmu_counter.present)
+ close(pmu_counter.fd);
+ }
+
+ free(gputop_dev[i].pmu_device_obj->gt_act_freq);
+ free(gputop_dev[i].pmu_device_obj->gt_req_freq);
+
for (int j = 0;
j < gputop_dev[i].pmu_device_obj->num_engines;
j++) {
@@ -127,6 +141,7 @@ void *xe_populate_engines(const void *obj, int index)
struct igt_device_card *card = ptr->card;
uint64_t engine_active_config, engine_total_config;
uint64_t engine_class, engine_instance, gt_shift;
+ uint64_t gt_actual_freq, gt_requested_freq;
struct drm_xe_engine_class_instance *hwe;
struct xe_pmu_device *engines;
char device[30];
@@ -157,7 +172,32 @@ void *xe_populate_engines(const void *obj, int index)
gt_shift = pmu_format_shift(card_fd, "gt");
engine_class = pmu_format_shift(card_fd, "engine_class");
engine_instance = pmu_format_shift(card_fd, "engine_instance");
+
xe_perf_device(card_fd, device, sizeof(device));
+
+ engines->num_gts = xe_number_gt(card_fd);
+
+ engines->gt_act_freq = malloc(sizeof(struct xe_pmu_counter) * engines->num_gts);
+ if (!engines->gt_act_freq)
+ return NULL;
+
+ engines->gt_req_freq = malloc(sizeof(struct xe_pmu_counter) * engines->num_gts);
+ if (!engines->gt_req_freq)
+ return NULL;
+
+ ret = perf_event_config(device, "gt-actual-frequency", >_actual_freq);
+ if (ret < 0)
+ return NULL;
+
+ ret = perf_event_config(device, "gt-requested-frequency", >_requested_freq);
+ if (ret < 0)
+ return NULL;
+
+ for (int i = 0; i < engines->num_gts; i++) {
+ engines->gt_act_freq[i].config = i << gt_shift | gt_actual_freq;
+ engines->gt_req_freq[i].config = i << gt_shift | gt_requested_freq;
+ }
+
engines->device = strdup(device);
ret = perf_event_config(device, "engine-active-ticks", &engine_active_config);
if (ret < 0)
@@ -237,6 +277,28 @@ void xe_pmu_sample(const void *obj, int index)
pmu_read_multi(engines->fd, num_val, val);
+ engines->act_freq.val.prev = 0;
+ engines->act_freq.val.cur = 0;
+ engines->req_freq.val.prev = 0;
+ engines->req_freq.val.cur = 0;
+
+ for (i = 0; i < engines->num_gts; i++) {
+ update_sample(&engines->gt_act_freq[i], val);
+ engines->act_freq.val.prev = engines->act_freq.val.cur;
+ engines->act_freq.val.cur += engines->gt_act_freq[i].val.cur -
+ engines->gt_act_freq[i].val.prev;
+
+ update_sample(&engines->gt_req_freq[i], val);
+ engines->req_freq.val.prev = engines->req_freq.val.cur;
+ engines->req_freq.val.cur += engines->gt_req_freq[i].val.cur -
+ engines->gt_req_freq[i].val.prev;
+ }
+
+ engines->act_freq.val.cur /= engines->num_gts;
+ engines->act_freq.val.prev /= engines->num_gts;
+ engines->req_freq.val.cur /= engines->num_gts;
+ engines->req_freq.val.prev /= engines->num_gts;
+
for (i = 0; i < engines->num_engines; i++) {
struct xe_engine *engine = engine_ptr(engines, i);
@@ -258,6 +320,20 @@ int xe_pmu_init(const void *obj, int index)
engines->fd = -1;
engines->num_counters = 0;
+ for (i = 0; i < engines->num_gts; i++) {
+ fd = _open_pmu(type, &engines->num_counters,
+ &engines->gt_act_freq[i],
+ &engines->fd);
+ if (fd < 0)
+ return -1;
+
+ fd = _open_pmu(type, &engines->num_counters,
+ &engines->gt_req_freq[i],
+ &engines->fd);
+ if (fd < 0)
+ return -1;
+ }
+
for (i = 0; i < engines->num_engines; i++) {
engine = engine_ptr(engines, i);
fd = _open_pmu(type, &engines->num_counters, &engine->engine_active_ticks,
@@ -289,10 +365,14 @@ print_device_description(const void *obj, int lines, int w, int h)
{
char *desc;
int len;
-
- len = asprintf(&desc, "DRIVER: %s || BDF: %s",
- ((struct xe_gputop *)obj)->card->driver,
- ((struct xe_gputop *)obj)->card->pci_slot_name);
+ struct igt_device_card *card = ((struct xe_gputop *)obj)->card;
+ struct xe_pmu_device *device = ((struct xe_gputop *)obj)->pmu_device_obj;
+
+ len = asprintf(&desc, "DRIVER: %s || BDF: %s || FREQUENCY: %lu/%lu MHz",
+ card->driver,
+ card->pci_slot_name,
+ device->act_freq.val.cur,
+ device->req_freq.val.cur);
printf("\033[7m%s%*s\033[0m\n",
desc,
diff --git a/tools/gputop/xe_gputop.h b/tools/gputop/xe_gputop.h
index 1e3856071..8c599e9d5 100644
--- a/tools/gputop/xe_gputop.h
+++ b/tools/gputop/xe_gputop.h
@@ -39,8 +39,13 @@ struct xe_engine {
struct xe_pmu_device {
unsigned int num_engines;
unsigned int num_counters;
+ unsigned int num_gts;
int fd;
char *device;
+ struct xe_pmu_counter act_freq;
+ struct xe_pmu_counter *gt_act_freq;
+ struct xe_pmu_counter req_freq;
+ struct xe_pmu_counter *gt_req_freq;
struct xe_engine engine;
};
--
2.34.1
More information about the igt-dev
mailing list