Intel-GFX Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH i-g-t 0/2] Add PMU tests for GT frequency
@ 2025-04-02  1:39 Vinay Belgaumkar
  2025-04-02  1:39 ` [PATCH i-g-t 1/2] lib/xe_gt: Move get/set GT freq utils to lib Vinay Belgaumkar
  2025-04-02  1:39 ` [PATCH i-g-t 2/2] tests/xe_pmu: Add frequency test Vinay Belgaumkar
  0 siblings, 2 replies; 14+ messages in thread
From: Vinay Belgaumkar @ 2025-04-02  1:39 UTC (permalink / raw)
  To: intel-gfx, igt-dev; +Cc: Vinay Belgaumkar

Also move some frequency helpers to lib.

Signed-off-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com>

Vinay Belgaumkar (2):
  lib/xe_gt: Move get/set GT freq utils to lib
  tests/xe_pmu: Add frequency test

 lib/xe/xe_gt.c           |  59 ++++++++++++++
 lib/xe/xe_gt.h           |   2 +
 tests/intel/xe_gt_freq.c | 164 +++++++++++++++------------------------
 tests/intel/xe_pmu.c     |  93 ++++++++++++++++++++++
 4 files changed, 218 insertions(+), 100 deletions(-)

-- 
2.38.1


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH i-g-t 1/2] lib/xe_gt: Move get/set GT freq utils to lib
  2025-04-02  1:39 [PATCH i-g-t 0/2] Add PMU tests for GT frequency Vinay Belgaumkar
@ 2025-04-02  1:39 ` Vinay Belgaumkar
  2025-04-03 10:50   ` Riana Tauro
  2025-04-02  1:39 ` [PATCH i-g-t 2/2] tests/xe_pmu: Add frequency test Vinay Belgaumkar
  1 sibling, 1 reply; 14+ messages in thread
From: Vinay Belgaumkar @ 2025-04-02  1:39 UTC (permalink / raw)
  To: intel-gfx, igt-dev; +Cc: Vinay Belgaumkar

These can be used from other tests as well.

Signed-off-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
---
 lib/xe/xe_gt.c           |  59 ++++++++++++++
 lib/xe/xe_gt.h           |   2 +
 tests/intel/xe_gt_freq.c | 164 +++++++++++++++------------------------
 3 files changed, 125 insertions(+), 100 deletions(-)

diff --git a/lib/xe/xe_gt.c b/lib/xe/xe_gt.c
index 6f1475be0..2fafd6ffd 100644
--- a/lib/xe/xe_gt.c
+++ b/lib/xe/xe_gt.c
@@ -4,6 +4,7 @@
  */
 
 #include <fcntl.h>
+#include <limits.h>
 #include <sys/stat.h>
 
 #include "igt_core.h"
@@ -241,3 +242,61 @@ int xe_gt_count_engines_by_class(int fd, int gt, int class)
 
 	return n;
 }
+
+/**
+ * xe_gt_set_freq:
+ * @fd: pointer to xe drm fd
+ * @gt_id: GT id
+ * @freq_name: which GT freq(min, max) to change
+ * @freq: value of freq to set
+ *
+ * Set GT min/max frequency
+ *
+ * Return: success or failure
+ */
+int xe_gt_set_freq(int fd, int gt_id, const char *freq_name, uint32_t freq)
+{
+	int ret = -EAGAIN;
+	char freq_attr[NAME_MAX];
+	int gt_fd;
+
+	snprintf(freq_attr, sizeof(freq_attr), "freq0/%s_freq", freq_name);
+	gt_fd = xe_sysfs_gt_open(fd, gt_id);
+	igt_assert_lte(0, gt_fd);
+
+	while (ret == -EAGAIN)
+		ret = igt_sysfs_printf(gt_fd, freq_attr, "%u", freq);
+
+	close(gt_fd);
+	return ret;
+}
+
+/**
+ * xe_gt_get_freq:
+ * @fd: pointer to xe drm fd
+ * @gt_id: GT id
+ * @freq_name: which GT freq(min, max, act, cur) to read
+ *
+ * Read the min/max/act/cur GT frequency
+ *
+ * Return: GT frequency value
+ */
+uint32_t xe_gt_get_freq(int fd, int gt_id, const char *freq_name)
+{
+	uint32_t freq;
+	int err = -EAGAIN;
+	char freq_attr[NAME_MAX];
+	int gt_fd;
+
+	snprintf(freq_attr, sizeof(freq_attr), "freq0/%s_freq", freq_name);
+	gt_fd = xe_sysfs_gt_open(fd, gt_id);
+	igt_assert_lte(0, gt_fd);
+
+	while (err == -EAGAIN)
+		err = igt_sysfs_scanf(gt_fd, freq_attr, "%u", &freq);
+
+	igt_debug("gt%d: %s freq %u\n", gt_id, freq_name, freq);
+
+	close(gt_fd);
+	return freq;
+}
diff --git a/lib/xe/xe_gt.h b/lib/xe/xe_gt.h
index 511b31149..06a59281c 100644
--- a/lib/xe/xe_gt.h
+++ b/lib/xe/xe_gt.h
@@ -23,4 +23,6 @@ int xe_gt_fill_engines_by_class(int fd, int gt, int class,
 				struct drm_xe_engine_class_instance eci[static XE_MAX_ENGINE_INSTANCE]);
 int xe_gt_count_engines_by_class(int fd, int gt, int class);
 
+int xe_gt_set_freq(int fd, int gt_id, const char *freq_name, uint32_t freq);
+uint32_t xe_gt_get_freq(int fd, int gt_id, const char *freq_name);
 #endif
diff --git a/tests/intel/xe_gt_freq.c b/tests/intel/xe_gt_freq.c
index 843144ad2..4adb205c9 100644
--- a/tests/intel/xe_gt_freq.c
+++ b/tests/intel/xe_gt_freq.c
@@ -14,6 +14,7 @@
 
 #include "igt.h"
 #include "lib/igt_syncobj.h"
+#include "lib/xe/xe_gt.h"
 #include "igt_sysfs.h"
 
 #include "xe_drm.h"
@@ -36,43 +37,6 @@
  */
 #define SLPC_FREQ_LATENCY_US 100000
 
-static int set_freq(int fd, int gt_id, const char *freq_name, uint32_t freq)
-{
-	int ret = -EAGAIN;
-	char freq_attr[22];
-	int gt_fd;
-
-	snprintf(freq_attr, sizeof(freq_attr), "freq0/%s_freq", freq_name);
-	gt_fd = xe_sysfs_gt_open(fd, gt_id);
-	igt_assert_lte(0, gt_fd);
-
-	while (ret == -EAGAIN)
-		ret = igt_sysfs_printf(gt_fd, freq_attr, "%u", freq);
-
-	close(gt_fd);
-	return ret;
-}
-
-static uint32_t get_freq(int fd, int gt_id, const char *freq_name)
-{
-	uint32_t freq;
-	int err = -EAGAIN;
-	char freq_attr[22];
-	int gt_fd;
-
-	snprintf(freq_attr, sizeof(freq_attr), "freq0/%s_freq", freq_name);
-	gt_fd = xe_sysfs_gt_open(fd, gt_id);
-	igt_assert_lte(0, gt_fd);
-
-	while (err == -EAGAIN)
-		err = igt_sysfs_scanf(gt_fd, freq_attr, "%u", &freq);
-
-	igt_debug("gt%d: %s freq %u\n", gt_id, freq_name, freq);
-
-	close(gt_fd);
-	return freq;
-}
-
 static bool within_expected_range(uint32_t freq, uint32_t val)
 {
 	/*
@@ -134,8 +98,8 @@ static void test_throttle_basic_api(int fd, int gt_id)
 
 static void test_freq_basic_api(int fd, int gt_id)
 {
-	uint32_t rpn = get_freq(fd, gt_id, "rpn");
-	uint32_t rp0 = get_freq(fd, gt_id, "rp0");
+	uint32_t rpn = xe_gt_get_freq(fd, gt_id, "rpn");
+	uint32_t rp0 = xe_gt_get_freq(fd, gt_id, "rp0");
 	uint32_t rpmid = (rp0 + rpn) / 2;
 	uint32_t min_freq, max_freq;
 
@@ -144,29 +108,29 @@ static void test_freq_basic_api(int fd, int gt_id)
 	 * RPn is the floor
 	 * RP0 is the ceiling
 	 */
-	igt_assert_lt(set_freq(fd, gt_id, "min", rpn - 1), 0);
-	igt_assert_lt(set_freq(fd, gt_id, "min", rp0 + 1), 0);
-	igt_assert_lt(set_freq(fd, gt_id, "max", rpn - 1), 0);
-	igt_assert_lt(set_freq(fd, gt_id, "max", rp0 + 1), 0);
+	igt_assert_lt(xe_gt_set_freq(fd, gt_id, "min", rpn - 1), 0);
+	igt_assert_lt(xe_gt_set_freq(fd, gt_id, "min", rp0 + 1), 0);
+	igt_assert_lt(xe_gt_set_freq(fd, gt_id, "max", rpn - 1), 0);
+	igt_assert_lt(xe_gt_set_freq(fd, gt_id, "max", rp0 + 1), 0);
 
 	/* Assert min requests are respected from rp0 to rpn */
-	igt_assert_lt(0, set_freq(fd, gt_id, "min", rp0));
-	igt_assert_eq_u32(get_freq(fd, gt_id, "min"), rp0);
-	igt_assert_lt(0, set_freq(fd, gt_id, "min", rpmid));
-	min_freq = get_freq(fd, gt_id, "min");
+	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "min", rp0));
+	igt_assert_eq_u32(xe_gt_get_freq(fd, gt_id, "min"), rp0);
+	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "min", rpmid));
+	min_freq = xe_gt_get_freq(fd, gt_id, "min");
 	/* SLPC can set min higher than rpmid - as it follows RPe */
 	igt_assert_lte_u32((rpmid - FREQ_UNIT_MHZ), min_freq);
-	igt_assert_lt(0, set_freq(fd, gt_id, "min", rpn));
-	igt_assert_eq_u32(get_freq(fd, gt_id, "min"), rpn);
+	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "min", rpn));
+	igt_assert_eq_u32(xe_gt_get_freq(fd, gt_id, "min"), rpn);
 
 	/* Assert max requests are respected from rpn to rp0 */
-	igt_assert_lt(0, set_freq(fd, gt_id, "max", rpn));
-	igt_assert_eq_u32(get_freq(fd, gt_id, "max"), rpn);
-	igt_assert_lt(0, set_freq(fd, gt_id, "max", rpmid));
-	max_freq = get_freq(fd, gt_id, "max");
+	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "max", rpn));
+	igt_assert_eq_u32(xe_gt_get_freq(fd, gt_id, "max"), rpn);
+	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "max", rpmid));
+	max_freq = xe_gt_get_freq(fd, gt_id, "max");
 	igt_assert(within_expected_range(max_freq, rpmid));
-	igt_assert_lt(0, set_freq(fd, gt_id, "max", rp0));
-	igt_assert_eq_u32(get_freq(fd, gt_id, "max"), rp0);
+	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "max", rp0));
+	igt_assert_eq_u32(xe_gt_get_freq(fd, gt_id, "max"), rp0);
 }
 
 /**
@@ -179,8 +143,8 @@ static void test_freq_basic_api(int fd, int gt_id)
 
 static void test_freq_fixed(int fd, int gt_id, bool gt_idle)
 {
-	uint32_t rpn = get_freq(fd, gt_id, "rpn");
-	uint32_t rp0 = get_freq(fd, gt_id, "rp0");
+	uint32_t rpn = xe_gt_get_freq(fd, gt_id, "rpn");
+	uint32_t rp0 = xe_gt_get_freq(fd, gt_id, "rp0");
 	uint32_t rpmid = (rp0 + rpn) / 2;
 	uint32_t cur_freq, act_freq;
 
@@ -192,50 +156,50 @@ static void test_freq_fixed(int fd, int gt_id, bool gt_idle)
 	 * And let's do this for all the 2 known Render Performance (RP) values
 	 * RP0 and RPn and something in between.
 	 */
-	igt_assert_lt(0, set_freq(fd, gt_id, "min", rpn));
-	igt_assert_lt(0, set_freq(fd, gt_id, "max", rpn));
+	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "min", rpn));
+	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "max", rpn));
 	usleep(SLPC_FREQ_LATENCY_US);
-	igt_assert_eq_u32(get_freq(fd, gt_id, "cur"), rpn);
+	igt_assert_eq_u32(xe_gt_get_freq(fd, gt_id, "cur"), rpn);
 
 	if (gt_idle) {
-		/* Wait for GT to go in C6 as previous get_freq wakes up GT*/
+		/* Wait for GT to go in C6 as previous xe_gt_get_freq wakes up GT*/
 		igt_assert_f(igt_wait(xe_gt_is_in_c6(fd, gt_id), 1000, 10),
 			     "GT %d should be in C6\n", gt_id);
-		igt_assert(get_freq(fd, gt_id, "act") == 0);
+		igt_assert(xe_gt_get_freq(fd, gt_id, "act") == 0);
 	} else {
-		igt_assert_eq_u32(get_freq(fd, gt_id, "act"), rpn);
+		igt_assert_eq_u32(xe_gt_get_freq(fd, gt_id, "act"), rpn);
 	}
 
-	igt_assert_lt(0, set_freq(fd, gt_id, "min", rpmid));
-	igt_assert_lt(0, set_freq(fd, gt_id, "max", rpmid));
+	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "min", rpmid));
+	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "max", rpmid));
 	usleep(SLPC_FREQ_LATENCY_US);
-	cur_freq = get_freq(fd, gt_id, "cur");
+	cur_freq = xe_gt_get_freq(fd, gt_id, "cur");
 	/* If rpmid is around RPe, we could see SLPC follow it */
 	igt_assert_lte_u32((rpmid - FREQ_UNIT_MHZ), cur_freq);
 
 	if (gt_idle) {
 		igt_assert_f(igt_wait(xe_gt_is_in_c6(fd, gt_id), 1000, 10),
 			     "GT %d should be in C6\n", gt_id);
-		igt_assert(get_freq(fd, gt_id, "act") == 0);
+		igt_assert(xe_gt_get_freq(fd, gt_id, "act") == 0);
 	} else {
-		act_freq = get_freq(fd, gt_id, "act");
+		act_freq = xe_gt_get_freq(fd, gt_id, "act");
 		igt_assert_lte_u32(act_freq, cur_freq + FREQ_UNIT_MHZ);
 	}
 
-	igt_assert_lt(0, set_freq(fd, gt_id, "min", rp0));
-	igt_assert_lt(0, set_freq(fd, gt_id, "max", rp0));
+	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "min", rp0));
+	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "max", rp0));
 	usleep(SLPC_FREQ_LATENCY_US);
 	/*
 	 * It is unlikely that PCODE will *always* respect any request above RPe
 	 * So for this level let's only check if GuC PC is doing its job
 	 * and respecting our request, by propagating it to the hardware.
 	 */
-	igt_assert_eq_u32(get_freq(fd, gt_id, "cur"), rp0);
+	igt_assert_eq_u32(xe_gt_get_freq(fd, gt_id, "cur"), rp0);
 
 	if (gt_idle) {
 		igt_assert_f(igt_wait(xe_gt_is_in_c6(fd, gt_id), 1000, 10),
 			     "GT %d should be in C6\n", gt_id);
-		igt_assert(get_freq(fd, gt_id, "act") == 0);
+		igt_assert(xe_gt_get_freq(fd, gt_id, "act") == 0);
 	}
 
 	igt_debug("Finished testing fixed request\n");
@@ -250,25 +214,25 @@ static void test_freq_fixed(int fd, int gt_id, bool gt_idle)
  */
 static void test_freq_range(int fd, int gt_id, bool gt_idle)
 {
-	uint32_t rpn = get_freq(fd, gt_id, "rpn");
-	uint32_t rp0 = get_freq(fd, gt_id, "rp0");
+	uint32_t rpn = xe_gt_get_freq(fd, gt_id, "rpn");
+	uint32_t rp0 = xe_gt_get_freq(fd, gt_id, "rp0");
 	uint32_t rpmid = (rp0 + rpn) / 2;
 	uint32_t cur, act;
 
 	igt_debug("Starting testing range request\n");
 
-	igt_assert_lt(0, set_freq(fd, gt_id, "min", rpn));
-	igt_assert_lt(0, set_freq(fd, gt_id, "max", rpmid));
+	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "min", rpn));
+	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "max", rpmid));
 	usleep(SLPC_FREQ_LATENCY_US);
-	cur = get_freq(fd, gt_id, "cur");
+	cur = xe_gt_get_freq(fd, gt_id, "cur");
 	igt_assert(rpn <= cur && cur <= rpmid + FREQ_UNIT_MHZ);
 
 	if (gt_idle) {
 		igt_assert_f(igt_wait(xe_gt_is_in_c6(fd, gt_id), 1000, 10),
 			     "GT %d should be in C6\n", gt_id);
-		igt_assert(get_freq(fd, gt_id, "act") == 0);
+		igt_assert(xe_gt_get_freq(fd, gt_id, "act") == 0);
 	} else {
-		act = get_freq(fd, gt_id, "act");
+		act = xe_gt_get_freq(fd, gt_id, "act");
 		igt_assert((rpn <= act) && (act <= cur + FREQ_UNIT_MHZ));
 	}
 
@@ -282,21 +246,21 @@ static void test_freq_range(int fd, int gt_id, bool gt_idle)
 
 static void test_freq_low_max(int fd, int gt_id)
 {
-	uint32_t rpn = get_freq(fd, gt_id, "rpn");
-	uint32_t rp0 = get_freq(fd, gt_id, "rp0");
+	uint32_t rpn = xe_gt_get_freq(fd, gt_id, "rpn");
+	uint32_t rp0 = xe_gt_get_freq(fd, gt_id, "rp0");
 	uint32_t rpmid = (rp0 + rpn) / 2;
 
 	/*
 	 *  When max request < min request, max is ignored and min works like
 	 * a fixed one. Let's assert this assumption
 	 */
-	igt_assert_lt(0, set_freq(fd, gt_id, "min", rpmid));
-	igt_assert_lt(0, set_freq(fd, gt_id, "max", rpn));
+	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "min", rpmid));
+	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "max", rpn));
 	usleep(SLPC_FREQ_LATENCY_US);
 
 	/* Cur freq will follow RPe, which could be higher than min freq */
 	igt_assert_lte_u32((rpmid - FREQ_UNIT_MHZ),
-			   get_freq(fd, gt_id, "cur"));
+			   xe_gt_get_freq(fd, gt_id, "cur"));
 }
 
 /**
@@ -306,18 +270,18 @@ static void test_freq_low_max(int fd, int gt_id)
 
 static void test_suspend(int fd, int gt_id)
 {
-	uint32_t rpn = get_freq(fd, gt_id, "rpn");
+	uint32_t rpn = xe_gt_get_freq(fd, gt_id, "rpn");
 
-	igt_assert_lt(0, set_freq(fd, gt_id, "min", rpn));
-	igt_assert_lt(0, set_freq(fd, gt_id, "max", rpn));
+	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "min", rpn));
+	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "max", rpn));
 	usleep(SLPC_FREQ_LATENCY_US);
-	igt_assert_eq_u32(get_freq(fd, gt_id, "cur"), rpn);
+	igt_assert_eq_u32(xe_gt_get_freq(fd, gt_id, "cur"), rpn);
 
 	igt_system_suspend_autoresume(SUSPEND_STATE_S3,
 				      SUSPEND_TEST_NONE);
 
-	igt_assert_eq_u32(get_freq(fd, gt_id, "min"), rpn);
-	igt_assert_eq_u32(get_freq(fd, gt_id, "max"), rpn);
+	igt_assert_eq_u32(xe_gt_get_freq(fd, gt_id, "min"), rpn);
+	igt_assert_eq_u32(xe_gt_get_freq(fd, gt_id, "max"), rpn);
 }
 
 /**
@@ -330,24 +294,24 @@ static void test_suspend(int fd, int gt_id)
 
 static void test_reset(int fd, int gt_id, int cycles)
 {
-	uint32_t rpn = get_freq(fd, gt_id, "rpn");
+	uint32_t rpn = xe_gt_get_freq(fd, gt_id, "rpn");
 
 	for (int i = 0; i < cycles; i++) {
-		igt_assert_f(set_freq(fd, gt_id, "min", rpn) > 0,
+		igt_assert_f(xe_gt_set_freq(fd, gt_id, "min", rpn) > 0,
 			     "Failed after %d good cycles\n", i);
-		igt_assert_f(set_freq(fd, gt_id, "max", rpn) > 0,
+		igt_assert_f(xe_gt_set_freq(fd, gt_id, "max", rpn) > 0,
 			     "Failed after %d good cycles\n", i);
 		usleep(SLPC_FREQ_LATENCY_US);
-		igt_assert_f(get_freq(fd, gt_id, "cur") == rpn,
+		igt_assert_f(xe_gt_get_freq(fd, gt_id, "cur") == rpn,
 			     "Failed after %d good cycles\n", i);
 
 		xe_force_gt_reset_sync(fd, gt_id);
 
 		usleep(SLPC_FREQ_LATENCY_US);
 
-		igt_assert_f(get_freq(fd, gt_id, "min") == rpn,
+		igt_assert_f(xe_gt_get_freq(fd, gt_id, "min") == rpn,
 			     "Failed after %d good cycles\n", i);
-		igt_assert_f(get_freq(fd, gt_id, "max") == rpn,
+		igt_assert_f(xe_gt_get_freq(fd, gt_id, "max") == rpn,
 			     "Failed after %d good cycles\n", i);
 	}
 }
@@ -448,8 +412,8 @@ igt_main
 		stash_max = (uint32_t *) malloc(sizeof(uint32_t) * num_gts);
 
 		xe_for_each_gt(fd, gt) {
-			stash_min[gt] = get_freq(fd, gt, "min");
-			stash_max[gt] = get_freq(fd, gt, "max");
+			stash_min[gt] = xe_gt_get_freq(fd, gt, "min");
+			stash_max[gt] = xe_gt_get_freq(fd, gt, "max");
 		}
 	}
 
@@ -525,8 +489,8 @@ igt_main
 
 	igt_fixture {
 		xe_for_each_gt(fd, gt) {
-			set_freq(fd, gt, "max", stash_max[gt]);
-			set_freq(fd, gt, "min", stash_min[gt]);
+			xe_gt_set_freq(fd, gt, "max", stash_max[gt]);
+			xe_gt_set_freq(fd, gt, "min", stash_min[gt]);
 		}
 		free(stash_min);
 		free(stash_max);
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH i-g-t 2/2] tests/xe_pmu: Add frequency test
  2025-04-02  1:39 [PATCH i-g-t 0/2] Add PMU tests for GT frequency Vinay Belgaumkar
  2025-04-02  1:39 ` [PATCH i-g-t 1/2] lib/xe_gt: Move get/set GT freq utils to lib Vinay Belgaumkar
