[PATCH i-g-t v7] tests/intel/xe_compute: Add Compute workload Scheduling and Display EU busyness

nishit.sharma at intel.com nishit.sharma at intel.com
Tue Jul 8 06:14:35 UTC 2025


From: Nishit Sharma <nishit.sharma at intel.com>

Adds compute workload scheduling and execution on multi-ccs available.
This also adds logic to show EU busyness information on console while workload is running
on multiple CCS engine instances.

Signed-off-by: Nishit Sharma <nishit.sharma at intel.com>
---
 lib/intel_compute.c      |  34 ++-
 lib/intel_compute.h      |   2 +
 tests/intel/xe_compute.c | 599 ++++++++++++++++++++++++++++++++++++++-
 tests/meson.build        |   1 +
 4 files changed, 629 insertions(+), 7 deletions(-)

diff --git a/lib/intel_compute.c b/lib/intel_compute.c
index 147dd2916..e1685788c 100644
--- a/lib/intel_compute.c
+++ b/lib/intel_compute.c
@@ -255,8 +255,14 @@ static void bo_execenv_bind(struct bo_execenv *execenv,
 				break;
 			}
 
-			bo_dict[i].handle = xe_bo_create(fd, execenv->vm, bo_dict[i].size,
-							 placement, flags);
+			if (!execenv->user)
+				bo_dict[i].handle = xe_bo_create(fd, execenv->vm, bo_dict[i].size,
+								 placement, flags);
+			else if (execenv->user)
+				bo_dict[i].handle = xe_bo_create_caching(fd, execenv->vm,
+									 bo_dict[i].size,
+									 placement, flags,
+									 DRM_XE_GEM_CPU_CACHING_WC);
 			bo_dict[i].data = xe_bo_map(fd, bo_dict[i].handle, bo_dict[i].size);
 			xe_vm_bind_async(fd, vm, 0, bo_dict[i].handle, 0, bo_dict[i].addr,
 					 bo_dict[i].size, &sync, 1);
@@ -1849,10 +1855,26 @@ static void xe2lpg_compute_exec(int fd, const unsigned char *kernel,
 				    OFFSET_KERNEL, 0, false,
 				    execenv.array_size);
 
-	bo_execenv_exec(&execenv, ADDR_BATCH);
-
-	if (!user || (user && !user->skip_results_check))
-		bo_check_square(input_data, output_data, execenv.array_size);
+	if (user && user->loop_kernel_duration) {
+		bo_execenv_exec_async(&execenv, ADDR_BATCH);
+		igt_measured_usleep(user->loop_kernel_duration);
+		((int *)bo_dict[4].data)[0] = MAGIC_LOOP_STOP;
+		bo_execenv_sync(&execenv);
+		user->skip_results_check = 1;
+	} else
+		bo_execenv_exec(&execenv, ADDR_BATCH);
+
+	for (int i = 0; i < execenv.array_size; i++) {
+		float input = input_data[i];
+		float output = output_data[i];
+		float expected_output = input * input;
+
+		if (output != expected_output)
+			igt_debug("[%4d] input:%f output:%f expected_output:%f\n",
+					i, input, output, expected_output);
+		if (!user || (user && !user->skip_results_check))
+			igt_assert_eq_double(output, expected_output);
+	}
 
 	bo_execenv_unbind(&execenv, bo_dict, entries);
 	bo_execenv_destroy(&execenv);
