[PATCH i-g-t v2 64/66] tests/xe_eudebug_online: Add multisession test cases

Christoph Manszewski christoph.manszewski at intel.com
Tue Jul 30 11:45:21 UTC 2024


From: Karolina Stolarek <karolina.stolarek at intel.com>

Add subtests where we run many sessions, either on a single or
multiple tiles. Extract a macro that selects compute or render
engine from the same GT so it can be used in a helper.

Signed-off-by: Karolina Stolarek <karolina.stolarek at intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek at intel.com>
---
 tests/intel/xe_eudebug_online.c | 208 +++++++++++++++++++++++++++++++-
 1 file changed, 202 insertions(+), 6 deletions(-)

diff --git a/tests/intel/xe_eudebug_online.c b/tests/intel/xe_eudebug_online.c
index 864591a34..ab1a57d9b 100644
--- a/tests/intel/xe_eudebug_online.c
+++ b/tests/intel/xe_eudebug_online.c
@@ -29,6 +29,7 @@
 #define SHADER_CACHING_SRAM		(1 << 6)
 #define SHADER_CACHING_VRAM		(1 << 7)
 #define DISABLE_LONG_RUNNING_MODE	(1 << 8)
+#define SHADER_MIN_THREADS		(1 << 9)
 #define TRIGGER_RESUME_SINGLE_WALK	(1 << 25)
 #define TRIGGER_RESUME_PARALLEL_WALK	(1 << 26)
 #define TRIGGER_RECONNECT		(1 << 27)
@@ -56,6 +57,7 @@
 #define SIMD_SIZE		16
 
 #define STARTUP_TIMEOUT_MS	3000
+#define WORKLOAD_DELAY_US	(5000 * 1000)
 
 #define PAGE_SIZE 4096
 
