* [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 ` Vinay Belgaumkar
2025-04-03 10:39 ` Riana Tauro
0 siblings, 1 reply; 15+ 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] 15+ 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; 15+ 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] 15+ messages in thread
* [PATCH i-g-t 0/2] Add PMU test for GT frequency
@ 2025-04-07 23:44 Vinay Belgaumkar
2025-04-07 23:44 ` [PATCH i-g-t 1/2] lib/xe_gt: Move get/set GT freq utils to lib Vinay Belgaumkar
2025-04-07 23:44 ` [PATCH i-g-t 2/2] tests/xe_pmu: Add frequency test Vinay Belgaumkar
0 siblings, 2 replies; 15+ messages in thread
From: Vinay Belgaumkar @ 2025-04-07 23:44 UTC (permalink / raw)
To: intel-gfx, igt-dev; +Cc: Vinay Belgaumkar, Riana Tauro
This will validate PMU frequency attributes that have been added
to the driver.
Cc: Riana Tauro <riana.tauro@intel.com>>
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 | 128 +++++++++++++++++++++++++++++-
4 files changed, 252 insertions(+), 101 deletions(-)
--
2.38.1
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH i-g-t 1/2] lib/xe_gt: Move get/set GT freq utils to lib
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 11:13 ` Kamil Konieczny
2025-04-07 23:44 ` [PATCH i-g-t 2/2] tests/xe_pmu: Add frequency test Vinay Belgaumkar
1 sibling, 1 reply; 15+ messages in thread
From: Vinay Belgaumkar @ 2025-04-07 23:44 UTC (permalink / raw)
To: intel-gfx, igt-dev; +Cc: Vinay Belgaumkar, Riana Tauro
Add utils to get/set GT frequency attributes. These ar per GT
and exposed via sysfs already.
Reviewed-by: Riana Tauro <riana.tauro@intel.com>
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..bd6d1800b 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/rp0/rpn/rpe GT frequencies
+ *
+ * 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] 15+ 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 ` [PATCH i-g-t 1/2] lib/xe_gt: Move get/set GT freq utils to lib Vinay Belgaumkar
@ 2025-04-07 23:44 ` Vinay Belgaumkar
2025-04-09 9:58 ` Riana Tauro
1 sibling, 1 reply; 15+ 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] 15+ 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; 15+ 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] 15+ 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; 15+ 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] 15+ messages in thread
* Re: [PATCH i-g-t 1/2] lib/xe_gt: Move get/set GT freq utils to lib
2025-04-07 23:44 ` [PATCH i-g-t 1/2] lib/xe_gt: Move get/set GT freq utils to lib Vinay Belgaumkar
@ 2025-04-09 11:13 ` Kamil Konieczny
2025-04-10 1:24 ` Belgaumkar, Vinay
0 siblings, 1 reply; 15+ messages in thread
From: Kamil Konieczny @ 2025-04-09 11:13 UTC (permalink / raw)
To: Vinay Belgaumkar; +Cc: intel-gfx, igt-dev, Riana Tauro
Hi Vinay,
On 2025-04-07 at 16:44:05 -0700, Vinay Belgaumkar wrote:
> Add utils to get/set GT frequency attributes. These ar per GT
s/ar/are/
> and exposed via sysfs already.
>
> Reviewed-by: Riana Tauro <riana.tauro@intel.com>
> 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..bd6d1800b 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
Add a note about an assert in case of unsuccesfull open.
> + *
> + * 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/rp0/rpn/rpe GT frequencies
Add a note about an assert in case of unsuccesfull open.
> + *
> + * 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"
While it is here could you move both includes 'lib/'
after 'igt_sysfs.h'? So they will be sorted.
Regards,
Kamil
> #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 [flat|nested] 15+ messages in thread
* Re: [PATCH i-g-t 1/2] lib/xe_gt: Move get/set GT freq utils to lib
2025-04-09 11:13 ` Kamil Konieczny
@ 2025-04-10 1:24 ` Belgaumkar, Vinay
0 siblings, 0 replies; 15+ messages in thread
From: Belgaumkar, Vinay @ 2025-04-10 1:24 UTC (permalink / raw)
To: Kamil Konieczny, intel-gfx, igt-dev, Riana Tauro
On 4/9/2025 4:13 AM, Kamil Konieczny wrote:
> Hi Vinay,
> On 2025-04-07 at 16:44:05 -0700, Vinay Belgaumkar wrote:
>> Add utils to get/set GT frequency attributes. These ar per GT
> s/ar/are/
ok.
>
>> and exposed via sysfs already.
>>
>> Reviewed-by: Riana Tauro <riana.tauro@intel.com>
>> 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..bd6d1800b 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
> Add a note about an assert in case of unsuccesfull open.
ok.
>
>> + *
>> + * 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/rp0/rpn/rpe GT frequencies
> Add a note about an assert in case of unsuccesfull open.
ok.
>
>> + *
>> + * 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"
> While it is here could you move both includes 'lib/'
> after 'igt_sysfs.h'? So they will be sorted.
sure,
Thanks,
Vinay.
>
> Regards,
> Kamil
>
>> #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 [flat|nested] 15+ 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; 15+ 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] 15+ 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; 15+ 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] 15+ 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; 15+ 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] 15+ 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; 15+ 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] 15+ 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; 15+ 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] 15+ 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; 15+ 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] 15+ messages in thread
end of thread, other threads:[~2025-04-11 22:46 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 1/2] lib/xe_gt: Move get/set GT freq utils to lib Vinay Belgaumkar
2025-04-09 11:13 ` Kamil Konieczny
2025-04-10 1:24 ` Belgaumkar, Vinay
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
-- strict thread matches above, loose matches on Subject: below --
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
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-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 2/2] tests/xe_pmu: Add frequency test Vinay Belgaumkar
2025-04-03 10:39 ` Riana Tauro
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox