[PATCH 53/66] tests/xe_eudebug_online: Set dynamic breakpoint on interrupt-all

Christoph Manszewski christoph.manszewski at intel.com
Mon Jul 29 16:01:46 UTC 2024


From: Dominik Grzegorzek <dominik.grzegorzek at intel.com>

Implement interrupt-all-set-breakpoint, which interrupts all threads,
and once spots attention it sets a breakpoint on the next instruction.

Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek at intel.com>
Cc: Mika Kuoppala <mika.kuoppala at intel.com>
---
 tests/intel/xe_eudebug_online.c | 81 ++++++++++++++++++++++++++++++++-
 1 file changed, 80 insertions(+), 1 deletion(-)

diff --git a/tests/intel/xe_eudebug_online.c b/tests/intel/xe_eudebug_online.c
index 8791b29fa..5bb165fef 100644
--- a/tests/intel/xe_eudebug_online.c
+++ b/tests/intel/xe_eudebug_online.c
@@ -22,6 +22,7 @@
 
 #define SHADER_BREAKPOINT	(1 << 0)
 #define SHADER_LOOP		(1 << 1)
+#define TRIGGER_RESUME_SET_BP	(1 << 28)
 #define TRIGGER_RESUME_DELAYED	(1 << 29)
 #define TRIGGER_RESUME_DSS	(1 << 30)
 #define TRIGGER_RESUME_ONE	(1 << 31)
@@ -276,6 +277,7 @@ struct online_debug_data {
 	uint64_t bb_offset;
 	size_t bb_size;
 	int vm_fd;
+	uint32_t first_aip;
 	struct timespec exception_arrived;
 	int last_eu_control_seqno;
 };
@@ -342,6 +344,71 @@ static void copy_first_bit(uint8_t *dst, uint8_t *src, int size)
 	}
 }
 
+/*
+ * Searches for the first instruction. It stands on assumption,
+ * that shader kernel is placed before sip within the bb.
+ */
+static uint32_t find_kernel_in_bb(struct gpgpu_shader *kernel,
+				  struct online_debug_data *data)
+{
+	uint32_t *p = kernel->code;
+	size_t sz = 4 * sizeof(uint32_t);
+	uint32_t buf[4];
+	int i;
+
+	for (i = 0; i < data->bb_size; i += sz) {
+		igt_assert_eq(pread(data->vm_fd, &buf, sz, data->bb_offset + i), sz);
+
+
+		if (memcmp(p, buf, sz) == 0)
+			break;
+	}
+
+	igt_assert(i < data->bb_size);
+
+	return i;
+}
+
+static void set_breakpoint_once(struct xe_eudebug_debugger *d,
+				struct online_debug_data *data)
+{
+	const uint32_t breakpoint_bit = 1 << 30;
+	size_t sz = sizeof(uint32_t);
+	struct gpgpu_shader *kernel;
+	uint32_t aip;
+
+	kernel = get_shader(d->master_fd, d->flags);
+
+	if (data->first_aip) {
+		uint32_t expected = find_kernel_in_bb(kernel, data) + kernel->size * 4 - 0x10;
+
+		igt_assert_eq(pread(data->vm_fd, &aip, sz, data->target_offset), sz);
+		igt_assert_eq_u32(aip, expected);
+	} else {
+		uint32_t instr_usdw;
+
+		igt_assert(data->vm_fd != -1);
+		igt_assert(data->target_size != 0);
+		igt_assert(data->bb_size != 0);
+
+		igt_assert_eq(pread(data->vm_fd, &aip, sz, data->target_offset), sz);
+		data->first_aip = aip;
+
+		aip = find_kernel_in_bb(kernel, data);
+
+		/* set breakpoint on last instruction */
+		aip += kernel->size * 4 - 0x10;
+		igt_assert_eq(pread(data->vm_fd, &instr_usdw, sz,
+				    data->bb_offset + aip), sz);
+		instr_usdw |= breakpoint_bit;
+		igt_assert_eq(pwrite(data->vm_fd, &instr_usdw, sz,
+				     data->bb_offset + aip), sz);
+
+	}
+
+	gpgpu_shader_destroy(kernel);
+}
+
 #define MAX_PREEMPT_TIMEOUT 10ull
 static void eu_attention_resume_trigger(struct xe_eudebug_debugger *d,
 					struct drm_xe_eudebug_event *e)
@@ -382,6 +449,8 @@ static void eu_attention_resume_trigger(struct xe_eudebug_debugger *d,
 			resume[i] = event[i];
 			break;
 		}
+	} else if (d->flags & TRIGGER_RESUME_SET_BP) {
+		set_breakpoint_once(d, data);
 	}
 
 	if (d->flags & SHADER_LOOP) {
@@ -602,7 +671,7 @@ static void run_online_client(struct xe_eudebug_client *c)
 	data->threads_count = count_canaries_neq(ptr, w_dim, 0);
 	igt_assert_f(data->threads_count, "No canaries found, nothing executed?\n");
 
-	if (c->flags & SHADER_BREAKPOINT) {
+	if (c->flags & SHADER_BREAKPOINT || c->flags & TRIGGER_RESUME_SET_BP) {
 		uint32_t aip = ptr[0];
 
 		igt_assert_f(aip != SHADER_CANARY, "Workload executed but breakpoint not hit!\n");
@@ -860,6 +929,13 @@ static void test_basic_online(int fd, struct drm_xe_engine_class_instance *hwe,
  *	Schedules EU workload which should last about a few seconds, then
  *	interrupts all threads, checks whether attention event came, and
  *	resumes stopped threads back.
+ *
+ * SUBTEST: interrupt-all-set-breakpoint
+ * Description:
+ *	Schedules EU workload which should last about a few seconds, then
+ *	interrupts all threads, once attention event come it sets breakpoint on
+ *	the very next instruction and resumes stopped thereads back. It expects
+ *	that every thread hits the breakpoint.
  */
 static void test_interrupt_all(int fd, struct drm_xe_engine_class_instance *hwe, int flags)
 {
@@ -970,6 +1046,9 @@ igt_main
 	test_gt_render_or_compute("interrupt-all", fd, hwe)
 		test_interrupt_all(fd, hwe, SHADER_LOOP);
 
+	test_gt_render_or_compute("interrupt-all-set-breakpoint", fd, hwe)
+		test_interrupt_all(fd, hwe, SHADER_LOOP | TRIGGER_RESUME_SET_BP);
+
 	igt_fixture {
 		intel_allocator_multiprocess_stop();
 		drm_close_driver(fd);
-- 
2.34.1



More information about the igt-dev mailing list