@@ -109,6 +111,9 @@ static struct intel_buf *create_uc_buf(int fd, int width, int height)
 
 static int get_number_of_threads(uint64_t flags)
 {
+	if (flags & SHADER_MIN_THREADS)
+		return 16;
+
 	if (flags & (TRIGGER_RESUME_ONE | TRIGGER_RESUME_SINGLE_WALK |
 		     TRIGGER_RESUME_PARALLEL_WALK | SHADER_CACHING_SRAM | SHADER_CACHING_VRAM))
 		return 32;
@@ -342,6 +347,7 @@ struct online_debug_data {
 	int stepped_threads_count;
 	struct timespec exception_arrived;
 	int last_eu_control_seqno;
+	struct drm_xe_eudebug_event *exception_event;
 };
 
 static struct online_debug_data *
@@ -561,6 +567,19 @@ static int get_stepped_threads_count(struct online_debug_data *data, int threads
 	return count;
 }
 
+static void save_first_exception_trigger(struct xe_eudebug_debugger *d,
+					 struct drm_xe_eudebug_event *e)
+{
+	struct online_debug_data *data = d->ptr;
+
+	pthread_mutex_lock(&data->mutex);
+	if (!data->exception_event) {
+		igt_gettime(&data->exception_arrived);
+		data->exception_event = igt_memdup(e, e->len);
+	}
+	pthread_mutex_unlock(&data->mutex);
+}
+
 #define MAX_PREEMPT_TIMEOUT 10ull
 static int is_client_resumed;
 static void eu_attention_resume_trigger(struct xe_eudebug_debugger *d,
@@ -1768,22 +1787,193 @@ static void test_caching(int fd, struct drm_xe_engine_class_instance *hwe, int f
 	online_debug_data_destroy(data);
 }
 
+static int wait_for_exception(struct online_debug_data *data, int timeout)
+{
+	int ret = -ETIMEDOUT;
+
+	igt_for_milliseconds(timeout) {
+		pthread_mutex_lock(&data->mutex);
+		if ((data->exception_arrived.tv_sec |
+		     data->exception_arrived.tv_nsec) != 0)
+			ret = 0;
+		pthread_mutex_unlock(&data->mutex);
+
+		if (!ret)
+			break;
+		usleep(1000);
+	}
+
+	return ret;
+}
+
+#define is_compute_on_gt(__e, __gt) ((__e->engine_class == DRM_XE_ENGINE_CLASS_RENDER || \
+				      __e->engine_class == DRM_XE_ENGINE_CLASS_COMPUTE) && \
+				      __e->gt_id == __gt)
+
+struct xe_engine_list_entry {
+	struct igt_list_head link;
+	struct drm_xe_engine_class_instance *hwe;
+};
+
+#define MAX_TILES	2
+static int find_suitable_engines(struct drm_xe_engine_class_instance *hwes[GEM_MAX_ENGINES],
+				 int fd, bool many_tiles)
+{
+	struct xe_device *xe_dev;
+	struct drm_xe_engine_class_instance *e;
+	struct xe_engine_list_entry *en, *tmp;
+	struct igt_list_head compute_engines[MAX_TILES];
+	int gt_id;
+	int tile_id, i, engine_count = 0, tile_count = 0;
+
+	xe_dev = xe_device_get(fd);
+
+	for (i = 0; i < MAX_TILES; i++)
+		IGT_INIT_LIST_HEAD(&compute_engines[i]);
+
+	xe_for_each_gt(fd, gt_id) {
+		xe_for_each_engine(fd, e) {
+			if (is_compute_on_gt(e, gt_id)) {
+				tile_id = xe_dev->gt_list->gt_list[gt_id].tile_id;
+
+				en = malloc(sizeof(struct xe_engine_list_entry));
+				en->hwe = e;
+
+				igt_list_add_tail(&en->link, &compute_engines[tile_id]);
+			}
+		}
+	}
+
+	for (i = 0; i < MAX_TILES; i++) {
+		if (igt_list_empty(&compute_engines[i]))
+			continue;
+
+		if (many_tiles) {
+			en = igt_list_first_entry(&compute_engines[i], en, link);
+			hwes[engine_count++] = en->hwe;
+			tile_count++;
+		} else {
+			if (igt_list_length(&compute_engines[i]) > 1) {
+				igt_list_for_each_entry(en, &compute_engines[i], link)
+					hwes[engine_count++] = en->hwe;
+				break;
+			}
+		}
+	}
+
+	for (i = 0; i < MAX_TILES; i++) {
+		igt_list_for_each_entry_safe(en, tmp, &compute_engines[i], link) {
+			igt_list_del(&en->link);
+			free(en);
+		}
+	}
+
+	if (many_tiles)
+		igt_require_f(tile_count > 1, "Mulit-tile scenario requires more tiles\n");
+
+	return engine_count;
+}
+
+/**
+ * SUBTEST: breakpoint-many-sessions-single-tile
+ * Description:
+ *	Schedules EU workload with preinstalled breakpoint on every compute engine
+ *	available on the tile. Checks if the contexts hit breakpoint in sequence
+ *	and resumes them.
+ *
+ * SUBTEST: breakpoint-many-sessions-tiles
+ * Description:
+ *	Schedules EU workload with preinstalled breakpoint on selected compute
+ *      engines, with one per tile. Checks if each context hit breakpoint and
+ *      resumes them.
+ */
+static void test_many_sessions_on_tiles(int fd, bool multi_tile)
+{
+	int n = 0, flags = SHADER_BREAKPOINT | SHADER_MIN_THREADS;
+	struct xe_eudebug_session *s[GEM_MAX_ENGINES] = {};
+	struct online_debug_data *data[GEM_MAX_ENGINES] = {};
+	struct drm_xe_engine_class_instance *hwe[GEM_MAX_ENGINES] = {};
+	struct drm_xe_eudebug_event_eu_attention *eus;
+	uint64_t current_t, next_t, diff;
+	int i;
+
+	n = find_suitable_engines(hwe, fd, multi_tile);
+
+	igt_require_f(n > 1, "Test requires at least two parallel compute engines!\n");
+
+	for (i = 0; i < n; i++) {
+		data[i] = online_debug_data_create(hwe[i]);
+		s[i] = xe_eudebug_session_create(fd, run_online_client, flags, data[i]);
+
+		xe_eudebug_debugger_add_trigger(s[i]->d, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
+						eu_attention_debug_trigger);
+		xe_eudebug_debugger_add_trigger(s[i]->d, DRM_XE_EUDEBUG_EVENT_EU_ATTENTION,
+						save_first_exception_trigger);
+		xe_eudebug_debugger_add_trigger(s[i]->d, DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE,
+						ufence_ack_trigger);
+
+		igt_assert_eq(xe_eudebug_debugger_attach(s[i]->d, s[i]->c), 0);
+
+		xe_eudebug_debugger_start_worker(s[i]->d);
+		xe_eudebug_client_start(s[i]->c);
+	}
+
+	for (i = 0; i < n; i++) {
+		/* XXX: Sometimes racy, expects clients to execute in sequence */
+		igt_assert(!wait_for_exception(data[i], STARTUP_TIMEOUT_MS));
+
+		eus = (struct drm_xe_eudebug_event_eu_attention *)data[i]->exception_event;
+
+		/* Delay all but the last workload to check serialization */
+		if (i < n - 1)
+			usleep(WORKLOAD_DELAY_US);
+
+		eu_ctl_resume(s[i]->d->master_fd, s[i]->d->fd,
+			      eus->client_handle, eus->exec_queue_handle,
+			      eus->lrc_handle, eus->bitmask, eus->bitmask_size);
+		free(eus);
+	}
+
+	for (i = 0; i < n - 1; i++) {
+		/* Convert timestamps to microseconds */
+		current_t = data[i]->exception_arrived.tv_nsec * 1000;
+		next_t = data[i + 1]->exception_arrived.tv_nsec * 1000;
+		diff = current_t < next_t ? next_t - current_t : current_t - next_t;
+
+		if (multi_tile)
+			igt_assert_f(diff < WORKLOAD_DELAY_US,
+				     "Expected to execute workloads concurrently. Actual delay: %lu ms\n",
+				     diff);
+		else
+			igt_assert_f(diff >= WORKLOAD_DELAY_US,
+				     "Expected a serialization of workloads. Actual delay: %lu ms\n",
+				     diff);
+	}
+
+	for (i = 0; i < n; i++) {
+		xe_eudebug_client_wait_done(s[i]->c);
+		xe_eudebug_debugger_stop_worker(s[i]->d, 1);
+
+		xe_eudebug_event_log_print(s[i]->d->log, true);
+		online_session_check(s[i], flags);
+
+		xe_eudebug_session_destroy(s[i]);
+		online_debug_data_destroy(data[i]);
+	}
+}
+
 static struct drm_xe_engine_class_instance *pick_compute(int fd, int gt)
 {
 	struct drm_xe_engine_class_instance *hwe;
 	int count = 0;
 
-	#define match(__e) ((__e->engine_class == DRM_XE_ENGINE_CLASS_RENDER || \
-			     __e->engine_class == DRM_XE_ENGINE_CLASS_COMPUTE) && __e->gt_id == gt)
-
 	xe_for_each_engine(fd, hwe)
-		if (match(hwe))
+		if (is_compute_on_gt(hwe, gt))
 			count++;
 
 	xe_for_each_engine(fd, hwe)
-		if (match(hwe) && rand() % count-- == 0)
+		if (is_compute_on_gt(hwe, gt) && rand() % count-- == 0)
 			return hwe;
-	#undef match
 
 	return NULL;
 }
@@ -1863,6 +2053,12 @@ igt_main
 	test_gt_render_or_compute("writes-caching-vram", fd, hwe)
 		test_caching(fd, hwe, SHADER_CACHING_VRAM);
 
+	igt_subtest("breakpoint-many-sessions-single-tile")
+		test_many_sessions_on_tiles(fd, false);
+
+	igt_subtest("breakpoint-many-sessions-tiles")
+		test_many_sessions_on_tiles(fd, true);
+
 	igt_fixture {
 		xe_eudebug_enable(fd, was_enabled);
 
-- 
2.34.1



More information about the igt-dev mailing list