[PATCH i-g-t v4 2/3] tests/intel/xe_pmu: Add PMU test to validate engine activity stats
Riana Tauro
riana.tauro at intel.com
Tue Feb 25 07:13:10 UTC 2025
Add a test to validate engine activity by reading PMU counters
(engine-active-ticks, engine-total-ticks) when running
workload on every engine
v2: rename busy to active
add assert to format events (Umesh)
add a helper macro
v3: initialize config (Umesh)
Signed-off-by: Riana Tauro <riana.tauro at intel.com>
Reviewed-by: Umesh Nerlige Ramappa <umesh.nerlige.ramappa at intel.com>
---
tests/intel/xe_pmu.c | 130 ++++++++++++++++++++++++++++++++++++-------
1 file changed, 110 insertions(+), 20 deletions(-)
diff --git a/tests/intel/xe_pmu.c b/tests/intel/xe_pmu.c
index d408d0f99..692cc986f 100644
--- a/tests/intel/xe_pmu.c
+++ b/tests/intel/xe_pmu.c
@@ -12,24 +12,23 @@
* Test category: Functional tests
*/
-#include <fcntl.h>
-#include <limits.h>
-#include <time.h>
-#include <errno.h>
-#include <dirent.h>
-#include <string.h>
-#include <sys/time.h>
-
#include "igt.h"
-#include "igt_device.h"
#include "igt_perf.h"
#include "igt_sysfs.h"
#include "xe/xe_gt.h"
+#include "xe/xe_ioctl.h"
+#include "xe/xe_spin.h"
#define SLEEP_DURATION 2 /* in seconds */
const double tolerance = 0.1;
+#define test_each_engine(test, fd, hwe) \
+ igt_subtest_with_dynamic(test) \
+ xe_for_each_engine(fd, hwe) \
+ igt_dynamic_f("engine-%s%d", xe_engine_class_string(hwe->engine_class), \
+ hwe->engine_instance)
+
static int open_pmu(int xe, uint64_t config)
{
int fd;
@@ -41,6 +40,17 @@ static int open_pmu(int xe, uint64_t config)
return fd;
}
+static int open_group(int xe, uint64_t config, int group)
+{
+ int fd;
+
+ fd = igt_perf_open_group(xe_perf_type_id(xe), config, group);
+ igt_skip_on(fd < 0 && errno == ENODEV);
+ igt_assert(fd >= 0);
+
+ return fd;
+}
+
static uint64_t __pmu_read_single(int fd, uint64_t *ts)
{
uint64_t data[2];
@@ -52,6 +62,19 @@ static uint64_t __pmu_read_single(int fd, uint64_t *ts)
return data[0];
}
+static uint64_t pmu_read_multi(int fd, unsigned int num, uint64_t *val)
+{
+ uint64_t buf[2 + num];
+ unsigned int i;
+
+ igt_assert_eq(read(fd, buf, sizeof(buf)), sizeof(buf));
+
+ for (i = 0; i < num; i++)
+ val[i] = buf[2 + i];
+
+ return buf[1];
+}
+
static unsigned long read_idle_residency(int fd, int gt)
{
unsigned long residency = 0;
@@ -65,23 +88,86 @@ static unsigned long read_idle_residency(int fd, int gt)
return residency;
}
-static uint64_t get_event_config(int xe, unsigned int gt, char *event)
+static uint64_t add_format_config(const char *xe_device, const char *format, uint64_t val)
{
int ret;
- char xe_device[100];
- uint64_t pmu_config;
uint32_t shift;
+ uint64_t config;
+
+ ret = perf_event_format(xe_device, format, &shift);
+ igt_assert(ret >= 0);
+ config = val << shift;
+
+ return config;
+}
+
+static uint64_t get_event_config(int xe, unsigned int gt, struct drm_xe_engine_class_instance *eci,
+ const char *event)
+{
+ char xe_device[100];
+ uint64_t pmu_config = 0;
+ int ret;
xe_perf_device(xe, xe_device, sizeof(xe_device));
ret = perf_event_config(xe_device, event, &pmu_config);
igt_assert(ret >= 0);
- ret = perf_event_format(xe_device, "gt", &shift);
- igt_assert(ret >= 0);
- pmu_config |= (uint64_t)gt << shift;
+ pmu_config |= add_format_config(xe_device, "gt", gt);
+
+ if (eci) {
+ pmu_config |= add_format_config(xe_device, "engine_class", eci->engine_class);
+ pmu_config |= add_format_config(xe_device, "engine_instance", eci->engine_instance);
+ }
return pmu_config;
}
+/**
+ * SUBTEST: engine-activity-load
+ * Description: Test to validate engine activity stats by running a workload and
+ * reading engine active ticks and engine total ticks PMU counters
+ */
+static void engine_activity(int fd, struct drm_xe_engine_class_instance *eci)
+{
+ uint64_t config, engine_active_ticks, engine_total_ticks, before[2], after[2];
+ struct xe_cork *cork = NULL;
+ uint32_t vm;
+ int pmu_fd[2];
+
+ config = get_event_config(fd, eci->gt_id, eci, "engine-active-ticks");
+ pmu_fd[0] = open_group(fd, config, -1);
+
+ config = get_event_config(fd, eci->gt_id, eci, "engine-total-ticks");
+ pmu_fd[1] = open_group(fd, config, 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);
+
+ pmu_read_multi(pmu_fd[0], 2, before);
+ usleep(SLEEP_DURATION * USEC_PER_SEC);
+ pmu_read_multi(pmu_fd[0], 2, after);
+
+ xe_cork_sync_end(fd, cork);
+
+ engine_active_ticks = after[0] - before[0];
+ engine_total_ticks = after[1] - before[1];
+
+ igt_debug("Engine active ticks: after %ld, before %ld delta %ld\n", after[0], before[0],
+ engine_active_ticks);
+ igt_debug("Engine total ticks: after %ld, before %ld delta %ld\n", after[1], before[1],
+ engine_total_ticks);
+
+ if (cork)
+ xe_cork_destroy(fd, cork);
+
+ xe_vm_destroy(fd, vm);
+
+ close(pmu_fd[0]);
+ close(pmu_fd[1]);
+
+ assert_within_epsilon(engine_active_ticks, engine_total_ticks, tolerance);
+}
+
/**
* SUBTEST: gt-c6-idle
* Description: Basic residency test to validate idle residency
@@ -91,14 +177,12 @@ static void test_gt_c6_idle(int xe, unsigned int gt)
{
int pmu_fd;
uint64_t pmu_config;
- char event[100];
uint64_t ts[2];
unsigned long slept, start, end;
uint64_t val;
/* Get the PMU config for the gt-c6 event */
- sprintf(event, "gt-c6-residency");
- pmu_config = get_event_config(xe, gt, event);
+ pmu_config = get_event_config(xe, gt, NULL, "gt-c6-residency");
pmu_fd = open_pmu(xe, pmu_config);
@@ -125,16 +209,22 @@ static void test_gt_c6_idle(int xe, unsigned int gt)
igt_main
{
int fd, gt;
+ struct drm_xe_engine_class_instance *eci;
igt_fixture {
fd = drm_open_driver(DRIVER_XE);
- igt_require(!IS_PONTEVECCHIO(xe_dev_id(fd)));
}
igt_describe("Validate PMU gt-c6 residency counters when idle");
- igt_subtest("gt-c6-idle")
+ igt_subtest("gt-c6-idle") {
+ igt_require(!IS_PONTEVECCHIO(xe_dev_id(fd)));
xe_for_each_gt(fd, gt)
test_gt_c6_idle(fd, gt);
+ }
+
+ igt_describe("Validate engine activity with workload");
+ test_each_engine("engine-activity-load", fd, eci)
+ engine_activity(fd, eci);
igt_fixture {
close(fd);
--
2.47.1
More information about the igt-dev
mailing list