@ 2025-04-02  1:39 ` Vinay Belgaumkar
  2025-04-03 10:39   ` Riana Tauro
  1 sibling, 1 reply; 14+ messages in thread
From: Vinay Belgaumkar @ 2025-04-02  1:39 UTC (permalink / raw)
  To: intel-gfx, igt-dev; +Cc: Vinay Belgaumkar, Lucas De Marchi, Rodrigo Vivi

Add a basic test that uses PMU to read GT actual and requested
frequencies while running a workload.

Cc: Lucas De Marchi <lucas.demarchi@intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
---
 tests/intel/xe_pmu.c | 93 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 93 insertions(+)

diff --git a/tests/intel/xe_pmu.c b/tests/intel/xe_pmu.c
index 66edf24ad..43085b4d0 100644
--- a/tests/intel/xe_pmu.c
+++ b/tests/intel/xe_pmu.c
@@ -226,6 +226,95 @@ static void test_gt_c6_idle(int xe, unsigned int gt)
 	close(pmu_fd);
 }
 
+/**
+ * SUBTEST: gt-frequency
+ * Description: Validate we can collect accurate frequency PMU stats
+ *		while running a workload.
+ */
+static void test_gt_frequency(int fd, struct drm_xe_engine_class_instance *eci)
+{
+	struct xe_cork *cork = NULL;
+	uint64_t end[2], start[2];
+	unsigned long config_rq_freq, config_act_freq;
+	double min[2], max[2];
+	uint32_t gt = eci->gt_id;
+	uint32_t orig_min = xe_gt_get_freq(fd, eci->gt_id, "min");
+	uint32_t orig_max = xe_gt_get_freq(fd, eci->gt_id, "max");
+	uint32_t vm;
+	int pmu_fd[2];
+
+	config_rq_freq = get_event_config(fd, gt, NULL, "gt-requested-frequency");
+	pmu_fd[0] = open_group(fd, config_rq_freq, -1);
+
+	config_act_freq = get_event_config(fd, gt, NULL, "gt-actual-frequency");
+	pmu_fd[1] = open_group(fd, config_act_freq, pmu_fd[0]);
+
+	vm = xe_vm_create(fd, 0, 0);
+
+	cork = xe_cork_create_opts(fd, eci, vm, 1, 1);
+	xe_cork_sync_start(fd, cork);
+
+	/*
+	 * Set GPU to min frequency and read PMU counters.
+	 */
+	igt_assert(xe_gt_set_freq(fd, gt, "max", orig_min) > 0);
+	igt_assert(xe_gt_get_freq(fd, gt, "max") == orig_min);
+
+	pmu_read_multi(pmu_fd[0], 2, start);
+	usleep(SLEEP_DURATION * USEC_PER_SEC);
+	pmu_read_multi(pmu_fd[0], 2, end);
+
+	min[0] = (end[0] - start[0]);
+	min[1] = (end[1] - start[1]);
+
+	/*
+	 * Set GPU to max frequency and read PMU counters.
+	 */
+	igt_assert(xe_gt_set_freq(fd, gt, "max", orig_max) > 0);
+	igt_assert(xe_gt_get_freq(fd, gt, "max") == orig_max);
+	igt_assert(xe_gt_set_freq(fd, gt, "min", orig_max) > 0);
+	igt_assert(xe_gt_get_freq(fd, gt, "min") == orig_max);
+
+	pmu_read_multi(pmu_fd[0], 2, start);
+	usleep(SLEEP_DURATION * USEC_PER_SEC);
+	pmu_read_multi(pmu_fd[0], 2, end);
+
+	max[0] = (end[0] - start[0]);
+	max[1] = (end[1] - start[1]);
+
+	if (!cork->ended)
+		xe_cork_sync_end(fd, cork);
+
+	/*
+	 * Restore min/max.
+	 */
+	igt_assert(xe_gt_set_freq(fd, gt, "min", orig_min) > 0);
+	igt_assert(xe_gt_get_freq(fd, gt, "min") == orig_min);
+
+	igt_info("Minimum frequency: requested %.1f, actual %.1f\n",
+		 min[0], min[1]);
+	igt_info("Maximum frequency: requested %.1f, actual %.1f\n",
+		 max[0], max[1]);
+
+	close(pmu_fd[0]);
+	close(pmu_fd[1]);
+
+	if (cork)
+		xe_cork_destroy(fd, cork);
+
+	xe_vm_destroy(fd, vm);
+
+	close(pmu_fd[0]);
+	close(pmu_fd[1]);
+
+	assert_within_epsilon(min[0], orig_min, tolerance);
+	/*
+	 * On thermally throttled devices we cannot be sure maximum frequency
+	 * can be reached so use larger tolerance downwards.
+	 */
+	assert_within_epsilon_up_down(max[0], orig_max, tolerance, 0.15f);
+}
+
 igt_main
 {
 	int fd, gt;
@@ -254,6 +343,10 @@ igt_main
 	test_each_engine("engine-activity-load", fd, eci)
 		engine_activity(fd, eci, TEST_LOAD);
 
+	igt_describe("Validate PMU GT freq measured is within the tolerance");
+	test_each_engine("gt-frequency", fd, eci)
+		test_gt_frequency(fd, eci);
+
 	igt_fixture {
 		close(fd);
 	}
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH i-g-t 2/2] tests/xe_pmu: Add frequency test
  2025-04-02  1:39 ` [PATCH i-g-t 2/2] tests/xe_pmu: Add frequency test Vinay Belgaumkar
@ 2025-04-03 10:39   ` Riana Tauro
  0 siblings, 0 replies; 14+ messages in thread
From: Riana Tauro @ 2025-04-03 10:39 UTC (permalink / raw)
  To: Vinay Belgaumkar, intel-gfx, igt-dev; +Cc: Lucas De Marchi, Rodrigo Vivi

Hi Vinay

VF igt patches were merged so this will need a rebase

On 4/2/2025 7:09 AM, Vinay Belgaumkar wrote:
> Add a basic test that uses PMU to read GT actual and requested
> frequencies while running a workload.
> 
> Cc: Lucas De Marchi <lucas.demarchi@intel.com>
> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> Signed-off-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
> ---
>   tests/intel/xe_pmu.c | 93 ++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 93 insertions(+)
> 
> diff --git a/tests/intel/xe_pmu.c b/tests/intel/xe_pmu.c
> index 66edf24ad..43085b4d0 100644
> --- a/tests/intel/xe_pmu.c
> +++ b/tests/intel/xe_pmu.c
> @@ -226,6 +226,95 @@ static void test_gt_c6_idle(int xe, unsigned int gt)
>   	close(pmu_fd);
>   }
>   
> +/**
> + * SUBTEST: gt-frequency
> + * Description: Validate we can collect accurate frequency PMU stats
> + *		while running a workload.
> + */
> +static void test_gt_frequency(int fd, struct drm_xe_engine_class_instance *eci)
> +{
> +	struct xe_cork *cork = NULL;
> +	uint64_t end[2], start[2];
> +	unsigned long config_rq_freq, config_act_freq;
> +	double min[2], max[2];
> +	uint32_t gt = eci->gt_id;
> +	uint32_t orig_min = xe_gt_get_freq(fd, eci->gt_id, "min");
> +	uint32_t orig_max = xe_gt_get_freq(fd, eci->gt_id, "max");
> +	uint32_t vm;
> +	int pmu_fd[2];
> +
> +	config_rq_freq = get_event_config(fd, gt, NULL, "gt-requested-frequency");
> +	pmu_fd[0] = open_group(fd, config_rq_freq, -1);
> +
> +	config_act_freq = get_event_config(fd, gt, NULL, "gt-actual-frequency");
> +	pmu_fd[1] = open_group(fd, config_act_freq, pmu_fd[0]);
> +
> +	vm = xe_vm_create(fd, 0, 0);
> +
> +	cork = xe_cork_create_opts(fd, eci, vm, 1, 1);
> +	xe_cork_sync_start(fd, cork);
> +
> +	/*
> +	 * Set GPU to min frequency and read PMU counters.
> +	 */
> +	igt_assert(xe_gt_set_freq(fd, gt, "max", orig_min) > 0);
> +	igt_assert(xe_gt_get_freq(fd, gt, "max") == orig_min);
> +
> +	pmu_read_multi(pmu_fd[0], 2, start);
> +	usleep(SLEEP_DURATION * USEC_PER_SEC);
> +	pmu_read_multi(pmu_fd[0], 2, end);
> +
> +	min[0] = (end[0] - start[0]);
> +	min[1] = (end[1] - start[1]);
> +
> +	/*
> +	 * Set GPU to max frequency and read PMU counters.
> +	 */
> +	igt_assert(xe_gt_set_freq(fd, gt, "max", orig_max) > 0);
> +	igt_assert(xe_gt_get_freq(fd, gt, "max") == orig_max);
> +	igt_assert(xe_gt_set_freq(fd, gt, "min", orig_max) > 0);
> +	igt_assert(xe_gt_get_freq(fd, gt, "min") == orig_max);
Should a exit handler be added to restore frequencies in case of assert 
failure?> +
> +	pmu_read_multi(pmu_fd[0], 2, start);
> +	usleep(SLEEP_DURATION * USEC_PER_SEC);
> +	pmu_read_multi(pmu_fd[0], 2, end);
> +
> +	max[0] = (end[0] - start[0]);
> +	max[1] = (end[1] - start[1]);
> +
> +	if (!cork->ended)This can be removed. The engine activity had a trailing idle case which
ended the cork before. The lib already has this check> +	 
xe_cork_sync_end(fd, cork);
> +
> +	/*
> +	 * Restore min/max.
> +	 */
> +	igt_assert(xe_gt_set_freq(fd, gt, "min", orig_min) > 0);
> +	igt_assert(xe_gt_get_freq(fd, gt, "min") == orig_min);
> +
> +	igt_info("Minimum frequency: requested %.1f, actual %.1f\n",
> +		 min[0], min[1]);
> +	igt_info("Maximum frequency: requested %.1f, actual %.1f\n",
> +		 max[0], max[1]);
> +
> +	close(pmu_fd[0]);
> +	close(pmu_fd[1]);
> +
> +	if (cork)
> +		xe_cork_destroy(fd, cork);
> +
> +	xe_vm_destroy(fd, vm);
> +
> +	close(pmu_fd[0]);
> +	close(pmu_fd[1]);
> +
> +	assert_within_epsilon(min[0], orig_min, tolerance);
> +	/*
> +	 * On thermally throttled devices we cannot be sure maximum frequency
> +	 * can be reached so use larger tolerance downwards.
> +	 */
> +	assert_within_epsilon_up_down(max[0], orig_max, tolerance, 0.15f);
> +}
> +
>   igt_main
>   {
>   	int fd, gt;
> @@ -254,6 +343,10 @@ igt_main
>   	test_each_engine("engine-activity-load", fd, eci)
>   		engine_activity(fd, eci, TEST_LOAD);
>   
> +	igt_describe("Validate PMU GT freq measured is within the tolerance");Can't we have this per-gt instead of engine?

Thanks
Riana> +	test_each_engine("gt-frequency", fd, eci)
> +		test_gt_frequency(fd, eci);
> +
>   	igt_fixture {
>   		close(fd);
>   	}


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH i-g-t 1/2] lib/xe_gt: Move get/set GT freq utils to lib
  2025-04-02  1:39 ` [PATCH i-g-t 1/2] lib/xe_gt: Move get/set GT freq utils to lib Vinay Belgaumkar
@ 2025-04-03 10:50   ` Riana Tauro
  0 siblings, 0 replies; 14+ messages in thread