diff --git a/lib/intel_compute.h b/lib/intel_compute.h
index 412791d07..19977933f 100644
--- a/lib/intel_compute.h
+++ b/lib/intel_compute.h
@@ -63,6 +63,8 @@ struct user_execenv {
 	uint64_t input_addr;
 	/** @output_addr: override default address of the output array if provided */
 	uint64_t output_addr;
+	/** @loop_kernel_duration: duration till kernel should execute in gpu **/
+	uint32_t loop_kernel_duration;
 };
 
 enum execenv_alloc_prefs {
diff --git a/tests/intel/xe_compute.c b/tests/intel/xe_compute.c
index 5e9140902..7b90e2779 100644
--- a/tests/intel/xe_compute.c
+++ b/tests/intel/xe_compute.c
@@ -12,6 +12,7 @@
  */
 
 #include <string.h>
+#include <sys/ioctl.h>
 
 #include "igt.h"
 #include "igt_sysfs.h"
@@ -19,6 +20,45 @@
 #include "xe/xe_ioctl.h"
 #include "xe/xe_query.h"
 
+#include "igt_device.h"
+#include "tools/gputop/xe_gputop.h"
+#include "igt_drm_clients.h"
+
+/**
+ * Number of supported drivers needs to be adjusted as per the length of
+ * the drivers[] array.
+ */
+#define	NUM_DRIVER	1
+#define	LOOP_DURATION	(1000000ull)
+#define	engine_ptr(engines, n)	(&(engines)->engine + (n))
+#define NS_SLEEP	(1000000ull)
+
+enum utilization_type {
+	UTILIZATION_TYPE_ENGINE_TIME,
+	UTILIZATION_TYPE_TOTAL_CYCLES,
+};
+
+bool workload_sched;
+
+pthread_barrier_t barrier;
+struct thread_data {
+	pthread_t thread;
+	pthread_mutex_t *mutex;
+	pthread_cond_t *cond;
+	int class;
+	int fd;
+	int gt;
+	struct user_execenv *execenv;
+	struct drm_xe_engine_class_instance *eci;
+	bool *go;
+};
+
+struct xe_gpu_info {
+	char *pmu_device;
+	struct igt_device_card *card;
+	struct xe_pmu_device *eng_obj;
+};
+
 static int gt_sysfs_open(int gt)
 {
 	int fd, gt_fd;
@@ -203,12 +243,565 @@ test_compute_square(int fd)
 		      "GPU not supported\n");
 }
 
