[PATCH v2] tools/gputop/xe_gputop: Adding GPU frequency support

Disantkumar Mistry disantkumar.isvarbhai.mistry at intel.com
Tue Jul 22 05:14:33 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). Exposing each GT frequency details in gputop
as device description section.

Signed-off-by: Disantkumar Mistry <disantkumar.isvarbhai.mistry at intel.com>
---
 tools/gputop/xe_gputop.c | 84 +++++++++++++++++++++++++++++++++++++---
 tools/gputop/xe_gputop.h |  3 ++
 2 files changed, 82 insertions(+), 5 deletions(-)

diff --git a/tools/gputop/xe_gputop.c b/tools/gputop/xe_gputop.c
index 9757369a8..5b2055a19 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", &gt_actual_freq);
+	if (ret < 0)
+		return NULL;
+
+	ret = perf_event_config(device, "gt-requested-frequency", &gt_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,11 @@ void xe_pmu_sample(const void *obj, int index)
 
 	pmu_read_multi(engines->fd, num_val, val);
 
+	for (i = 0; i < engines->num_gts; i++) {
+		update_sample(&engines->gt_act_freq[i], val);
+		update_sample(&engines->gt_req_freq[i], val);
+	}
+
 	for (i = 0; i < engines->num_engines; i++) {
 		struct xe_engine *engine = engine_ptr(engines, i);
 
@@ -258,6 +303,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,
@@ -287,18 +346,33 @@ static double pmu_active_percentage(struct xe_engine *engine)
 static int
 print_device_description(const void *obj, int lines, int w, int h)
 {
-	char *desc;
-	int len;
+	char *desc, *gt_freq = NULL;
+	int len = 0, counter = 0;
+	struct igt_device_card *card = ((struct xe_gputop *)obj)->card;
+	struct xe_pmu_device *device = ((struct xe_gputop *)obj)->pmu_device_obj;
+
+	for (int i = 0; i < device->num_gts; i++) {
+		long act_freq = device->gt_act_freq[i].val.cur - device->gt_act_freq[i].val.prev;
+		long req_freq = device->gt_req_freq[i].val.cur - device->gt_req_freq[i].val.prev;
+
+		len += snprintf(NULL, 0, "FREQ-GT%d: %lu/%lu  ", i, act_freq, req_freq);
+		gt_freq = (char *)realloc(gt_freq, (len + 1) * sizeof(char));
+
+		sprintf(gt_freq + counter, "FREQ-GT%d: %lu/%lu  ", i, act_freq, req_freq);
+		counter = len;
+	}
 
-	len = asprintf(&desc, "DRIVER: %s || BDF: %s",
-		       ((struct xe_gputop *)obj)->card->driver,
-		       ((struct xe_gputop *)obj)->card->pci_slot_name);
+	len = asprintf(&desc, "DRIVER: %s || BDF: %s || %s",
+		       card->driver,
+		       card->pci_slot_name,
+		       gt_freq);
 
 	printf("\033[7m%s%*s\033[0m\n",
 	       desc,
 	       (int)(w - len), " ");
 	lines++;
 	free(desc);
+	free(gt_freq);
 	return lines;
 }
 
diff --git a/tools/gputop/xe_gputop.h b/tools/gputop/xe_gputop.h
index 1e3856071..baea232fc 100644
--- a/tools/gputop/xe_gputop.h
+++ b/tools/gputop/xe_gputop.h
@@ -39,8 +39,11 @@ 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 *gt_act_freq;
+	struct xe_pmu_counter *gt_req_freq;
 	struct xe_engine engine;
 };
 
-- 
2.34.1



More information about the igt-dev mailing list