From: Riana Tauro @ 2025-04-03 10:50 UTC (permalink / raw)
  To: Vinay Belgaumkar, intel-gfx, igt-dev

Hi Vinay

On 4/2/2025 7:09 AM, Vinay Belgaumkar wrote:
> These can be used from other tests as well.
Could you add more description to the commit message>
> Signed-off-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
> ---
>   lib/xe/xe_gt.c           |  59 ++++++++++++++
>   lib/xe/xe_gt.h           |   2 +
>   tests/intel/xe_gt_freq.c | 164 +++++++++++++++------------------------
>   3 files changed, 125 insertions(+), 100 deletions(-)
> 
> diff --git a/lib/xe/xe_gt.c b/lib/xe/xe_gt.c
> index 6f1475be0..2fafd6ffd 100644
> --- a/lib/xe/xe_gt.c
> +++ b/lib/xe/xe_gt.c
> @@ -4,6 +4,7 @@
>    */
>   
>   #include <fcntl.h>
> +#include <limits.h>
>   #include <sys/stat.h>
>   
>   #include "igt_core.h"
> @@ -241,3 +242,61 @@ int xe_gt_count_engines_by_class(int fd, int gt, int class)
>   
>   	return n;
>   }
> +
> +/**
> + * xe_gt_set_freq:
> + * @fd: pointer to xe drm fd
> + * @gt_id: GT id
> + * @freq_name: which GT freq(min, max) to change
> + * @freq: value of freq to set
> + *
> + * Set GT min/max frequency
> + *
> + * Return: success or failure
> + */
> +int xe_gt_set_freq(int fd, int gt_id, const char *freq_name, uint32_t freq)
> +{
> +	int ret = -EAGAIN;
> +	char freq_attr[NAME_MAX];
> +	int gt_fd;
> +
> +	snprintf(freq_attr, sizeof(freq_attr), "freq0/%s_freq", freq_name);
> +	gt_fd = xe_sysfs_gt_open(fd, gt_id);
> +	igt_assert_lte(0, gt_fd);
> +
> +	while (ret == -EAGAIN)
> +		ret = igt_sysfs_printf(gt_fd, freq_attr, "%u", freq);
> +
> +	close(gt_fd);
> +	return ret;
> +}
> +
> +/**
> + * xe_gt_get_freq:
> + * @fd: pointer to xe drm fd
> + * @gt_id: GT id
> + * @freq_name: which GT freq(min, max, act, cur) to read
> + *
> + * Read the min/max/act/cur GT frequency
rp0/rpn/rpe

enum that matches the string would be better in case
some other test sends a wrong name, but upto you

With addition of the missing names and descriptive commit message
Reviewed-by: Riana Tauro <riana.tauro@intel.com>> + *
> + * Return: GT frequency value
> + */
> +uint32_t xe_gt_get_freq(int fd, int gt_id, const char *freq_name)
> +{
> +	uint32_t freq;
> +	int err = -EAGAIN;
> +	char freq_attr[NAME_MAX];
> +	int gt_fd;
> +
> +	snprintf(freq_attr, sizeof(freq_attr), "freq0/%s_freq", freq_name);
> +	gt_fd = xe_sysfs_gt_open(fd, gt_id);
> +	igt_assert_lte(0, gt_fd);
> +
> +	while (err == -EAGAIN)
> +		err = igt_sysfs_scanf(gt_fd, freq_attr, "%u", &freq);
> +
> +	igt_debug("gt%d: %s freq %u\n", gt_id, freq_name, freq);
> +
> +	close(gt_fd);
> +	return freq;
> +}
> diff --git a/lib/xe/xe_gt.h b/lib/xe/xe_gt.h
> index 511b31149..06a59281c 100644
> --- a/lib/xe/xe_gt.h
> +++ b/lib/xe/xe_gt.h
> @@ -23,4 +23,6 @@ int xe_gt_fill_engines_by_class(int fd, int gt, int class,
>   				struct drm_xe_engine_class_instance eci[static XE_MAX_ENGINE_INSTANCE]);
>   int xe_gt_count_engines_by_class(int fd, int gt, int class);
>   
> +int xe_gt_set_freq(int fd, int gt_id, const char *freq_name, uint32_t freq);
> +uint32_t xe_gt_get_freq(int fd, int gt_id, const char *freq_name);
>   #endif
> diff --git a/tests/intel/xe_gt_freq.c b/tests/intel/xe_gt_freq.c
> index 843144ad2..4adb205c9 100644
> --- a/tests/intel/xe_gt_freq.c
> +++ b/tests/intel/xe_gt_freq.c
> @@ -14,6 +14,7 @@
>   
>   #include "igt.h"
>   #include "lib/igt_syncobj.h"
> +#include "lib/xe/xe_gt.h"
>   #include "igt_sysfs.h"
>   
>   #include "xe_drm.h"
> @@ -36,43 +37,6 @@
>    */
>   #define SLPC_FREQ_LATENCY_US 100000
>   
> -static int set_freq(int fd, int gt_id, const char *freq_name, uint32_t freq)
> -{
> -	int ret = -EAGAIN;
> -	char freq_attr[22];
> -	int gt_fd;
> -
> -	snprintf(freq_attr, sizeof(freq_attr), "freq0/%s_freq", freq_name);
> -	gt_fd = xe_sysfs_gt_open(fd, gt_id);
> -	igt_assert_lte(0, gt_fd);
> -
> -	while (ret == -EAGAIN)
> -		ret = igt_sysfs_printf(gt_fd, freq_attr, "%u", freq);
> -
> -	close(gt_fd);
> -	return ret;
> -}
> -
> -static uint32_t get_freq(int fd, int gt_id, const char *freq_name)
> -{
> -	uint32_t freq;
> -	int err = -EAGAIN;
> -	char freq_attr[22];
> -	int gt_fd;
> -
> -	snprintf(freq_attr, sizeof(freq_attr), "freq0/%s_freq", freq_name);
> -	gt_fd = xe_sysfs_gt_open(fd, gt_id);
> -	igt_assert_lte(0, gt_fd);
> -
> -	while (err == -EAGAIN)
> -		err = igt_sysfs_scanf(gt_fd, freq_attr, "%u", &freq);
> -
> -	igt_debug("gt%d: %s freq %u\n", gt_id, freq_name, freq);
> -
> -	close(gt_fd);
> -	return freq;
> -}
> -
>   static bool within_expected_range(uint32_t freq, uint32_t val)
>   {
>   	/*
> @@ -134,8 +98,8 @@ static void test_throttle_basic_api(int fd, int gt_id)
>   
>   static void test_freq_basic_api(int fd, int gt_id)
>   {
> -	uint32_t rpn = get_freq(fd, gt_id, "rpn");
> -	uint32_t rp0 = get_freq(fd, gt_id, "rp0");
> +	uint32_t rpn = xe_gt_get_freq(fd, gt_id, "rpn");
> +	uint32_t rp0 = xe_gt_get_freq(fd, gt_id, "rp0");
>   	uint32_t rpmid = (rp0 + rpn) / 2;
>   	uint32_t min_freq, max_freq;
>   
> @@ -144,29 +108,29 @@ static void test_freq_basic_api(int fd, int gt_id)
>   	 * RPn is the floor
>   	 * RP0 is the ceiling
>   	 */
> -	igt_assert_lt(set_freq(fd, gt_id, "min", rpn - 1), 0);
> -	igt_assert_lt(set_freq(fd, gt_id, "min", rp0 + 1), 0);
> -	igt_assert_lt(set_freq(fd, gt_id, "max", rpn - 1), 0);
> -	igt_assert_lt(set_freq(fd, gt_id, "max", rp0 + 1), 0);
> +	igt_assert_lt(xe_gt_set_freq(fd, gt_id, "min", rpn - 1), 0);
> +	igt_assert_lt(xe_gt_set_freq(fd, gt_id, "min", rp0 + 1), 0);
> +	igt_assert_lt(xe_gt_set_freq(fd, gt_id, "max", rpn - 1), 0);
> +	igt_assert_lt(xe_gt_set_freq(fd, gt_id, "max", rp0 + 1), 0);
>   
>   	/* Assert min requests are respected from rp0 to rpn */
> -	igt_assert_lt(0, set_freq(fd, gt_id, "min", rp0));
> -	igt_assert_eq_u32(get_freq(fd, gt_id, "min"), rp0);
> -	igt_assert_lt(0, set_freq(fd, gt_id, "min", rpmid));
> -	min_freq = get_freq(fd, gt_id, "min");
> +	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "min", rp0));
> +	igt_assert_eq_u32(xe_gt_get_freq(fd, gt_id, "min"), rp0);
> +	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "min", rpmid));
> +	min_freq = xe_gt_get_freq(fd, gt_id, "min");
>   	/* SLPC can set min higher than rpmid - as it follows RPe */
>   	igt_assert_lte_u32((rpmid - FREQ_UNIT_MHZ), min_freq);
> -	igt_assert_lt(0, set_freq(fd, gt_id, "min", rpn));
> -	igt_assert_eq_u32(get_freq(fd, gt_id, "min"), rpn);
> +	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "min", rpn));
> +	igt_assert_eq_u32(xe_gt_get_freq(fd, gt_id, "min"), rpn);
>   
>   	/* Assert max requests are respected from rpn to rp0 */
> -	igt_assert_lt(0, set_freq(fd, gt_id, "max", rpn));
> -	igt_assert_eq_u32(get_freq(fd, gt_id, "max"), rpn);
> -	igt_assert_lt(0, set_freq(fd, gt_id, "max", rpmid));
> -	max_freq = get_freq(fd, gt_id, "max");
> +	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "max", rpn));
> +	igt_assert_eq_u32(xe_gt_get_freq(fd, gt_id, "max"), rpn);
> +	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "max", rpmid));
> +	max_freq = xe_gt_get_freq(fd, gt_id, "max");
>   	igt_assert(within_expected_range(max_freq, rpmid));
> -	igt_assert_lt(0, set_freq(fd, gt_id, "max", rp0));
> -	igt_assert_eq_u32(get_freq(fd, gt_id, "max"), rp0);
> +	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "max", rp0));
> +	igt_assert_eq_u32(xe_gt_get_freq(fd, gt_id, "max"), rp0);
>   }
>   
>   /**
> @@ -179,8 +143,8 @@ static void test_freq_basic_api(int fd, int gt_id)
>   
>   static void test_freq_fixed(int fd, int gt_id, bool gt_idle)
>   {
> -	uint32_t rpn = get_freq(fd, gt_id, "rpn");
> -	uint32_t rp0 = get_freq(fd, gt_id, "rp0");
> +	uint32_t rpn = xe_gt_get_freq(fd, gt_id, "rpn");
> +	uint32_t rp0 = xe_gt_get_freq(fd, gt_id, "rp0");
>   	uint32_t rpmid = (rp0 + rpn) / 2;
>   	uint32_t cur_freq, act_freq;
>   
> @@ -192,50 +156,50 @@ static void test_freq_fixed(int fd, int gt_id, bool gt_idle)
>   	 * And let's do this for all the 2 known Render Performance (RP) values
>   	 * RP0 and RPn and something in between.
>   	 */
> -	igt_assert_lt(0, set_freq(fd, gt_id, "min", rpn));
> -	igt_assert_lt(0, set_freq(fd, gt_id, "max", rpn));
> +	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "min", rpn));
> +	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "max", rpn));
>   	usleep(SLPC_FREQ_LATENCY_US);
> -	igt_assert_eq_u32(get_freq(fd, gt_id, "cur"), rpn);
> +	igt_assert_eq_u32(xe_gt_get_freq(fd, gt_id, "cur"), rpn);
>   
>   	if (gt_idle) {
> -		/* Wait for GT to go in C6 as previous get_freq wakes up GT*/
> +		/* Wait for GT to go in C6 as previous xe_gt_get_freq wakes up GT*/
>   		igt_assert_f(igt_wait(xe_gt_is_in_c6(fd, gt_id), 1000, 10),
>   			     "GT %d should be in C6\n", gt_id);
> -		igt_assert(get_freq(fd, gt_id, "act") == 0);
> +		igt_assert(xe_gt_get_freq(fd, gt_id, "act") == 0);
>   	} else {
> -		igt_assert_eq_u32(get_freq(fd, gt_id, "act"), rpn);
> +		igt_assert_eq_u32(xe_gt_get_freq(fd, gt_id, "act"), rpn);
>   	}
>   
> -	igt_assert_lt(0, set_freq(fd, gt_id, "min", rpmid));
> -	igt_assert_lt(0, set_freq(fd, gt_id, "max", rpmid));
> +	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "min", rpmid));
> +	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "max", rpmid));
>   	usleep(SLPC_FREQ_LATENCY_US);
> -	cur_freq = get_freq(fd, gt_id, "cur");
> +	cur_freq = xe_gt_get_freq(fd, gt_id, "cur");
>   	/* If rpmid is around RPe, we could see SLPC follow it */
>   	igt_assert_lte_u32((rpmid - FREQ_UNIT_MHZ), cur_freq);
>   
>   	if (gt_idle) {
>   		igt_assert_f(igt_wait(xe_gt_is_in_c6(fd, gt_id), 1000, 10),
>   			     "GT %d should be in C6\n", gt_id);
> -		igt_assert(get_freq(fd, gt_id, "act") == 0);
> +		igt_assert(xe_gt_get_freq(fd, gt_id, "act") == 0);
>   	} else {
> -		act_freq = get_freq(fd, gt_id, "act");
> +		act_freq = xe_gt_get_freq(fd, gt_id, "act");
>   		igt_assert_lte_u32(act_freq, cur_freq + FREQ_UNIT_MHZ);
>   	}
>   
> -	igt_assert_lt(0, set_freq(fd, gt_id, "min", rp0));
> -	igt_assert_lt(0, set_freq(fd, gt_id, "max", rp0));
> +	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "min", rp0));
> +	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "max", rp0));
>   	usleep(SLPC_FREQ_LATENCY_US);
>   	/*
>   	 * It is unlikely that PCODE will *always* respect any request above RPe
>   	 * So for this level let's only check if GuC PC is doing its job
>   	 * and respecting our request, by propagating it to the hardware.
>   	 */
> -	igt_assert_eq_u32(get_freq(fd, gt_id, "cur"), rp0);
> +	igt_assert_eq_u32(xe_gt_get_freq(fd, gt_id, "cur"), rp0);
>   
>   	if (gt_idle) {
>   		igt_assert_f(igt_wait(xe_gt_is_in_c6(fd, gt_id), 1000, 10),
>   			     "GT %d should be in C6\n", gt_id);
> -		igt_assert(get_freq(fd, gt_id, "act") == 0);
> +		igt_assert(xe_gt_get_freq(fd, gt_id, "act") == 0);
>   	}
>   
>   	igt_debug("Finished testing fixed request\n");
> @@ -250,25 +214,25 @@ static void test_freq_fixed(int fd, int gt_id, bool gt_idle)
>    */
>   static void test_freq_range(int fd, int gt_id, bool gt_idle)
>   {
> -	uint32_t rpn = get_freq(fd, gt_id, "rpn");
> -	uint32_t rp0 = get_freq(fd, gt_id, "rp0");
> +	uint32_t rpn = xe_gt_get_freq(fd, gt_id, "rpn");
> +	uint32_t rp0 = xe_gt_get_freq(fd, gt_id, "rp0");
>   	uint32_t rpmid = (rp0 + rpn) / 2;
>   	uint32_t cur, act;
>   
>   	igt_debug("Starting testing range request\n");
>   
> -	igt_assert_lt(0, set_freq(fd, gt_id, "min", rpn));
> -	igt_assert_lt(0, set_freq(fd, gt_id, "max", rpmid));
> +	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "min", rpn));
> +	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "max", rpmid));
>   	usleep(SLPC_FREQ_LATENCY_US);
> -	cur = get_freq(fd, gt_id, "cur");
> +	cur = xe_gt_get_freq(fd, gt_id, "cur");
>   	igt_assert(rpn <= cur && cur <= rpmid + FREQ_UNIT_MHZ);
>   
>   	if (gt_idle) {
>   		igt_assert_f(igt_wait(xe_gt_is_in_c6(fd, gt_id), 1000, 10),
>   			     "GT %d should be in C6\n", gt_id);
> -		igt_assert(get_freq(fd, gt_id, "act") == 0);
> +		igt_assert(xe_gt_get_freq(fd, gt_id, "act") == 0);
>   	} else {
> -		act = get_freq(fd, gt_id, "act");
> +		act = xe_gt_get_freq(fd, gt_id, "act");
>   		igt_assert((rpn <= act) && (act <= cur + FREQ_UNIT_MHZ));
>   	}
>   
> @@ -282,21 +246,21 @@ static void test_freq_range(int fd, int gt_id, bool gt_idle)
>   
>   static void test_freq_low_max(int fd, int gt_id)
>   {
> -	uint32_t rpn = get_freq(fd, gt_id, "rpn");
> -	uint32_t rp0 = get_freq(fd, gt_id, "rp0");
> +	uint32_t rpn = xe_gt_get_freq(fd, gt_id, "rpn");
> +	uint32_t rp0 = xe_gt_get_freq(fd, gt_id, "rp0");
>   	uint32_t rpmid = (rp0 + rpn) / 2;
>   
>   	/*
>   	 *  When max request < min request, max is ignored and min works like
>   	 * a fixed one. Let's assert this assumption
>   	 */
> -	igt_assert_lt(0, set_freq(fd, gt_id, "min", rpmid));
> -	igt_assert_lt(0, set_freq(fd, gt_id, "max", rpn));
> +	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "min", rpmid));
> +	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "max", rpn));
>   	usleep(SLPC_FREQ_LATENCY_US);
>   
>   	/* Cur freq will follow RPe, which could be higher than min freq */
>   	igt_assert_lte_u32((rpmid - FREQ_UNIT_MHZ),
> -			   get_freq(fd, gt_id, "cur"));
> +			   xe_gt_get_freq(fd, gt_id, "cur"));
>   }
>   
>   /**
> @@ -306,18 +270,18 @@ static void test_freq_low_max(int fd, int gt_id)
>   
>   static void test_suspend(int fd, int gt_id)
>   {
> -	uint32_t rpn = get_freq(fd, gt_id, "rpn");
> +	uint32_t rpn = xe_gt_get_freq(fd, gt_id, "rpn");
>   
> -	igt_assert_lt(0, set_freq(fd, gt_id, "min", rpn));
> -	igt_assert_lt(0, set_freq(fd, gt_id, "max", rpn));
> +	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "min", rpn));
> +	igt_assert_lt(0, xe_gt_set_freq(fd, gt_id, "max", rpn));
>   	usleep(SLPC_FREQ_LATENCY_US);
> -	igt_assert_eq_u32(get_freq(fd, gt_id, "cur"), rpn);
> +	igt_assert_eq_u32(xe_gt_get_freq(fd, gt_id, "cur"), rpn);
>   
>   	igt_system_suspend_autoresume(SUSPEND_STATE_S3,
>   				      SUSPEND_TEST_NONE);
>   
> -	igt_assert_eq_u32(get_freq(fd, gt_id, "min"), rpn);
> -	igt_assert_eq_u32(get_freq(fd, gt_id, "max"), rpn);
> +	igt_assert_eq_u32(xe_gt_get_freq(fd, gt_id, "min"), rpn);
> +	igt_assert_eq_u32(xe_gt_get_freq(fd, gt_id, "max"), rpn);
>   }
>   
>   /**
> @@ -330,24 +294,24 @@ static void test_suspend(int fd, int gt_id)
>   
>   static void test_reset(int fd, int gt_id, int cycles)
>   {
> -	uint32_t rpn = get_freq(fd, gt_id, "rpn");
> +	uint32_t rpn = xe_gt_get_freq(fd, gt_id, "rpn");
>   
>   	for (int i = 0; i < cycles; i++) {
> -		igt_assert_f(set_freq(fd, gt_id, "min", rpn) > 0,
> +		igt_assert_f(xe_gt_set_freq(fd, gt_id, "min", rpn) > 0,
>   			     "Failed after %d good cycles\n", i);
> -		igt_assert_f(set_freq(fd, gt_id, "max", rpn) > 0,
> +		igt_assert_f(xe_gt_set_freq(fd, gt_id, "max", rpn) > 0,
>   			     "Failed after %d good cycles\n", i);
>   		usleep(SLPC_FREQ_LATENCY_US);
> -		igt_assert_f(get_freq(fd, gt_id, "cur") == rpn,
> +		igt_assert_f(xe_gt_get_freq(fd, gt_id, "cur") == rpn,
>   			     "Failed after %d good cycles\n", i);
>   
>   		xe_force_gt_reset_sync(fd, gt_id);
>   
>   		usleep(SLPC_FREQ_LATENCY_US);
>   
> -		igt_assert_f(get_freq(fd, gt_id, "min") == rpn,
> +		igt_assert_f(xe_gt_get_freq(fd, gt_id, "min") == rpn,
>   			     "Failed after %d good cycles\n", i);
> -		igt_assert_f(get_freq(fd, gt_id, "max") == rpn,
> +		igt_assert_f(xe_gt_get_freq(fd, gt_id, "max") == rpn,
>   			     "Failed after %d good cycles\n", i);
>   	}
>   }
> @@ -448,8 +412,8 @@ igt_main
>   		stash_max = (uint32_t *) malloc(sizeof(uint32_t) * num_gts);
>   
>   		xe_for_each_gt(fd, gt) {
> -			stash_min[gt] = get_freq(fd, gt, "min");
> -			stash_max[gt] = get_freq(fd, gt, "max");
> +			stash_min[gt] = xe_gt_get_freq(fd, gt, "min");
> +			stash_max[gt] = xe_gt_get_freq(fd, gt, "max");
>   		}
>   	}
>   
> @@ -525,8 +489,8 @@ igt_main
>   
>   	igt_fixture {
>   		xe_for_each_gt(fd, gt) {
> -			set_freq(fd, gt, "max", stash_max[gt]);
> -			set_freq(fd, gt, "min", stash_min[gt]);
> +			xe_gt_set_freq(fd, gt, "max", stash_max[gt]);
> +			xe_gt_set_freq(fd, gt, "min", stash_min[gt]);
>   		}
>   		free(stash_min);
>   		free(stash_max);


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH i-g-t 2/2] tests/xe_pmu: Add frequency test
  2025-04-07 23:44 [PATCH i-g-t 0/2] Add PMU test for GT frequency Vinay Belgaumkar
@ 2025-04-07 23:44 ` Vinay Belgaumkar
  2025-04-09  9:58   ` Riana Tauro
  0 siblings, 1 reply; 14+ messages in thread
From: Vinay Belgaumkar @ 2025-04-07 23:44 UTC (permalink / raw)
  To: intel-gfx, igt-dev
  Cc: Vinay Belgaumkar, Lucas De Marchi, Rodrigo Vivi, Riana Tauro

Add a basic test that uses PMU to read GT actual and requested
frequencies while running a workload.

v2: Rebase and comments (Riana)

Cc: Lucas De Marchi <lucas.demarchi@intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Riana Tauro <riana.tauro@intel.com>
Signed-off-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
---
 tests/intel/xe_pmu.c | 128 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 127 insertions(+), 1 deletion(-)

diff --git a/tests/intel/xe_pmu.c b/tests/intel/xe_pmu.c
index 175bbf374..fbac9c798 100644
--- a/tests/intel/xe_pmu.c
+++ b/tests/intel/xe_pmu.c
@@ -376,6 +376,94 @@ static void test_gt_c6_idle(int xe, unsigned int gt)
 	close(pmu_fd);
 }
 
+/**
+ * SUBTEST: gt-frequency
+ * Description: Validate we can collect accurate frequency PMU stats
+ *		while running a workload.
+ */
+static void test_gt_frequency(int fd, struct drm_xe_engine_class_instance *eci)
+{
+	struct xe_cork *cork = NULL;
+	uint64_t end[2], start[2];
+	unsigned long config_rq_freq, config_act_freq;
+	double min[2], max[2];
+	uint32_t gt = eci->gt_id;
+	uint32_t orig_min = xe_gt_get_freq(fd, eci->gt_id, "min");
+	uint32_t orig_max = xe_gt_get_freq(fd, eci->gt_id, "max");
+	uint32_t vm;
+	int pmu_fd[2];
+
+	config_rq_freq = get_event_config(gt, NULL, "gt-requested-frequency");
+	pmu_fd[0] = open_group(fd, config_rq_freq, -1);
+
+	config_act_freq = get_event_config(gt, NULL, "gt-actual-frequency");
+	pmu_fd[1] = open_group(fd, config_act_freq, pmu_fd[0]);
+
+	vm = xe_vm_create(fd, 0, 0);
+
+	cork = xe_cork_create_opts(fd, eci, vm, 1, 1);
+	xe_cork_sync_start(fd, cork);
+
+	/*
+	 * Set GPU to min frequency and read PMU counters.
+	 */
+	igt_assert(xe_gt_set_freq(fd, gt, "max", orig_min) > 0);
+	igt_assert(xe_gt_get_freq(fd, gt, "max") == orig_min);
+
+	pmu_read_multi(pmu_fd[0], 2, start);
+	usleep(SLEEP_DURATION * USEC_PER_SEC);
+	pmu_read_multi(pmu_fd[0], 2, end);
+
+	min[0] = (end[0] - start[0]);
+	min[1] = (end[1] - start[1]);
+
+	/*
+	 * Set GPU to max frequency and read PMU counters.
+	 */
+	igt_assert(xe_gt_set_freq(fd, gt, "max", orig_max) > 0);
+	igt_assert(xe_gt_get_freq(fd, gt, "max") == orig_max);
+	igt_assert(xe_gt_set_freq(fd, gt, "min", orig_max) > 0);
+	igt_assert(xe_gt_get_freq(fd, gt, "min") == orig_max);
+
+	pmu_read_multi(pmu_fd[0], 2, start);
+	usleep(SLEEP_DURATION * USEC_PER_SEC);
+	pmu_read_multi(pmu_fd[0], 2, end);
+
+	max[0] = (end[0] - start[0]);
+	max[1] = (end[1] - start[1]);
+
+	xe_cork_sync_end(fd, cork);
+
+	/*
+	 * Restore min/max.
+	 */
+	igt_assert(xe_gt_set_freq(fd, gt, "min", orig_min) > 0);
+	igt_assert(xe_gt_get_freq(fd, gt, "min") == orig_min);
+
+	igt_info("Minimum frequency: requested %.1f, actual %.1f\n",
+		 min[0], min[1]);
+	igt_info("Maximum frequency: requested %.1f, actual %.1f\n",
+		 max[0], max[1]);
+
+	close(pmu_fd[0]);
+	close(pmu_fd[1]);
+
+	if (cork)
+		xe_cork_destroy(fd, cork);
+
+	xe_vm_destroy(fd, vm);
+
+	close(pmu_fd[0]);
+	close(pmu_fd[1]);
+
+	assert_within_epsilon(min[0], orig_min, tolerance);
+	/*
+	 * On thermally throttled devices we cannot be sure maximum frequency
+	 * can be reached so use larger tolerance downwards.
+	 */
+	assert_within_epsilon_up_down(max[0], orig_max, tolerance, 0.15f);
+}
+
 static unsigned int enable_and_provision_vfs(int fd)
 {
 	unsigned int gt, num_vfs;
@@ -429,8 +517,9 @@ static void disable_vfs(int fd)
 
 igt_main
 {
-	int fd, gt;
+	int fd, gt, num_gts;
 	struct drm_xe_engine_class_instance *eci;
+	uint32_t *stash_min, *stash_max;
 
 	igt_fixture {
 		fd = drm_open_driver(DRIVER_XE);
@@ -482,6 +571,43 @@ igt_main
 			disable_vfs(fd);
 	}
 
+	igt_subtest_group {
+		igt_fixture {
+			igt_require(xe_sysfs_gt_has_node(fd, 0, "freq0"));
+			num_gts = xe_number_gt(fd);
+
+			stash_min = (uint32_t *) malloc(sizeof(uint32_t) * num_gts);
+			stash_max = (uint32_t *) malloc(sizeof(uint32_t) * num_gts);
+
+			xe_for_each_gt(fd, gt) {
+				stash_min[gt] = xe_gt_get_freq(fd, gt, "min");
+				stash_max[gt] = xe_gt_get_freq(fd, gt, "max");
+			}
+		}
+
+		igt_describe("Validate PMU GT freq measured is within the tolerance");
+		igt_subtest_with_dynamic("gt-frequency") {
+			xe_for_each_gt(fd, gt) {
+				igt_dynamic_f("gt%u", gt)
+				xe_for_each_engine(fd, eci) {
+					if (gt == eci->gt_id) {
+						test_gt_frequency(fd, eci);
+						break;
+					}
+				}
+			}
+		}
+
+		igt_fixture {
+			xe_for_each_gt(fd, gt) {
+				xe_gt_set_freq(fd, gt, "max", stash_max[gt]);
+				xe_gt_set_freq(fd, gt, "min", stash_min[gt]);
+			}
+			free(stash_min);
+			free(stash_max);
+		}
+	}
+
 	igt_fixture {
 		close(fd);
 	}
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH i-g-t 2/2] tests/xe_pmu: Add frequency test
  2025-04-07 23:44 ` [PATCH i-g-t 2/2] tests/xe_pmu: Add frequency test Vinay Belgaumkar
@ 2025-04-09  9:58   ` Riana Tauro
  2025-04-09 11:06     ` Kamil Konieczny
  2025-04-10  1:31     ` Belgaumkar, Vinay
  0 siblings, 2 replies; 14+ messages in thread
From: Riana Tauro @ 2025-04-09  9:58 UTC (permalink / raw)
  To: Vinay Belgaumkar, intel-gfx, igt-dev; +Cc: Lucas De Marchi, Rodrigo Vivi

Hi Vinay

On 4/8/2025 5:14 AM, Vinay Belgaumkar wrote:
> Add a basic test that uses PMU to read GT actual and requested
> frequencies while running a workload.
> 
> v2: Rebase and comments (Riana)
> 
> Cc: Lucas De Marchi <lucas.demarchi@intel.com>
> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> Cc: Riana Tauro <riana.tauro@intel.com>
> Signed-off-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
> ---
>   tests/intel/xe_pmu.c | 128 ++++++++++++++++++++++++++++++++++++++++++-
>   1 file changed, 127 insertions(+), 1 deletion(-)
> 
> diff --git a/tests/intel/xe_pmu.c b/tests/intel/xe_pmu.c
> index 175bbf374..fbac9c798 100644
> --- a/tests/intel/xe_pmu.c
> +++ b/tests/intel/xe_pmu.c
> @@ -376,6 +376,94 @@ static void test_gt_c6_idle(int xe, unsigned int gt)
>   	close(pmu_fd);
>   }
>   
> +/**
> + * SUBTEST: gt-frequency
> + * Description: Validate we can collect accurate frequency PMU stats
> + *		while running a workload.
> + */
> +static void test_gt_frequency(int fd, struct drm_xe_engine_class_instance *eci)
> +{
> +	struct xe_cork *cork = NULL;
> +	uint64_t end[2], start[2];
> +	unsigned long config_rq_freq, config_act_freq;
> +	double min[2], max[2];
> +	uint32_t gt = eci->gt_id;
> +	uint32_t orig_min = xe_gt_get_freq(fd, eci->gt_id, "min");
> +	uint32_t orig_max = xe_gt_get_freq(fd, eci->gt_id, "max");
> +	uint32_t vm;
> +	int pmu_fd[2];
> +
> +	config_rq_freq = get_event_config(gt, NULL, "gt-requested-frequency");
> +	pmu_fd[0] = open_group(fd, config_rq_freq, -1);
> +
> +	config_act_freq = get_event_config(gt, NULL, "gt-actual-frequency");
> +	pmu_fd[1] = open_group(fd, config_act_freq, pmu_fd[0]);
> +
> +	vm = xe_vm_create(fd, 0, 0);
> +
> +	cork = xe_cork_create_opts(fd, eci, vm, 1, 1);
> +	xe_cork_sync_start(fd, cork);
> +
> +	/*
> +	 * Set GPU to min frequency and read PMU counters.
> +	 */
> +	igt_assert(xe_gt_set_freq(fd, gt, "max", orig_min) > 0);
> +	igt_assert(xe_gt_get_freq(fd, gt, "max") == orig_min);
> +
> +	pmu_read_multi(pmu_fd[0], 2, start);
> +	usleep(SLEEP_DURATION * USEC_PER_SEC);
> +	pmu_read_multi(pmu_fd[0], 2, end);
> +
> +	min[0] = (end[0] - start[0]);
> +	min[1] = (end[1] - start[1]);
> +
> +	/*
> +	 * Set GPU to max frequency and read PMU counters.
> +	 */
> +	igt_assert(xe_gt_set_freq(fd, gt, "max", orig_max) > 0);
> +	igt_assert(xe_gt_get_freq(fd, gt, "max") == orig_max);
> +	igt_assert(xe_gt_set_freq(fd, gt, "min", orig_max) > 0);
> +	igt_assert(xe_gt_get_freq(fd, gt, "min") == orig_max);
> +
> +	pmu_read_multi(pmu_fd[0], 2, start);
> +	usleep(SLEEP_DURATION * USEC_PER_SEC);
> +	pmu_read_multi(pmu_fd[0], 2, end);
> +
> +	max[0] = (end[0] - start[0]);
> +	max[1] = (end[1] - start[1]);
> +
> +	xe_cork_sync_end(fd, cork);
> +
> +	/*
> +	 * Restore min/max.
> +	 */
> +	igt_assert(xe_gt_set_freq(fd, gt, "min", orig_min) > 0);
> +	igt_assert(xe_gt_get_freq(fd, gt, "min") == orig_min);
> +
> +	igt_info("Minimum frequency: requested %.1f, actual %.1f\n",
> +		 min[0], min[1]);
> +	igt_info("Maximum frequency: requested %.1f, actual %.1f\n",
> +		 max[0], max[1]);
> +
> +	close(pmu_fd[0]);
> +	close(pmu_fd[1]);
> +
> +	if (cork)
> +		xe_cork_destroy(fd, cork);
> +
> +	xe_vm_destroy(fd, vm);
> +
> +	close(pmu_fd[0]);
> +	close(pmu_fd[1]);
> +
> +	assert_within_epsilon(min[0], orig_min, tolerance);
> +	/*
> +	 * On thermally throttled devices we cannot be sure maximum frequency
> +	 * can be reached so use larger tolerance downwards.
> +	 */
> +	assert_within_epsilon_up_down(max[0], orig_max, tolerance, 0.15f);
> +}
> +
>   static unsigned int enable_and_provision_vfs(int fd)
>   {
>   	unsigned int gt, num_vfs;
> @@ -429,8 +517,9 @@ static void disable_vfs(int fd)
>   
>   igt_main
>   {
> -	int fd, gt;
> +	int fd, gt, num_gts;
>   	struct drm_xe_engine_class_instance *eci;
> +	uint32_t *stash_min, *stash_max;
>   
>   	igt_fixture {
>   		fd = drm_open_driver(DRIVER_XE);
> @@ -482,6 +571,43 @@ igt_main
>   			disable_vfs(fd);
>   	}
>   
> +	igt_subtest_group {
> +		igt_fixture {
> +			igt_require(xe_sysfs_gt_has_node(fd, 0, "freq0"));
> +			num_gts = xe_number_gt(fd);
> +
> +			stash_min = (uint32_t *) malloc(sizeof(uint32_t) * num_gts);
> +			stash_max = (uint32_t *) malloc(sizeof(uint32_t) * num_gts);
> +
> +			xe_for_each_gt(fd, gt) {
> +				stash_min[gt] = xe_gt_get_freq(fd, gt, "min");
> +				stash_max[gt] = xe_gt_get_freq(fd, gt, "max");
This can be moved inside the igt_subtest with local variables since it's 
only one test. The subtest group is executed for all the other tests too

Thanks
Riana> +			}
> +		}
> +
> +		igt_describe("Validate PMU GT freq measured is within the tolerance");
> +		igt_subtest_with_dynamic("gt-frequency") {
> +			xe_for_each_gt(fd, gt) {
> +				igt_dynamic_f("gt%u", gt)
> +				xe_for_each_engine(fd, eci) {
> +					if (gt == eci->gt_id) {
> +						test_gt_frequency(fd, eci);
> +						break;
> +					}
> +				}
> +			}
> +		}
> +
> +		igt_fixture {
> +			xe_for_each_gt(fd, gt) {
> +				xe_gt_set_freq(fd, gt, "max", stash_max[gt]);
> +				xe_gt_set_freq(fd, gt, "min", stash_min[gt]);
> +			}
> +			free(stash_min);
> +			free(stash_max);
> +		}
> +	}
> +
>   	igt_fixture {
>   		close(fd);
>   	}


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH i-g-t 2/2] tests/xe_pmu: Add frequency test
  2025-04-09  9:58   ` Riana Tauro
@ 2025-04-09 11:06     ` Kamil Konieczny
  2025-04-10  1:26       ` Belgaumkar, Vinay
  2025-04-10  1:31     ` Belgaumkar, Vinay
  1 sibling, 1 reply; 14+ messages in thread
From: Kamil Konieczny @ 2025-04-09 11:06 UTC (permalink / raw)
  To: igt-dev
  Cc: Riana Tauro, Vinay Belgaumkar, intel-gfx, Lucas De Marchi,
	Rodrigo Vivi

Hi,
On 2025-04-09 at 15:28:59 +0530, Riana Tauro wrote:
> Hi Vinay
> 
> On 4/8/2025 5:14 AM, Vinay Belgaumkar wrote:
> > Add a basic test that uses PMU to read GT actual and requested
> > frequencies while running a workload.
> > 
> > v2: Rebase and comments (Riana)
> > 
> > Cc: Lucas De Marchi <lucas.demarchi@intel.com>
> > Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> > Cc: Riana Tauro <riana.tauro@intel.com>
> > Signed-off-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
> > ---
> >   tests/intel/xe_pmu.c | 128 ++++++++++++++++++++++++++++++++++++++++++-
> >   1 file changed, 127 insertions(+), 1 deletion(-)
> > 
> > diff --git a/tests/intel/xe_pmu.c b/tests/intel/xe_pmu.c
> > index 175bbf374..fbac9c798 100644
> > --- a/tests/intel/xe_pmu.c
> > +++ b/tests/intel/xe_pmu.c
> > @@ -376,6 +376,94 @@ static void test_gt_c6_idle(int xe, unsigned int gt)
> >   	close(pmu_fd);
> >   }
> > +/**
> > + * SUBTEST: gt-frequency
> > + * Description: Validate we can collect accurate frequency PMU stats
> > + *		while running a workload.
> > + */
> > +static void test_gt_frequency(int fd, struct drm_xe_engine_class_instance *eci)
> > +{
> > +	struct xe_cork *cork = NULL;
> > +	uint64_t end[2], start[2];
> > +	unsigned long config_rq_freq, config_act_freq;
> > +	double min[2], max[2];
> > +	uint32_t gt = eci->gt_id;
> > +	uint32_t orig_min = xe_gt_get_freq(fd, eci->gt_id, "min");
> > +	uint32_t orig_max = xe_gt_get_freq(fd, eci->gt_id, "max");
> > +	uint32_t vm;
> > +	int pmu_fd[2];
> > +
> > +	config_rq_freq = get_event_config(gt, NULL, "gt-requested-frequency");
> > +	pmu_fd[0] = open_group(fd, config_rq_freq, -1);
> > +
> > +	config_act_freq = get_event_config(gt, NULL, "gt-actual-frequency");
> > +	pmu_fd[1] = open_group(fd, config_act_freq, pmu_fd[0]);
> > +
> > +	vm = xe_vm_create(fd, 0, 0);
> > +
> > +	cork = xe_cork_create_opts(fd, eci, vm, 1, 1);
> > +	xe_cork_sync_start(fd, cork);
> > +
> > +	/*
> > +	 * Set GPU to min frequency and read PMU counters.
> > +	 */
> > +	igt_assert(xe_gt_set_freq(fd, gt, "max", orig_min) > 0);
> > +	igt_assert(xe_gt_get_freq(fd, gt, "max") == orig_min);
> > +
> > +	pmu_read_multi(pmu_fd[0], 2, start);
> > +	usleep(SLEEP_DURATION * USEC_PER_SEC);
> > +	pmu_read_multi(pmu_fd[0], 2, end);
> > +
> > +	min[0] = (end[0] - start[0]);
> > +	min[1] = (end[1] - start[1]);
> > +
> > +	/*
> > +	 * Set GPU to max frequency and read PMU counters.
> > +	 */
> > +	igt_assert(xe_gt_set_freq(fd, gt, "max", orig_max) > 0);
> > +	igt_assert(xe_gt_get_freq(fd, gt, "max") == orig_max);
> > +	igt_assert(xe_gt_set_freq(fd, gt, "min", orig_max) > 0);
> > +	igt_assert(xe_gt_get_freq(fd, gt, "min") == orig_max);
> > +
> > +	pmu_read_multi(pmu_fd[0], 2, start);
> > +	usleep(SLEEP_DURATION * USEC_PER_SEC);
> > +	pmu_read_multi(pmu_fd[0], 2, end);
> > +
> > +	max[0] = (end[0] - start[0]);
> > +	max[1] = (end[1] - start[1]);
> > +
> > +	xe_cork_sync_end(fd, cork);
> > +
> > +	/*
> > +	 * Restore min/max.
> > +	 */
> > +	igt_assert(xe_gt_set_freq(fd, gt, "min", orig_min) > 0);
> > +	igt_assert(xe_gt_get_freq(fd, gt, "min") == orig_min);
> > +
> > +	igt_info("Minimum frequency: requested %.1f, actual %.1f\n",
> > +		 min[0], min[1]);
> > +	igt_info("Maximum frequency: requested %.1f, actual %.1f\n",
> > +		 max[0], max[1]);
> > +
> > +	close(pmu_fd[0]);
> > +	close(pmu_fd[1]);
> > +
> > +	if (cork)
> > +		xe_cork_destroy(fd, cork);
> > +
> > +	xe_vm_destroy(fd, vm);
> > +
> > +	close(pmu_fd[0]);
> > +	close(pmu_fd[1]);
> > +
> > +	assert_within_epsilon(min[0], orig_min, tolerance);
> > +	/*
> > +	 * On thermally throttled devices we cannot be sure maximum frequency
> > +	 * can be reached so use larger tolerance downwards.
> > +	 */
> > +	assert_within_epsilon_up_down(max[0], orig_max, tolerance, 0.15f);
> > +}
> > +
> >   static unsigned int enable_and_provision_vfs(int fd)
> >   {
> >   	unsigned int gt, num_vfs;
> > @@ -429,8 +517,9 @@ static void disable_vfs(int fd)
> >   igt_main
> >   {
> > -	int fd, gt;
> > +	int fd, gt, num_gts;
> >   	struct drm_xe_engine_class_instance *eci;
> > +	uint32_t *stash_min, *stash_max;
> >   	igt_fixture {
> >   		fd = drm_open_driver(DRIVER_XE);
> > @@ -482,6 +571,43 @@ igt_main
> >   			disable_vfs(fd);
> >   	}
> > +	igt_subtest_group {

Add here:
	bool has_freq0_node, needs_restore = false;

> > +		igt_fixture {
> > +			igt_require(xe_sysfs_gt_has_node(fd, 0, "freq0"));

Move this require into subtest. If you need it here then remember its
value for later use:
	has_freq0_node = xe_sysfs_gt_has_node(fd, 0, "freq0");

> > +			num_gts = xe_number_gt(fd);
> > +

So here start with if:

	if (has_freq0_node) {

> > +			stash_min = (uint32_t *) malloc(sizeof(uint32_t) * num_gts);
> > +			stash_max = (uint32_t *) malloc(sizeof(uint32_t) * num_gts);
> > +
> > +			xe_for_each_gt(fd, gt) {
> > +				stash_min[gt] = xe_gt_get_freq(fd, gt, "min");
> > +				stash_max[gt] = xe_gt_get_freq(fd, gt, "max");
> This can be moved inside the igt_subtest with local variables since it's
> only one test. The subtest group is executed for all the other tests too
> 
> Thanks
> Riana> +			}
> > +		}
> > +
> > +		igt_describe("Validate PMU GT freq measured is within the tolerance");
> > +		igt_subtest_with_dynamic("gt-frequency") {

needs_restore = true;

> > +			xe_for_each_gt(fd, gt) {
> > +				igt_dynamic_f("gt%u", gt)
> > +				xe_for_each_engine(fd, eci) {
> > +					if (gt == eci->gt_id) {
> > +						test_gt_frequency(fd, eci);
> > +						break;
> > +					}
> > +				}
> > +			}
> > +		}
> > +
> > +		igt_fixture {

			if (needs_restore) {
				
> > +			xe_for_each_gt(fd, gt) {
> > +				xe_gt_set_freq(fd, gt, "max", stash_max[gt]);
> > +				xe_gt_set_freq(fd, gt, "min", stash_min[gt]);
> > +			}
> > +			free(stash_min);
> > +			free(stash_max);

			} /* restore */

Regards,
Kamil

> > +		}
> > +	}
> > +
> >   	igt_fixture {
> >   		close(fd);
> >   	}
> 

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH i-g-t 2/2] tests/xe_pmu: Add frequency test
  2025-04-09 11:06     ` Kamil Konieczny
@ 2025-04-10  1:26       ` Belgaumkar, Vinay
  0 siblings, 0 replies; 14+ messages in thread
From: Belgaumkar, Vinay @ 2025-04-10  1:26 UTC (permalink / raw)
  To: Kamil Konieczny, igt-dev, Riana Tauro, intel-gfx, Lucas De Marchi,
	Rodrigo Vivi


On 4/9/2025 4:06 AM, Kamil Konieczny wrote:
> Hi,
> On 2025-04-09 at 15:28:59 +0530, Riana Tauro wrote:
>> Hi Vinay
>>
>> On 4/8/2025 5:14 AM, Vinay Belgaumkar wrote:
>>> Add a basic test that uses PMU to read GT actual and requested
>>> frequencies while running a workload.
>>>
>>> v2: Rebase and comments (Riana)
>>>
>>> Cc: Lucas De Marchi <lucas.demarchi@intel.com>
>>> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
>>> Cc: Riana Tauro <riana.tauro@intel.com>
>>> Signed-off-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
>>> ---
>>>    tests/intel/xe_pmu.c | 128 ++++++++++++++++++++++++++++++++++++++++++-
>>>    1 file changed, 127 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/tests/intel/xe_pmu.c b/tests/intel/xe_pmu.c
>>> index 175bbf374..fbac9c798 100644
>>> --- a/tests/intel/xe_pmu.c
>>> +++ b/tests/intel/xe_pmu.c
>>> @@ -376,6 +376,94 @@ static void test_gt_c6_idle(int xe, unsigned int gt)
>>>    	close(pmu_fd);
>>>    }
>>> +/**
>>> + * SUBTEST: gt-frequency
>>> + * Description: Validate we can collect accurate frequency PMU stats
>>> + *		while running a workload.
>>> + */
>>> +static void test_gt_frequency(int fd, struct drm_xe_engine_class_instance *eci)
>>> +{
>>> +	struct xe_cork *cork = NULL;
>>> +	uint64_t end[2], start[2];
>>> +	unsigned long config_rq_freq, config_act_freq;
>>> +	double min[2], max[2];
>>> +	uint32_t gt = eci->gt_id;
>>> +	uint32_t orig_min = xe_gt_get_freq(fd, eci->gt_id, "min");
>>> +	uint32_t orig_max = xe_gt_get_freq(fd, eci->gt_id, "max");
>>> +	uint32_t vm;
>>> +	int pmu_fd[2];
>>> +
>>> +	config_rq_freq = get_event_config(gt, NULL, "gt-requested-frequency");
>>> +	pmu_fd[0] = open_group(fd, config_rq_freq, -1);
>>> +
>>> +	config_act_freq = get_event_config(gt, NULL, "gt-actual-frequency");
>>> +	pmu_fd[1] = open_group(fd, config_act_freq, pmu_fd[0]);
>>> +
>>> +	vm = xe_vm_create(fd, 0, 0);
>>> +
>>> +	cork = xe_cork_create_opts(fd, eci, vm, 1, 1);
>>> +	xe_cork_sync_start(fd, cork);
>>> +
>>> +	/*
>>> +	 * Set GPU to min frequency and read PMU counters.
>>> +	 */
>>> +	igt_assert(xe_gt_set_freq(fd, gt, "max", orig_min) > 0);
>>> +	igt_assert(xe_gt_get_freq(fd, gt, "max") == orig_min);
>>> +
>>> +	pmu_read_multi(pmu_fd[0], 2, start);
>>> +	usleep(SLEEP_DURATION * USEC_PER_SEC);
>>> +	pmu_read_multi(pmu_fd[0], 2, end);
>>> +
>>> +	min[0] = (end[0] - start[0]);
>>> +	min[1] = (end[1] - start[1]);
>>> +
>>> +	/*
>>> +	 * Set GPU to max frequency and read PMU counters.
>>> +	 */
>>> +	igt_assert(xe_gt_set_freq(fd, gt, "max", orig_max) > 0);
>>> +	igt_assert(xe_gt_get_freq(fd, gt, "max") == orig_max);
>>> +	igt_assert(xe_gt_set_freq(fd, gt, "min", orig_max) > 0);
>>> +	igt_assert(xe_gt_get_freq(fd, gt, "min") == orig_max);
>>> +
>>> +	pmu_read_multi(pmu_fd[0], 2, start);
>>> +	usleep(SLEEP_DURATION * USEC_PER_SEC);
>>> +	pmu_read_multi(pmu_fd[0], 2, end);
>>> +
>>> +	max[0] = (end[0] - start[0]);
>>> +	max[1] = (end[1] - start[1]);
>>> +
>>> +	xe_cork_sync_end(fd, cork);
>>> +
>>> +	/*
>>> +	 * Restore min/max.
>>> +	 */
>>> +	igt_assert(xe_gt_set_freq(fd, gt, "min", orig_min) > 0);
>>> +	igt_assert(xe_gt_get_freq(fd, gt, "min") == orig_min);
>>> +
>>> +	igt_info("Minimum frequency: requested %.1f, actual %.1f\n",
>>> +		 min[0], min[1]);
>>> +	igt_info("Maximum frequency: requested %.1f, actual %.1f\n",
>>> +		 max[0], max[1]);
>>> +
>>> +	close(pmu_fd[0]);
>>> +	close(pmu_fd[1]);
>>> +
>>> +	if (cork)
>>> +		xe_cork_destroy(fd, cork);
>>> +
>>> +	xe_vm_destroy(fd, vm);
>>> +
>>> +	close(pmu_fd[0]);
>>> +	close(pmu_fd[1]);
>>> +
>>> +	assert_within_epsilon(min[0], orig_min, tolerance);
>>> +	/*
>>> +	 * On thermally throttled devices we cannot be sure maximum frequency
>>> +	 * can be reached so use larger tolerance downwards.
>>> +	 */
>>> +	assert_within_epsilon_up_down(max[0], orig_max, tolerance, 0.15f);
>>> +}
>>> +
>>>    static unsigned int enable_and_provision_vfs(int fd)
>>>    {
>>>    	unsigned int gt, num_vfs;
>>> @@ -429,8 +517,9 @@ static void disable_vfs(int fd)
>>>    igt_main
>>>    {
>>> -	int fd, gt;
>>> +	int fd, gt, num_gts;
>>>    	struct drm_xe_engine_class_instance *eci;
>>> +	uint32_t *stash_min, *stash_max;
>>>    	igt_fixture {
>>>    		fd = drm_open_driver(DRIVER_XE);
>>> @@ -482,6 +571,43 @@ igt_main
>>>    			disable_vfs(fd);
>>>    	}
>>> +	igt_subtest_group {
> Add here:
> 	bool has_freq0_node, needs_restore = false;
>
>>> +		igt_fixture {
>>> +			igt_require(xe_sysfs_gt_has_node(fd, 0, "freq0"));
> Move this require into subtest. If you need it here then remember its
> value for later use:
> 	has_freq0_node = xe_sysfs_gt_has_node(fd, 0, "freq0");
>
>>> +			num_gts = xe_number_gt(fd);
>>> +
> So here start with if:
>
> 	if (has_freq0_node) {
>
>>> +			stash_min = (uint32_t *) malloc(sizeof(uint32_t) * num_gts);
>>> +			stash_max = (uint32_t *) malloc(sizeof(uint32_t) * num_gts);
>>> +
>>> +			xe_for_each_gt(fd, gt) {
>>> +				stash_min[gt] = xe_gt_get_freq(fd, gt, "min");
>>> +				stash_max[gt] = xe_gt_get_freq(fd, gt, "max");
>> This can be moved inside the igt_subtest with local variables since it's
>> only one test. The subtest group is executed for all the other tests too
>>
>> Thanks
>> Riana> +			}
>>> +		}
>>> +
>>> +		igt_describe("Validate PMU GT freq measured is within the tolerance");
>>> +		igt_subtest_with_dynamic("gt-frequency") {
> needs_restore = true;
>
>>> +			xe_for_each_gt(fd, gt) {
>>> +				igt_dynamic_f("gt%u", gt)
>>> +				xe_for_each_engine(fd, eci) {
>>> +					if (gt == eci->gt_id) {
>>> +						test_gt_frequency(fd, eci);
>>> +						break;
>>> +					}
>>> +				}
>>> +			}
>>> +		}
>>> +
>>> +		igt_fixture {
> 			if (needs_restore) {

ok. Thanks,

Vinay.

> 				
>>> +			xe_for_each_gt(fd, gt) {
>>> +				xe_gt_set_freq(fd, gt, "max", stash_max[gt]);
>>> +				xe_gt_set_freq(fd, gt, "min", stash_min[gt]);
>>> +			}
>>> +			free(stash_min);
>>> +			free(stash_max);
> 			} /* restore */
>
> Regards,
> Kamil
>
>>> +		}
>>> +	}
>>> +
>>>    	igt_fixture {
>>>    		close(fd);
>>>    	}

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH i-g-t 2/2] tests/xe_pmu: Add frequency test
  2025-04-09  9:58   ` Riana Tauro
  2025-04-09 11:06     ` Kamil Konieczny
@ 2025-04-10  1:31     ` Belgaumkar, Vinay
  1 sibling, 0 replies; 14+ messages in thread
From: Belgaumkar, Vinay @ 2025-04-10  1:31 UTC (permalink / raw)
  To: Riana Tauro, intel-gfx, igt-dev; +Cc: Lucas De Marchi, Rodrigo Vivi


On 4/9/2025 2:58 AM, Riana Tauro wrote:
> Hi Vinay
>
> On 4/8/2025 5:14 AM, Vinay Belgaumkar wrote:
>> Add a basic test that uses PMU to read GT actual and requested
>> frequencies while running a workload.
>>
>> v2: Rebase and comments (Riana)
>>
>> Cc: Lucas De Marchi <lucas.demarchi@intel.com>
>> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
>> Cc: Riana Tauro <riana.tauro@intel.com>
>> Signed-off-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
>> ---
>>   tests/intel/xe_pmu.c | 128 ++++++++++++++++++++++++++++++++++++++++++-
>>   1 file changed, 127 insertions(+), 1 deletion(-)
>>
>> diff --git a/tests/intel/xe_pmu.c b/tests/intel/xe_pmu.c
>> index 175bbf374..fbac9c798 100644
>> --- a/tests/intel/xe_pmu.c
>> +++ b/tests/intel/xe_pmu.c
>> @@ -376,6 +376,94 @@ static void test_gt_c6_idle(int xe, unsigned int 
>> gt)
>>       close(pmu_fd);
>>   }
>>   +/**
>> + * SUBTEST: gt-frequency
>> + * Description: Validate we can collect accurate frequency PMU stats
>> + *        while running a workload.
>> + */
>> +static void test_gt_frequency(int fd, struct 
>> drm_xe_engine_class_instance *eci)
>> +{
>> +    struct xe_cork *cork = NULL;
>> +    uint64_t end[2], start[2];
>> +    unsigned long config_rq_freq, config_act_freq;
>> +    double min[2], max[2];
>> +    uint32_t gt = eci->gt_id;
>> +    uint32_t orig_min = xe_gt_get_freq(fd, eci->gt_id, "min");
>> +    uint32_t orig_max = xe_gt_get_freq(fd, eci->gt_id, "max");
>> +    uint32_t vm;
>> +    int pmu_fd[2];
>> +
>> +    config_rq_freq = get_event_config(gt, NULL, 
>> "gt-requested-frequency");
>> +    pmu_fd[0] = open_group(fd, config_rq_freq, -1);
>> +
>> +    config_act_freq = get_event_config(gt, NULL, 
>> "gt-actual-frequency");
>> +    pmu_fd[1] = open_group(fd, config_act_freq, pmu_fd[0]);
>> +
>> +    vm = xe_vm_create(fd, 0, 0);
>> +
>> +    cork = xe_cork_create_opts(fd, eci, vm, 1, 1);
>> +    xe_cork_sync_start(fd, cork);
>> +
>> +    /*
>> +     * Set GPU to min frequency and read PMU counters.
>> +     */
>> +    igt_assert(xe_gt_set_freq(fd, gt, "max", orig_min) > 0);
>> +    igt_assert(xe_gt_get_freq(fd, gt, "max") == orig_min);
>> +
>> +    pmu_read_multi(pmu_fd[0], 2, start);
>> +    usleep(SLEEP_DURATION * USEC_PER_SEC);
>> +    pmu_read_multi(pmu_fd[0], 2, end);
>> +
>> +    min[0] = (end[0] - start[0]);
>> +    min[1] = (end[1] - start[1]);
>> +
>> +    /*
>> +     * Set GPU to max frequency and read PMU counters.
>> +     */
>> +    igt_assert(xe_gt_set_freq(fd, gt, "max", orig_max) > 0);
>> +    igt_assert(xe_gt_get_freq(fd, gt, "max") == orig_max);
>> +    igt_assert(xe_gt_set_freq(fd, gt, "min", orig_max) > 0);
>> +    igt_assert(xe_gt_get_freq(fd, gt, "min") == orig_max);
>> +
>> +    pmu_read_multi(pmu_fd[0], 2, start);
>> +    usleep(SLEEP_DURATION * USEC_PER_SEC);
>> +    pmu_read_multi(pmu_fd[0], 2, end);
>> +
>> +    max[0] = (end[0] - start[0]);
>> +    max[1] = (end[1] - start[1]);
>> +
>> +    xe_cork_sync_end(fd, cork);
>> +
>> +    /*
>> +     * Restore min/max.
>> +     */
>> +    igt_assert(xe_gt_set_freq(fd, gt, "min", orig_min) > 0);
>> +    igt_assert(xe_gt_get_freq(fd, gt, "min") == orig_min);
>> +
>> +    igt_info("Minimum frequency: requested %.1f, actual %.1f\n",
>> +         min[0], min[1]);
>> +    igt_info("Maximum frequency: requested %.1f, actual %.1f\n",
>> +         max[0], max[1]);
>> +
>> +    close(pmu_fd[0]);
>> +    close(pmu_fd[1]);
>> +
>> +    if (cork)
>> +        xe_cork_destroy(fd, cork);
>> +
>> +    xe_vm_destroy(fd, vm);
>> +
>> +    close(pmu_fd[0]);
>> +    close(pmu_fd[1]);
>> +
>> +    assert_within_epsilon(min[0], orig_min, tolerance);
>> +    /*
>> +     * On thermally throttled devices we cannot be sure maximum 
>> frequency
>> +     * can be reached so use larger tolerance downwards.
>> +     */
>> +    assert_within_epsilon_up_down(max[0], orig_max, tolerance, 0.15f);
>> +}
>> +
>>   static unsigned int enable_and_provision_vfs(int fd)
>>   {
>>       unsigned int gt, num_vfs;
>> @@ -429,8 +517,9 @@ static void disable_vfs(int fd)
>>     igt_main
>>   {
>> -    int fd, gt;
>> +    int fd, gt, num_gts;
>>       struct drm_xe_engine_class_instance *eci;
>> +    uint32_t *stash_min, *stash_max;
>>         igt_fixture {
>>           fd = drm_open_driver(DRIVER_XE);
>> @@ -482,6 +571,43 @@ igt_main
>>               disable_vfs(fd);
>>       }
>>   +    igt_subtest_group {
>> +        igt_fixture {
>> +            igt_require(xe_sysfs_gt_has_node(fd, 0, "freq0"));
>> +            num_gts = xe_number_gt(fd);
>> +
>> +            stash_min = (uint32_t *) malloc(sizeof(uint32_t) * 
>> num_gts);
>> +            stash_max = (uint32_t *) malloc(sizeof(uint32_t) * 
>> num_gts);
>> +
>> +            xe_for_each_gt(fd, gt) {
>> +                stash_min[gt] = xe_gt_get_freq(fd, gt, "min");
>> +                stash_max[gt] = xe_gt_get_freq(fd, gt, "max");
> This can be moved inside the igt_subtest with local variables since 
> it's only one test. The subtest group is executed for all the other 
> tests too

ok.

Thanks,

Vinay.

>
> Thanks
> Riana> +            }
>> +        }
>> +
>> +        igt_describe("Validate PMU GT freq measured is within the 
>> tolerance");
>> +        igt_subtest_with_dynamic("gt-frequency") {
>> +            xe_for_each_gt(fd, gt) {
>> +                igt_dynamic_f("gt%u", gt)
>> +                xe_for_each_engine(fd, eci) {
>> +                    if (gt == eci->gt_id) {
>> +                        test_gt_frequency(fd, eci);
>> +                        break;
>> +                    }
>> +                }
>> +            }
>> +        }
>> +
>> +        igt_fixture {
>> +            xe_for_each_gt(fd, gt) {
>> +                xe_gt_set_freq(fd, gt, "max", stash_max[gt]);
>> +                xe_gt_set_freq(fd, gt, "min", stash_min[gt]);
>> +            }
>> +            free(stash_min);
>> +            free(stash_max);
>> +        }
>> +    }
>> +
>>       igt_fixture {
>>           close(fd);
>>       }
>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH i-g-t 2/2] tests/xe_pmu: Add frequency test
  2025-04-10  1:33 [PATCH i-g-t 0/2] Add PMU test for GT frequency Vinay Belgaumkar
@ 2025-04-10  1:33 ` Vinay Belgaumkar
  2025-04-11  7:33   ` Riana Tauro
  0 siblings, 1 reply; 14+ messages in thread
From: Vinay Belgaumkar @ 2025-04-10  1:33 UTC (permalink / raw)
  To: intel-gfx, igt-dev
  Cc: Vinay Belgaumkar, Lucas De Marchi, Rodrigo Vivi, Riana Tauro,
	Kamil Konieczny

Add a basic test that uses PMU to read GT actual and requested
frequencies while running a workload.

v2: Rebase and comments (Riana)
v3: Address review comments (Kamil and Riana)

Cc: Lucas De Marchi <lucas.demarchi@intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Riana Tauro <riana.tauro@intel.com>
Cc: Kamil Konieczny <kamil.konieczny@linux.intel.com>
Signed-off-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
---
 tests/intel/xe_pmu.c | 147 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 147 insertions(+)

diff --git a/tests/intel/xe_pmu.c b/tests/intel/xe_pmu.c
index 175bbf374..589c7cbde 100644
--- a/tests/intel/xe_pmu.c
+++ b/tests/intel/xe_pmu.c
@@ -376,6 +376,94 @@ static void test_gt_c6_idle(int xe, unsigned int gt)
 	close(pmu_fd);
 }
 
+/**
+ * SUBTEST: gt-frequency
+ * Description: Validate we can collect accurate frequency PMU stats
+ *		while running a workload.
+ */
+static void test_gt_frequency(int fd, struct drm_xe_engine_class_instance *eci)
+{
+	struct xe_cork *cork = NULL;
+	uint64_t end[2], start[2];
+	unsigned long config_rq_freq, config_act_freq;
+	double min[2], max[2];
+	uint32_t gt = eci->gt_id;
+	uint32_t orig_min = xe_gt_get_freq(fd, eci->gt_id, "min");
+	uint32_t orig_max = xe_gt_get_freq(fd, eci->gt_id, "max");
+	uint32_t vm;
+	int pmu_fd[2];
+
+	config_rq_freq = get_event_config(gt, NULL, "gt-requested-frequency");
+	pmu_fd[0] = open_group(fd, config_rq_freq, -1);
+
+	config_act_freq = get_event_config(gt, NULL, "gt-actual-frequency");
+	pmu_fd[1] = open_group(fd, config_act_freq, pmu_fd[0]);
+
+	vm = xe_vm_create(fd, 0, 0);
+
+	cork = xe_cork_create_opts(fd, eci, vm, 1, 1);
+	xe_cork_sync_start(fd, cork);
+
+	/*
+	 * Set GPU to min frequency and read PMU counters.
+	 */
+	igt_assert(xe_gt_set_freq(fd, gt, "max", orig_min) > 0);
+	igt_assert(xe_gt_get_freq(fd, gt, "max") == orig_min);
+
+	pmu_read_multi(pmu_fd[0], 2, start);
+	usleep(SLEEP_DURATION * USEC_PER_SEC);
+	pmu_read_multi(pmu_fd[0], 2, end);
+
+	min[0] = (end[0] - start[0]);
+	min[1] = (end[1] - start[1]);
+
+	/*
+	 * Set GPU to max frequency and read PMU counters.
+	 */
+	igt_assert(xe_gt_set_freq(fd, gt, "max", orig_max) > 0);
+	igt_assert(xe_gt_get_freq(fd, gt, "max") == orig_max);
+	igt_assert(xe_gt_set_freq(fd, gt, "min", orig_max) > 0);
+	igt_assert(xe_gt_get_freq(fd, gt, "min") == orig_max);
+
+	pmu_read_multi(pmu_fd[0], 2, start);
+	usleep(SLEEP_DURATION * USEC_PER_SEC);
+	pmu_read_multi(pmu_fd[0], 2, end);
+
+	max[0] = (end[0] - start[0]);
+	max[1] = (end[1] - start[1]);
+
+	xe_cork_sync_end(fd, cork);
+
+	/*
+	 * Restore min/max.
+	 */
+	igt_assert(xe_gt_set_freq(fd, gt, "min", orig_min) > 0);
+	igt_assert(xe_gt_get_freq(fd, gt, "min") == orig_min);
+
+	igt_info("Minimum frequency: requested %.1f, actual %.1f\n",
+		 min[0], min[1]);
+	igt_info("Maximum frequency: requested %.1f, actual %.1f\n",
+		 max[0], max[1]);
+
+	close(pmu_fd[0]);
+	close(pmu_fd[1]);
+
+	if (cork)
+		xe_cork_destroy(fd, cork);
+
+	xe_vm_destroy(fd, vm);
+
+	close(pmu_fd[0]);
+	close(pmu_fd[1]);
+
+	assert_within_epsilon(min[0], orig_min, tolerance);
+	/*
+	 * On thermally throttled devices we cannot be sure maximum frequency
+	 * can be reached so use larger tolerance downwards.
+	 */
+	assert_within_epsilon_up_down(max[0], orig_max, tolerance, 0.15f);
+}
+
 static unsigned int enable_and_provision_vfs(int fd)
 {
 	unsigned int gt, num_vfs;
@@ -427,6 +515,35 @@ static void disable_vfs(int fd)
 		       "Failed to restore sriov_drivers_autoprobe value\n");
 }
 
+static void stash_gt_freq(int fd, uint32_t **stash_min, uint32_t **stash_max)
+{
+	int num_gts, gt;
+
+	num_gts = xe_number_gt(fd);
+
+	*stash_min = (uint32_t *) malloc(sizeof(uint32_t) * num_gts);
+	*stash_max = (uint32_t *) malloc(sizeof(uint32_t) * num_gts);
+
+	igt_skip_on(*stash_min == NULL || *stash_max == NULL);
+
+	xe_for_each_gt(fd, gt) {
+		*stash_min[gt] = xe_gt_get_freq(fd, gt, "min");
+		*stash_max[gt] = xe_gt_get_freq(fd, gt, "max");
+	}
+}
+
+static void restore_gt_freq(int fd, uint32_t *stash_min, uint32_t *stash_max)
+{
+	int gt;
+
+	xe_for_each_gt(fd, gt) {
+		xe_gt_set_freq(fd, gt, "max", stash_max[gt]);
+		xe_gt_set_freq(fd, gt, "min", stash_min[gt]);
+	}
+	free(stash_min);
+	free(stash_max);
+}
+
 igt_main
 {
 	int fd, gt;
@@ -482,6 +599,36 @@ igt_main
 			disable_vfs(fd);
 	}
 
+	igt_subtest_group {
+		bool has_freq0_node, needs_freq_restore = false;
+		uint32_t *stash_min, *stash_max;
+
+		igt_fixture {
+			has_freq0_node = xe_sysfs_gt_has_node(fd, 0, "freq0");
+		}
+
+		igt_describe("Validate PMU GT freq measured is within the tolerance");
+		igt_subtest_with_dynamic("gt-frequency") {
+			igt_skip_on(!has_freq0_node);
+			stash_gt_freq(fd, &stash_min, &stash_max);
+			needs_freq_restore = true;
+			xe_for_each_gt(fd, gt) {
+				igt_dynamic_f("gt%u", gt)
+				xe_for_each_engine(fd, eci) {
+					if (gt == eci->gt_id) {
+						test_gt_frequency(fd, eci);
+						break;
+					}
+				}
+			}
+		}
+
+		igt_fixture {
+			if (needs_freq_restore)
+				restore_gt_freq(fd, stash_min, stash_max);
+		}
+	}
+
 	igt_fixture {
 		close(fd);
 	}
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH i-g-t 2/2] tests/xe_pmu: Add frequency test
  2025-04-10  1:33 ` [PATCH i-g-t 2/2] tests/xe_pmu: Add frequency test Vinay Belgaumkar
@ 2025-04-11  7:33   ` Riana Tauro
  2025-04-11 22:36     ` Belgaumkar, Vinay
  0 siblings, 1 reply; 14+ messages in thread
From: Riana Tauro @ 2025-04-11  7:33 UTC (permalink / raw)
  To: Vinay Belgaumkar, intel-gfx, igt-dev
  Cc: Lucas De Marchi, Rodrigo Vivi, Kamil Konieczny

Hi Vinay

On 4/10/2025 7:03 AM, Vinay Belgaumkar wrote:
> Add a basic test that uses PMU to read GT actual and requested
> frequencies while running a workload.
> 
> v2: Rebase and comments (Riana)
> v3: Address review comments (Kamil and Riana)
> 
> Cc: Lucas De Marchi <lucas.demarchi@intel.com>
> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> Cc: Riana Tauro <riana.tauro@intel.com>
> Cc: Kamil Konieczny <kamil.konieczny@linux.intel.com>
> Signed-off-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
> ---
>   tests/intel/xe_pmu.c | 147 +++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 147 insertions(+)
> 
> diff --git a/tests/intel/xe_pmu.c b/tests/intel/xe_pmu.c
> index 175bbf374..589c7cbde 100644
> --- a/tests/intel/xe_pmu.c
> +++ b/tests/intel/xe_pmu.c
> @@ -376,6 +376,94 @@ static void test_gt_c6_idle(int xe, unsigned int gt)
>   	close(pmu_fd);
>   }
>   
> +/**
> + * SUBTEST: gt-frequency
> + * Description: Validate we can collect accurate frequency PMU stats
> + *		while running a workload.
> + */
> +static void test_gt_frequency(int fd, struct drm_xe_engine_class_instance *eci)
> +{
> +	struct xe_cork *cork = NULL;
> +	uint64_t end[2], start[2];
> +	unsigned long config_rq_freq, config_act_freq;
> +	double min[2], max[2];
> +	uint32_t gt = eci->gt_id;
> +	uint32_t orig_min = xe_gt_get_freq(fd, eci->gt_id, "min");
> +	uint32_t orig_max = xe_gt_get_freq(fd, eci->gt_id, "max");
> +	uint32_t vm;
> +	int pmu_fd[2];
> +
> +	config_rq_freq = get_event_config(gt, NULL, "gt-requested-frequency");
> +	pmu_fd[0] = open_group(fd, config_rq_freq, -1);
> +
> +	config_act_freq = get_event_config(gt, NULL, "gt-actual-frequency");
> +	pmu_fd[1] = open_group(fd, config_act_freq, pmu_fd[0]);
> +
> +	vm = xe_vm_create(fd, 0, 0);
> +
> +	cork = xe_cork_create_opts(fd, eci, vm, 1, 1);
> +	xe_cork_sync_start(fd, cork);
> +
> +	/*
> +	 * Set GPU to min frequency and read PMU counters.
> +	 */
> +	igt_assert(xe_gt_set_freq(fd, gt, "max", orig_min) > 0);
> +	igt_assert(xe_gt_get_freq(fd, gt, "max") == orig_min);
> +
> +	pmu_read_multi(pmu_fd[0], 2, start);
> +	usleep(SLEEP_DURATION * USEC_PER_SEC);
> +	pmu_read_multi(pmu_fd[0], 2, end);
> +
> +	min[0] = (end[0] - start[0]);
> +	min[1] = (end[1] - start[1]);
> +
> +	/*
> +	 * Set GPU to max frequency and read PMU counters.
> +	 */
> +	igt_assert(xe_gt_set_freq(fd, gt, "max", orig_max) > 0);
> +	igt_assert(xe_gt_get_freq(fd, gt, "max") == orig_max);
> +	igt_assert(xe_gt_set_freq(fd, gt, "min", orig_max) > 0);
> +	igt_assert(xe_gt_get_freq(fd, gt, "min") == orig_max);
> +
> +	pmu_read_multi(pmu_fd[0], 2, start);
> +	usleep(SLEEP_DURATION * USEC_PER_SEC);
> +	pmu_read_multi(pmu_fd[0], 2, end);
> +
> +	max[0] = (end[0] - start[0]);
> +	max[1] = (end[1] - start[1]);
> +
> +	xe_cork_sync_end(fd, cork);
> +
> +	/*
> +	 * Restore min/max.
> +	 */
> +	igt_assert(xe_gt_set_freq(fd, gt, "min", orig_min) > 0);
> +	igt_assert(xe_gt_get_freq(fd, gt, "min") == orig_min);
> +
> +	igt_info("Minimum frequency: requested %.1f, actual %.1f\n",
> +		 min[0], min[1]);
> +	igt_info("Maximum frequency: requested %.1f, actual %.1f\n",
> +		 max[0], max[1]);
> +
> +	close(pmu_fd[0]);
> +	close(pmu_fd[1]);
> +
> +	if (cork)
> +		xe_cork_destroy(fd, cork);
> +
> +	xe_vm_destroy(fd, vm);
> +
> +	close(pmu_fd[0]);
> +	close(pmu_fd[1]);
> +
> +	assert_within_epsilon(min[0], orig_min, tolerance);
> +	/*
> +	 * On thermally throttled devices we cannot be sure maximum frequency
> +	 * can be reached so use larger tolerance downwards.
> +	 */
> +	assert_within_epsilon_up_down(max[0], orig_max, tolerance, 0.15f);
> +}
> +
>   static unsigned int enable_and_provision_vfs(int fd)
>   {
>   	unsigned int gt, num_vfs;
> @@ -427,6 +515,35 @@ static void disable_vfs(int fd)
>   		       "Failed to restore sriov_drivers_autoprobe value\n");
>   }
>   
> +static void stash_gt_freq(int fd, uint32_t **stash_min, uint32_t **stash_max)
> +{
> +	int num_gts, gt;
> +
> +	num_gts = xe_number_gt(fd);
> +
> +	*stash_min = (uint32_t *) malloc(sizeof(uint32_t) * num_gts);
> +	*stash_max = (uint32_t *) malloc(sizeof(uint32_t) * num_gts);
> +
> +	igt_skip_on(*stash_min == NULL || *stash_max == NULL);
> +
> +	xe_for_each_gt(fd, gt) {
> +		*stash_min[gt] = xe_gt_get_freq(fd, gt, "min");
> +		*stash_max[gt] = xe_gt_get_freq(fd, gt, "max");
> +	}
> +}
> +
> +static void restore_gt_freq(int fd, uint32_t *stash_min, uint32_t *stash_max)
> +{
> +	int gt;
> +
> +	xe_for_each_gt(fd, gt) {
> +		xe_gt_set_freq(fd, gt, "max", stash_max[gt]);
> +		xe_gt_set_freq(fd, gt, "min", stash_min[gt]);
> +	}
> +	free(stash_min);
> +	free(stash_max);
> +}
> +
>   igt_main
>   {
>   	int fd, gt;
> @@ -482,6 +599,36 @@ igt_main
>   			disable_vfs(fd);
>   	}
>   
> +	igt_subtest_group {
> +		bool has_freq0_node, needs_freq_restore = false;
> +		uint32_t *stash_min, *stash_max;
> +
> +		igt_fixture {
> +			has_freq0_node = xe_sysfs_gt_has_node(fd, 0, "freq0");
> +		}
> +
> +		igt_describe("Validate PMU GT freq measured is within the tolerance");
> +		igt_subtest_with_dynamic("gt-frequency") {
> +			igt_skip_on(!has_freq0_node);
> +			stash_gt_freq(fd, &stash_min, &stash_max);
> +			needs_freq_restore = true;
> +			xe_for_each_gt(fd, gt) {
Since it's one test, i thought it could be something like this, to avoid 
subtest group

	int orig_min = xe_gt_get_freq(fd, gt, "min");
	int orig_max = xe_gt_get_freq(fd, gt, "max");> +			 
igt_dynamic_f("gt%u", gt)
> +				xe_for_each_engine(fd, eci) {
> +					if (gt == eci->gt_id) {
> +						test_gt_frequency(fd, eci);
> +						break;
> +					}
> +				}
		xe_gt_set_freq(fd, gt, "max", orig_max);
		xe_gt_set_freq(fd, gt, "min", orig_min);

But if there are additional tests planned
Reviewed-by: Riana Tauro <riana.tauro@intel.com>>

> +			}
> +		}
> +
> +		igt_fixture {
> +			if (needs_freq_restore)
> +				restore_gt_freq(fd, stash_min, stash_max);
> +		}
> +	}
> +
>   	igt_fixture {
>   		close(fd);
>   	}


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH i-g-t 2/2] tests/xe_pmu: Add frequency test
  2025-04-11  7:33   ` Riana Tauro
@ 2025-04-11 22:36     ` Belgaumkar, Vinay
  0 siblings, 0 replies; 14+ messages in thread