+static void
+*intel_compute_thread(void *data)
+{
+	struct thread_data *t = (struct thread_data *)data;
+
+	usleep(3 * NS_SLEEP);
+
+	igt_info("Compute kernel executing on engine class :%s instance :%d gt: GT-%d\n",
+			xe_engine_class_string(t->eci->engine_class), t->eci->engine_instance,
+			t->eci->gt_id);
+
+	pthread_mutex_lock(t->mutex);
+	while (*t->go == 0)
+		pthread_cond_wait(t->cond, t->mutex);
+	pthread_mutex_unlock(t->mutex);
+
+	workload_sched = true;
+	igt_assert_f(xe_run_intel_compute_kernel_on_engine(t->fd,
+				t->eci,
+				t->execenv,
+				EXECENV_PREF_VRAM_IF_POSSIBLE),
+			"Unable to run compute kernel successfully\n");
+	workload_sched = false;
+	return NULL;
+}
+
+static volatile bool stop_top;
+
+static int
+pmu_format_shift(int xe, const char *name,
+		 struct xe_gpu_info *obj)
+{
+	uint32_t start;
+	int format;
+
+	format = perf_event_format(obj->pmu_device, name, &start);
+	if (format)
+		return 0;
+
+	return start;
+}
+
+static const char
+*class_display_name(unsigned int class)
+{
+	switch (class) {
+	case DRM_XE_ENGINE_CLASS_RENDER:
+		return "Render/3D";
+	case DRM_XE_ENGINE_CLASS_COPY:
+		return "Blitter";
+	case DRM_XE_ENGINE_CLASS_VIDEO_DECODE:
+		return "Video";
+	case DRM_XE_ENGINE_CLASS_VIDEO_ENHANCE:
+		return "VideoEnhance";
+	case DRM_XE_ENGINE_CLASS_COMPUTE:
+		return "Compute";
+	default:
+		return "[unknown]";
+	}
+}
+
+static void
+*xe_init_engines(const void *obj)
+{
+	struct igt_device_card *card = ((struct xe_gpu_info *)obj)->card;
+	struct xe_pmu_device *engines;
+	struct drm_xe_engine *ccs_engine;
+	int ret = 0, engine_count = 0;
+	struct drm_xe_engine_class_instance *hwe;
+	int card_fd;
+	uint64_t engine_class, engine_instance, gt_shift;
+	uint64_t engine_active_config, engine_total_config;
+
+	if (!card || !strlen(card->card) || !strlen(card->render))
+		return NULL;
+
+	if (strlen(card->card)) {
+		card_fd = igt_open_card(card);
+	} else if (strlen(card->render)) {
+		card_fd = igt_open_render(card);
+	} else {
+		fprintf(stderr, "Failed to detect device!\n");
+		return NULL;
+	}
+	xe_device_get(card_fd);
+
+	xe_for_each_engine(card_fd, hwe) {
+		ccs_engine = xe_find_engine_by_class(card_fd, DRM_XE_ENGINE_CLASS_COMPUTE);
+		if (ccs_engine)
+			engine_count++;
+	}
+
+	engines = calloc(1, sizeof(struct xe_pmu_device) +
+			engine_count * sizeof(struct xe_engine));
+	if (!engines)
+		return NULL;
+
+	engines->num_engines = 0;
+	engines->device = ((struct xe_gpu_info *)obj)->pmu_device;
+	gt_shift = pmu_format_shift(card_fd, "gt", (struct xe_gpu_info *)obj);
+	engine_class = pmu_format_shift(card_fd, "engine_class", (struct xe_gpu_info *)obj);
+	engine_instance = pmu_format_shift(card_fd, "engine_instance", (struct xe_gpu_info *)obj);
+	ret = perf_event_config(((struct xe_gpu_info *)obj)->pmu_device,
+			"engine-active-ticks",
+			&engine_active_config);
+	if (ret < 0)
+		return NULL;
+	ret = perf_event_config(((struct xe_gpu_info *)obj)->pmu_device,
+			"engine-total-ticks",
+			&engine_total_config);
+	if (ret < 0)
+		return NULL;
+	xe_for_each_engine(card_fd, hwe) {
+		if (hwe->engine_class == DRM_XE_ENGINE_CLASS_COMPUTE) {
+			uint64_t  param_config;
+			struct xe_engine *engine;
+
+			engine = engine_ptr(engines, engines->num_engines);
+			param_config = (uint64_t)hwe->gt_id << gt_shift | hwe->engine_class << engine_class
+				| hwe->engine_instance << engine_instance;
+			engine->drm_xe_engine = *hwe;
+			engine->engine_active_ticks.config = engine_active_config | param_config;
+			engine->engine_total_ticks.config = engine_total_config | param_config;
+
+			if (engine->engine_active_ticks.config == -1 ||
+					engine->engine_total_ticks.config == -1) {
+				ret = ENOENT;
+				break;
+			}
+
+			ret = asprintf(&engine->display_name, "%s/%u",
+					class_display_name(engine->drm_xe_engine.engine_class),
+					engine->drm_xe_engine.engine_instance);
+
+			if (ret <= 0) {
+				ret = errno;
+				break;
+			}
+
+			engines->num_engines++;
+		}
+	}
+
+	if (!ret) {
+		errno = ret;
+		return NULL;
+	}
+
+	((struct xe_gpu_info *)obj)->eng_obj = engines;
+
+	return engines;
+}
+
+static int
+_open_pmu(uint64_t type, unsigned int *cnt,
+	  struct xe_pmu_counter *pmu, int *fd)
+{
+	int fd__ = igt_perf_open_group(type, pmu->config, *fd);
+
+	if (fd__ >= 0) {
+		if (*fd == -1)
+			*fd = fd__;
+		pmu->present = true;
+		pmu->idx = (*cnt)++;
+		pmu->fd = fd__;
+	}
+
+	return fd__;
+}
+
+static int xe_gpu_pmu_init(const void *obj)
+{
+	struct xe_pmu_device *engines = ((struct xe_gpu_info *)obj)->eng_obj;
+	unsigned int i;
+	int fd;
+	struct xe_engine *engine;
+	uint64_t type = igt_perf_type_id(engines->device);
+
+	engines->fd = -1;
+	engines->num_counters = 0;
+
+	for (i = 0; i < engines->num_engines; i++) {
+		engine = engine_ptr(engines, i);
+		fd = _open_pmu(type, &engines->num_counters, &engine->engine_active_ticks,
+				&engines->fd);
+		if (fd < 0)
+			return -1;
+		fd = _open_pmu(type, &engines->num_counters, &engine->engine_total_ticks,
+				&engines->fd);
+		if (fd < 0)
+			return -1;
+	}
+	return 0;
+}
+
+static void
+eu_util_free(struct xe_gpu_info *gpu_ptr)
+{
+	struct xe_engine *eng;
+	struct xe_pmu_counter pmu;
+
+	igt_info("EU cleanup process\n");
+
+	if (gpu_ptr->card)
+		free(gpu_ptr->card);
+
+	if (gpu_ptr->eng_obj) {
+		for (int j = 0; j < ((struct xe_pmu_device *)gpu_ptr->eng_obj)->num_engines ; j++) {
+			eng = engine_ptr((struct xe_pmu_device *)(gpu_ptr)->eng_obj, j);
+			if (eng->display_name)
+				free(eng->display_name);
+
+			pmu = eng->engine_active_ticks;
+			if (pmu.present)
+				close(pmu.fd);
+
+			pmu = eng->engine_total_ticks;
+			if (pmu.present)
+				close(pmu.fd);
+		}
+		free(gpu_ptr->eng_obj);
+	}
+	if (gpu_ptr->pmu_device)
+		free(gpu_ptr->pmu_device);
+}
+
+static char
+*pmu_name(struct igt_device_card *card)
+{
+	int card_fd;
+	char device[30];
+	char *path;
+
+	if (strlen(card->card))
+		card_fd = igt_open_card(card);
+	else if (strlen(card->render))
+		card_fd = igt_open_render(card);
+
+	if (card_fd == -1)
+		return NULL;
+
+	xe_perf_device(card_fd, device, sizeof(device));
+	path = strdup(device);
+	close(card_fd);
+	return path;
+}
+
+static struct xe_gpu_info *
+xe_device_match(const char *filter)
+{
+	struct igt_device_card card;
+	struct xe_gpu_info *gpu_ptr =  NULL;
+
+	if (!igt_device_card_match(filter, &card)) {
+		igt_info("No device found for the filter\n\n");
+		return NULL;
+	}
+
+	gpu_ptr = (struct xe_gpu_info *)malloc(sizeof(struct xe_gpu_info));
+	igt_assert(gpu_ptr);
+
+	gpu_ptr->pmu_device = pmu_name(&card);
+	if (!gpu_ptr->pmu_device) {
+		fprintf(stderr, "%s : pmu_device path returned NULL", card.pci_slot_name);
+		exit(EXIT_FAILURE);
+	}
+	gpu_ptr->card = &card;
+	return gpu_ptr;
+}
+
+static uint64_t
+pmu_read_multi(int fd, unsigned int num, uint64_t *val)
+{
+	uint64_t buf[2 + num];
+	unsigned int i;
+	ssize_t len;
+
+	memset(buf, 0, sizeof(buf));
+
+	len = read(fd, buf, sizeof(buf));
+	assert(len == sizeof(buf));
+
+	for (i = 0; i < num; i++)
+		val[i] = buf[2 + i];
+
+	return buf[1];
+}
+
+static void
+__update_sample(struct xe_pmu_counter *counter, uint64_t val)
+{
+	counter->val.prev = counter->val.cur;
+	counter->val.cur = val;
+}
+
+static void
+update_sample(struct xe_pmu_counter *counter, uint64_t *val)
+{
+	if (counter->present)
+		__update_sample(counter, val[counter->idx]);
+}
+
+static void xe_pmu_device_sample(const void *obj)
+{
+	struct xe_pmu_device *engines = ((struct xe_gpu_info *)obj)->eng_obj;
+	const int num_val = engines->num_counters;
+	uint64_t val[2 + num_val];
+	unsigned int i;
+
+	pmu_read_multi(engines->fd, num_val, val);
+
+	for (i = 0; i < engines->num_engines; i++) {
+		struct xe_engine *engine = engine_ptr(engines, i);
+
+		update_sample(&engine->engine_active_ticks, val);
+		update_sample(&engine->engine_total_ticks, val);
+	}
+}
+
+static double
+pmu_active_percentage(struct xe_engine *engine)
+{
+	double pmu_active_ticks = engine->engine_active_ticks.val.cur -
+		engine->engine_active_ticks.val.prev;
+	double pmu_total_ticks = engine->engine_total_ticks.val.cur -
+		engine->engine_total_ticks.val.prev;
+	double percentage;
+
+	percentage = (pmu_active_ticks * 100) / pmu_total_ticks;
+	return percentage;
+}
+
+static void
+print_engine_perc(struct xe_pmu_device *engines, unsigned int i)
+{
+	struct xe_engine *engine = engine_ptr(engines, i);
+	double percentage = pmu_active_percentage(engine);
+
+	igt_assert(engines);
+	if (engine->drm_xe_engine.engine_class == DRM_XE_ENGINE_CLASS_COMPUTE && !workload_sched) {
+		igt_info("Engine_instance :%d EU busyness :%5.1f\n", engine->drm_xe_engine.engine_instance, percentage);
+		if (!percentage)
+			igt_info("No workload scheduled, BU busyness :%5.1f expected\n", percentage);
+		else
+			igt_info("Workload scheduled, BU busyness :%5.1f expected\n", percentage);
+	} else if (engine->drm_xe_engine.engine_class == DRM_XE_ENGINE_CLASS_COMPUTE && workload_sched) {
+		igt_info("Engine_instance :%d EU busyness :%5.1f\n", engine->drm_xe_engine.engine_instance, percentage);
+		if (!percentage)
+			igt_info("No workload scheduled, BU busyness :%5.1f expected\n", percentage);
+		else
+			igt_info("Workload scheduled, BU busyness :%5.1f expected\n", percentage);
+	}
+
+	printf("\n");
+}
+
+static void xe_print_perc(const void *obj)
+{
+	struct xe_pmu_device *show = ((struct xe_gpu_info *)obj)->eng_obj;
+
+	for (unsigned int i = 0; i < show->num_engines; i++)
+		print_engine_perc(show, i);
+}
+
+static void *show_eu_util(void *data)
+{
+	struct igt_drm_clients *clients = NULL;
+	struct pci_device *pdev = NULL;
+	struct xe_gpu_info *gpu_ptr = NULL;
+	char filter[50] = "";
+	int ret, dev_fd;
+	long n;
+
+	dev_fd = drm_open_driver(DRIVER_XE);
+
+	pdev = igt_device_get_pci_device(dev_fd);
+	igt_require(pdev);
+
+	strcpy(filter, "pci:vendor=Intel,device=discrete,card=0");
+	gpu_ptr = xe_device_match(filter);
+	if (!gpu_ptr) {
+		printf("No device found.\n");
+		eu_util_free(gpu_ptr);
+		exit(1);
+	}
+
+	drm_close_driver(dev_fd);
+
+	if (!xe_init_engines(gpu_ptr)) {
+		fprintf(stderr,
+				"Failed to initialize engines! (%s)\n",
+				strerror(errno));
+		eu_util_free(gpu_ptr);
+		return NULL;
+	}
+
+	ret = xe_gpu_pmu_init(gpu_ptr);
+	if (ret) {
+		fprintf(stderr,
+				"Failed to initialize PMU! (%s)\n",
+				strerror(errno));
+		if (errno == EACCES && geteuid())
+			fprintf(stderr,
+					"\n"
+					"Access error\n"
+					"More info athttps://www.kernel.org/doc/html/latest/admin-guide/perf-security.html\n");
+		igt_devices_free();
+		eu_util_free(gpu_ptr);
+		return NULL;
+	}
+
+	xe_pmu_device_sample(gpu_ptr);
+
+	clients = igt_drm_clients_init(NULL);
+	if (!clients)
+		exit(1);
+	igt_drm_clients_scan(clients, NULL, NULL, 0, NULL, 0);
+	while ((n != 0) && !stop_top) {
+		igt_drm_clients_scan(clients, NULL, NULL, 0, NULL, 0);
+		xe_pmu_device_sample(gpu_ptr);
+		xe_print_perc(gpu_ptr);
+		usleep(2 * NS_SLEEP);
+	}
+	igt_drm_clients_free(clients);
+	eu_util_free(gpu_ptr);
+
+	return NULL;
+}
+
+static void
+thread_init_eu_utils(void)
+{
+	pthread_t eu_utils;
+	int fd;
+	uint16_t dev_id;
+
+	fd = drm_open_driver(DRIVER_XE);
+	dev_id = intel_get_drm_devid(fd);
+
+	/* Creating thread to display EU utilization in BMG */
+	if (IS_BATTLEMAGE(dev_id))
+		pthread_create(&eu_utils, NULL, show_eu_util, NULL);
+}
+
+/**
+ * SUBTEST: eu-busy-10-sec
+ * Functionality: OpenCL kernel
+ * Description:
+ *      Run an openCL long rinning Kernel that returns output[i] = input[i] * input[i],
+ */
+static void
+test_eu_busy(int fd, int num_gt, u32 duration_sec)
+{
+	struct user_execenv execenv = { 0 };
+	struct thread_data *threads_data;
+	struct drm_xe_engine_class_instance *hwe;
+	const struct intel_compute_kernels *kernels;
+	pthread_mutex_t mutex;
+	pthread_cond_t cond;
+	u32 gt, n_threads = 0, iterations = 0, n_instances = 0, i;
+	bool go = false;
+	int ccs_mode, gt_fd;
+	u32 num_slices, ip_ver;
+
+	fd = drm_open_driver(DRIVER_XE);
+	ip_ver = intel_graphics_ver(intel_get_drm_devid(fd));
+	kernels = intel_compute_square_kernels;
+	drm_close_driver(fd);
+
+	for (gt = 0; gt < num_gt; gt++) {
+		if (!get_num_cslices(gt, &num_slices))
+			continue;
+
+		gt_fd = gt_sysfs_open(gt);
+		igt_assert(igt_sysfs_printf(gt_fd, "ccs_mode", "%u", 2) > 0);
+		igt_assert(igt_sysfs_scanf(gt_fd, "ccs_mode", "%u", &ccs_mode) > 0);
+		close(gt_fd);
+	}
+
+	igt_skip_on_f(ccs_mode <= 1, "Skipping test as ccs_mode <=1 not matching criteria :%d\n",
+		      ccs_mode);
+
+	fd = drm_open_driver(DRIVER_XE);
+	thread_init_eu_utils();
+
+	while (kernels->kernel) {
+		if (ip_ver == kernels->ip_ver)
+			break;
+		kernels++;
+	}
+
+	/*If loop_kernel_duration not set user should use different
+	 *kernel and size
+	 *use with loop kernel and loop duration it assumes we stop
+	 *it via memory write
+	 */
+
+	execenv.loop_kernel_duration = duration_sec;
+	execenv.kernel = kernels->loop_kernel;
+	execenv.kernel_size = kernels->loop_kernel_size;
+	for (gt = 0; gt < num_gt; gt++) {
+		xe_for_each_engine(fd, hwe) {
+			igt_assert(hwe);
+			if (hwe->engine_class == DRM_XE_ENGINE_CLASS_COMPUTE)
+				++n_instances;
+		}
+	}
+
+	threads_data = calloc(n_instances, sizeof(*threads_data));
+	igt_assert(threads_data);
+
+	pthread_mutex_init(&mutex, 0);
+	pthread_cond_init(&cond, 0);
+
+	for (gt = 0; gt < num_gt; gt++) {
+		xe_for_each_engine(fd, hwe) {
+			if (hwe->gt_id != gt ||
+					hwe->engine_class != DRM_XE_ENGINE_CLASS_COMPUTE)
+				continue;
+
+			threads_data[i].mutex = &mutex;
+			threads_data[i].cond = &cond;
+			threads_data[i].fd = fd;
+			threads_data[i].eci = hwe;
+			threads_data[i].go = &go;
+			threads_data[i].execenv = &execenv;
+			++n_threads;
+			pthread_create(&threads_data[i].thread, 0, intel_compute_thread,
+					&threads_data[i]);
+			++i;
+			++iterations;
+			usleep(2 * NS_SLEEP);
+		}
+
+		pthread_mutex_lock(&mutex);
+		go = true;
+		pthread_cond_broadcast(&cond);
+		pthread_mutex_unlock(&mutex);
+
+		for (int val = 0; val < i; ++val) {
+			pthread_join(threads_data[val].thread, NULL);
+		}
+
+		i = 0;
+		n_threads = 0;
+		iterations = 0;
+		stop_top = true;
+	}
+	free(threads_data);
+	drm_close_driver(fd);
+}
+
 igt_main
 {
-	int xe;
+	int xe, num_gt;
 
 	igt_fixture {
 		xe = drm_open_driver(DRIVER_XE);
+		num_gt = xe_number_gt(xe);
 	}
 
 	igt_subtest("compute-square")
@@ -223,4 +816,8 @@ igt_main
 
 	igt_subtest("ccs-mode-compute-kernel")
 		test_compute_kernel_with_ccs_mode();
+
+	/* test to check available EU utilisation for multi_ccs */
+	igt_subtest("eu-busy-10-sec")
+		test_eu_busy(xe, num_gt, 10 * LOOP_DURATION);
 }
diff --git a/tests/meson.build b/tests/meson.build
index 9b87a0d24..7945f68f8 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -405,6 +405,7 @@ extra_dependencies = {
 	'sw_sync': [ libatomic ],
 	'xe_fault_injection': [ lib_igt_xe_oa ],
 	'xe_oa': [ lib_igt_xe_oa ],
+	'xe_compute': [ igt_deps,lib_igt_perf,lib_igt_drm_clients,lib_igt_drm_fdinfo,lib_igt_profiling,math ],
 }
 
 test_executables = []
-- 
2.43.0



More information about the igt-dev mailing list