From: Belgaumkar, Vinay @ 2025-04-11 22:36 UTC (permalink / raw)
  To: Riana Tauro, intel-gfx, igt-dev
  Cc: Lucas De Marchi, Rodrigo Vivi, Kamil Konieczny


On 4/11/2025 12:33 AM, Riana Tauro wrote:
> Hi Vinay
>
> On 4/10/2025 7:03 AM, Vinay Belgaumkar wrote:
>> Add a basic test that uses PMU to read GT actual and requested
>> frequencies while running a workload.
>>
>> v2: Rebase and comments (Riana)
>> v3: Address review comments (Kamil and Riana)
>>
>> Cc: Lucas De Marchi <lucas.demarchi@intel.com>
>> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
>> Cc: Riana Tauro <riana.tauro@intel.com>
>> Cc: Kamil Konieczny <kamil.konieczny@linux.intel.com>
>> Signed-off-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
>> ---
>>   tests/intel/xe_pmu.c | 147 +++++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 147 insertions(+)
>>
>> diff --git a/tests/intel/xe_pmu.c b/tests/intel/xe_pmu.c
>> index 175bbf374..589c7cbde 100644
>> --- a/tests/intel/xe_pmu.c
>> +++ b/tests/intel/xe_pmu.c
>> @@ -376,6 +376,94 @@ static void test_gt_c6_idle(int xe, unsigned int 
>> gt)
>>       close(pmu_fd);
>>   }
>>   +/**
>> + * SUBTEST: gt-frequency
>> + * Description: Validate we can collect accurate frequency PMU stats
>> + *        while running a workload.
>> + */
>> +static void test_gt_frequency(int fd, struct 
>> drm_xe_engine_class_instance *eci)
>> +{
>> +    struct xe_cork *cork = NULL;
>> +    uint64_t end[2], start[2];
>> +    unsigned long config_rq_freq, config_act_freq;
>> +    double min[2], max[2];
>> +    uint32_t gt = eci->gt_id;
>> +    uint32_t orig_min = xe_gt_get_freq(fd, eci->gt_id, "min");
>> +    uint32_t orig_max = xe_gt_get_freq(fd, eci->gt_id, "max");
>> +    uint32_t vm;
>> +    int pmu_fd[2];
>> +
>> +    config_rq_freq = get_event_config(gt, NULL, 
>> "gt-requested-frequency");
>> +    pmu_fd[0] = open_group(fd, config_rq_freq, -1);
>> +
>> +    config_act_freq = get_event_config(gt, NULL, 
>> "gt-actual-frequency");
>> +    pmu_fd[1] = open_group(fd, config_act_freq, pmu_fd[0]);
>> +
>> +    vm = xe_vm_create(fd, 0, 0);
>> +
>> +    cork = xe_cork_create_opts(fd, eci, vm, 1, 1);
>> +    xe_cork_sync_start(fd, cork);
>> +
>> +    /*
>> +     * Set GPU to min frequency and read PMU counters.
>> +     */
>> +    igt_assert(xe_gt_set_freq(fd, gt, "max", orig_min) > 0);
>> +    igt_assert(xe_gt_get_freq(fd, gt, "max") == orig_min);
>> +
>> +    pmu_read_multi(pmu_fd[0], 2, start);
>> +    usleep(SLEEP_DURATION * USEC_PER_SEC);
>> +    pmu_read_multi(pmu_fd[0], 2, end);
>> +
>> +    min[0] = (end[0] - start[0]);
>> +    min[1] = (end[1] - start[1]);
>> +
>> +    /*
>> +     * Set GPU to max frequency and read PMU counters.
>> +     */
>> +    igt_assert(xe_gt_set_freq(fd, gt, "max", orig_max) > 0);
>> +    igt_assert(xe_gt_get_freq(fd, gt, "max") == orig_max);
>> +    igt_assert(xe_gt_set_freq(fd, gt, "min", orig_max) > 0);
>> +    igt_assert(xe_gt_get_freq(fd, gt, "min") == orig_max);
>> +
>> +    pmu_read_multi(pmu_fd[0], 2, start);
>> +    usleep(SLEEP_DURATION * USEC_PER_SEC);
>> +    pmu_read_multi(pmu_fd[0], 2, end);
>> +
>> +    max[0] = (end[0] - start[0]);
>> +    max[1] = (end[1] - start[1]);
>> +
>> +    xe_cork_sync_end(fd, cork);
>> +
>> +    /*
>> +     * Restore min/max.
>> +     */
>> +    igt_assert(xe_gt_set_freq(fd, gt, "min", orig_min) > 0);
>> +    igt_assert(xe_gt_get_freq(fd, gt, "min") == orig_min);
>> +
>> +    igt_info("Minimum frequency: requested %.1f, actual %.1f\n",
>> +         min[0], min[1]);
>> +    igt_info("Maximum frequency: requested %.1f, actual %.1f\n",
>> +         max[0], max[1]);
>> +
>> +    close(pmu_fd[0]);
>> +    close(pmu_fd[1]);
>> +
>> +    if (cork)
>> +        xe_cork_destroy(fd, cork);
>> +
>> +    xe_vm_destroy(fd, vm);
>> +
>> +    close(pmu_fd[0]);
>> +    close(pmu_fd[1]);
>> +
>> +    assert_within_epsilon(min[0], orig_min, tolerance);
>> +    /*
>> +     * On thermally throttled devices we cannot be sure maximum 
>> frequency
>> +     * can be reached so use larger tolerance downwards.
>> +     */
>> +    assert_within_epsilon_up_down(max[0], orig_max, tolerance, 0.15f);
>> +}
>> +
>>   static unsigned int enable_and_provision_vfs(int fd)
>>   {
>>       unsigned int gt, num_vfs;
>> @@ -427,6 +515,35 @@ static void disable_vfs(int fd)
>>                  "Failed to restore sriov_drivers_autoprobe value\n");
>>   }
>>   +static void stash_gt_freq(int fd, uint32_t **stash_min, uint32_t 
>> **stash_max)
>> +{
>> +    int num_gts, gt;
>> +
>> +    num_gts = xe_number_gt(fd);
>> +
>> +    *stash_min = (uint32_t *) malloc(sizeof(uint32_t) * num_gts);
>> +    *stash_max = (uint32_t *) malloc(sizeof(uint32_t) * num_gts);
>> +
>> +    igt_skip_on(*stash_min == NULL || *stash_max == NULL);
>> +
>> +    xe_for_each_gt(fd, gt) {
>> +        *stash_min[gt] = xe_gt_get_freq(fd, gt, "min");
>> +        *stash_max[gt] = xe_gt_get_freq(fd, gt, "max");
>> +    }
>> +}
>> +
>> +static void restore_gt_freq(int fd, uint32_t *stash_min, uint32_t 
>> *stash_max)
>> +{
>> +    int gt;
>> +
>> +    xe_for_each_gt(fd, gt) {
>> +        xe_gt_set_freq(fd, gt, "max", stash_max[gt]);
>> +        xe_gt_set_freq(fd, gt, "min", stash_min[gt]);
>> +    }
>> +    free(stash_min);
>> +    free(stash_max);
>> +}
>> +
>>   igt_main
>>   {
>>       int fd, gt;
>> @@ -482,6 +599,36 @@ igt_main
>>               disable_vfs(fd);
>>       }
>>   +    igt_subtest_group {
>> +        bool has_freq0_node, needs_freq_restore = false;
>> +        uint32_t *stash_min, *stash_max;
>> +
>> +        igt_fixture {
>> +            has_freq0_node = xe_sysfs_gt_has_node(fd, 0, "freq0");
>> +        }
>> +
>> +        igt_describe("Validate PMU GT freq measured is within the 
>> tolerance");
>> +        igt_subtest_with_dynamic("gt-frequency") {
>> +            igt_skip_on(!has_freq0_node);
>> +            stash_gt_freq(fd, &stash_min, &stash_max);
>> +            needs_freq_restore = true;
>> +            xe_for_each_gt(fd, gt) {
> Since it's one test, i thought it could be something like this, to 
> avoid subtest group
>
>     int orig_min = xe_gt_get_freq(fd, gt, "min");
>     int orig_max = xe_gt_get_freq(fd, gt, "max");> +             
> igt_dynamic_f("gt%u", gt)
>> +                xe_for_each_engine(fd, eci) {
>> +                    if (gt == eci->gt_id) {
>> +                        test_gt_frequency(fd, eci);
>> +                        break;
>> +                    }
>> +                }
>         xe_gt_set_freq(fd, gt, "max", orig_max);
>         xe_gt_set_freq(fd, gt, "min", orig_min);

Didn't have subtest group before before, but fixture was needed to 
ensure freq restore happens when the test asserts due to an error. I'd 
like to be able to add more subtests at a later date as well, so keeping 
as is.

Thanks,

Vinay.

>
> But if there are additional tests planned
> Reviewed-by: Riana Tauro <riana.tauro@intel.com>>
>
>> +            }
>> +        }
>> +
>> +        igt_fixture {
>> +            if (needs_freq_restore)
>> +                restore_gt_freq(fd, stash_min, stash_max);
>> +        }
>> +    }
>> +
>>       igt_fixture {
>>           close(fd);
>>       }
>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH i-g-t 2/2] tests/xe_pmu: Add frequency test
  2025-04-11 22:45 [PATCH i-g-t 0/2] Add PMU test for GT frequency Vinay Belgaumkar
@ 2025-04-11 22:46 ` Vinay Belgaumkar
  0 siblings, 0 replies; 14+ messages in thread
From: Vinay Belgaumkar @ 2025-04-11 22:46 UTC (permalink / raw)
  To: intel-gfx, igt-dev
  Cc: Vinay Belgaumkar, Lucas De Marchi, Rodrigo Vivi, Riana Tauro,
	Kamil Konieczny

Add a basic test that uses PMU to read GT actual and requested
frequencies while running a workload.

v2: Rebase and comments (Riana)
v3: Address review comments (Kamil and Riana)

Cc: Lucas De Marchi <lucas.demarchi@intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Riana Tauro <riana.tauro@intel.com>
Cc: Kamil Konieczny <kamil.konieczny@linux.intel.com>
Reviewed-by: Riana Tauro <riana.tauro@intel.com>
Signed-off-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
---
 tests/intel/xe_pmu.c | 147 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 147 insertions(+)

diff --git a/tests/intel/xe_pmu.c b/tests/intel/xe_pmu.c
index 175bbf374..589c7cbde 100644
--- a/tests/intel/xe_pmu.c
+++ b/tests/intel/xe_pmu.c
@@ -376,6 +376,94 @@ static void test_gt_c6_idle(int xe, unsigned int gt)
 	close(pmu_fd);
 }
 
+/**
+ * SUBTEST: gt-frequency
+ * Description: Validate we can collect accurate frequency PMU stats
+ *		while running a workload.
+ */
+static void test_gt_frequency(int fd, struct drm_xe_engine_class_instance *eci)
+{
+	struct xe_cork *cork = NULL;
+	uint64_t end[2], start[2];
+	unsigned long config_rq_freq, config_act_freq;
+	double min[2], max[2];
+	uint32_t gt = eci->gt_id;
+	uint32_t orig_min = xe_gt_get_freq(fd, eci->gt_id, "min");
+	uint32_t orig_max = xe_gt_get_freq(fd, eci->gt_id, "max");
+	uint32_t vm;
+	int pmu_fd[2];
+
+	config_rq_freq = get_event_config(gt, NULL, "gt-requested-frequency");
+	pmu_fd[0] = open_group(fd, config_rq_freq, -1);
+
+	config_act_freq = get_event_config(gt, NULL, "gt-actual-frequency");
+	pmu_fd[1] = open_group(fd, config_act_freq, pmu_fd[0]);
+
+	vm = xe_vm_create(fd, 0, 0);
+
+	cork = xe_cork_create_opts(fd, eci, vm, 1, 1);
+	xe_cork_sync_start(fd, cork);
+
+	/*
+	 * Set GPU to min frequency and read PMU counters.
+	 */
+	igt_assert(xe_gt_set_freq(fd, gt, "max", orig_min) > 0);
+	igt_assert(xe_gt_get_freq(fd, gt, "max") == orig_min);
+
+	pmu_read_multi(pmu_fd[0], 2, start);
+	usleep(SLEEP_DURATION * USEC_PER_SEC);
+	pmu_read_multi(pmu_fd[0], 2, end);
+
+	min[0] = (end[0] - start[0]);
+	min[1] = (end[1] - start[1]);
+
+	/*
+	 * Set GPU to max frequency and read PMU counters.
+	 */
+	igt_assert(xe_gt_set_freq(fd, gt, "max", orig_max) > 0);
+	igt_assert(xe_gt_get_freq(fd, gt, "max") == orig_max);
+	igt_assert(xe_gt_set_freq(fd, gt, "min", orig_max) > 0);
+	igt_assert(xe_gt_get_freq(fd, gt, "min") == orig_max);
+
+	pmu_read_multi(pmu_fd[0], 2, start);
+	usleep(SLEEP_DURATION * USEC_PER_SEC);
+	pmu_read_multi(pmu_fd[0], 2, end);
+
+	max[0] = (end[0] - start[0]);
+	max[1] = (end[1] - start[1]);
+
+	xe_cork_sync_end(fd, cork);
+
+	/*
+	 * Restore min/max.
+	 */
+	igt_assert(xe_gt_set_freq(fd, gt, "min", orig_min) > 0);
+	igt_assert(xe_gt_get_freq(fd, gt, "min") == orig_min);
+
+	igt_info("Minimum frequency: requested %.1f, actual %.1f\n",
+		 min[0], min[1]);
+	igt_info("Maximum frequency: requested %.1f, actual %.1f\n",
+		 max[0], max[1]);
+
+	close(pmu_fd[0]);
+	close(pmu_fd[1]);
+
+	if (cork)
+		xe_cork_destroy(fd, cork);
+
+	xe_vm_destroy(fd, vm);
+
+	close(pmu_fd[0]);
+	close(pmu_fd[1]);
+
+	assert_within_epsilon(min[0], orig_min, tolerance);
+	/*
+	 * On thermally throttled devices we cannot be sure maximum frequency
+	 * can be reached so use larger tolerance downwards.
+	 */
+	assert_within_epsilon_up_down(max[0], orig_max, tolerance, 0.15f);
+}
+
 static unsigned int enable_and_provision_vfs(int fd)
 {
 	unsigned int gt, num_vfs;
@@ -427,6 +515,35 @@ static void disable_vfs(int fd)
 		       "Failed to restore sriov_drivers_autoprobe value\n");
 }
 
+static void stash_gt_freq(int fd, uint32_t **stash_min, uint32_t **stash_max)
+{
+	int num_gts, gt;
+
+	num_gts = xe_number_gt(fd);
+
+	*stash_min = (uint32_t *) malloc(sizeof(uint32_t) * num_gts);
+	*stash_max = (uint32_t *) malloc(sizeof(uint32_t) * num_gts);
+
+	igt_skip_on(*stash_min == NULL || *stash_max == NULL);
+
+	xe_for_each_gt(fd, gt) {
+		*stash_min[gt] = xe_gt_get_freq(fd, gt, "min");
+		*stash_max[gt] = xe_gt_get_freq(fd, gt, "max");
+	}
+}
+
+static void restore_gt_freq(int fd, uint32_t *stash_min, uint32_t *stash_max)
+{
+	int gt;
+
+	xe_for_each_gt(fd, gt) {
+		xe_gt_set_freq(fd, gt, "max", stash_max[gt]);
+		xe_gt_set_freq(fd, gt, "min", stash_min[gt]);
+	}
+	free(stash_min);
+	free(stash_max);
+}
+
 igt_main
 {
 	int fd, gt;
@@ -482,6 +599,36 @@ igt_main
 			disable_vfs(fd);
 	}
 
+	igt_subtest_group {
+		bool has_freq0_node, needs_freq_restore = false;
+		uint32_t *stash_min, *stash_max;
+
+		igt_fixture {
+			has_freq0_node = xe_sysfs_gt_has_node(fd, 0, "freq0");
+		}
+
+		igt_describe("Validate PMU GT freq measured is within the tolerance");
+		igt_subtest_with_dynamic("gt-frequency") {
+			igt_skip_on(!has_freq0_node);
+			stash_gt_freq(fd, &stash_min, &stash_max);
+			needs_freq_restore = true;
+			xe_for_each_gt(fd, gt) {
+				igt_dynamic_f("gt%u", gt)
+				xe_for_each_engine(fd, eci) {
+					if (gt == eci->gt_id) {
+						test_gt_frequency(fd, eci);
+						break;
+					}
+				}
+			}
+		}
+
+		igt_fixture {
+			if (needs_freq_restore)
+				restore_gt_freq(fd, stash_min, stash_max);
+		}
+	}
+
 	igt_fixture {
 		close(fd);
 	}
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2025-04-11 22:46 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-04-02  1:39 [PATCH i-g-t 0/2] Add PMU tests for GT frequency Vinay Belgaumkar
2025-04-02  1:39 ` [PATCH i-g-t 1/2] lib/xe_gt: Move get/set GT freq utils to lib Vinay Belgaumkar
2025-04-03 10:50   ` Riana Tauro
2025-04-02  1:39 ` [PATCH i-g-t 2/2] tests/xe_pmu: Add frequency test Vinay Belgaumkar
2025-04-03 10:39   ` Riana Tauro
  -- strict thread matches above, loose matches on Subject: below --
2025-04-07 23:44 [PATCH i-g-t 0/2] Add PMU test for GT frequency Vinay Belgaumkar
2025-04-07 23:44 ` [PATCH i-g-t 2/2] tests/xe_pmu: Add frequency test Vinay Belgaumkar
2025-04-09  9:58   ` Riana Tauro
2025-04-09 11:06     ` Kamil Konieczny
2025-04-10  1:26       ` Belgaumkar, Vinay
2025-04-10  1:31     ` Belgaumkar, Vinay
2025-04-10  1:33 [PATCH i-g-t 0/2] Add PMU test for GT frequency Vinay Belgaumkar
2025-04-10  1:33 ` [PATCH i-g-t 2/2] tests/xe_pmu: Add frequency test Vinay Belgaumkar
2025-04-11  7:33   ` Riana Tauro
2025-04-11 22:36     ` Belgaumkar, Vinay
2025-04-11 22:45 [PATCH i-g-t 0/2] Add PMU test for GT frequency Vinay Belgaumkar
2025-04-11 22:46 ` [PATCH i-g-t 2/2] tests/xe_pmu: Add frequency test Vinay Belgaumkar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox