[igt-dev] [PATCH i-g-t 63/74] tests/i915/gem_exec_balancer: Don't reset engines on a context

Jason Ekstrand jason at jlekstrand.net
Thu Apr 15 19:11:34 UTC 2021


Instead of resetting the set of engines to break implicit dependencies,
just use a new context.  This does drop a theoretical bit of test
coverage in the bonded chain tests because we can't drop the timeline
easily.  However, those tests also use the FENCE_SUBMIT pattern in a way
that the set of engines is swapped out between the first and second half
of the bonded pair.  That seems pretty sketchy.
---
 tests/i915/gem_exec_balancer.c | 163 +++++++++++++++++----------------
 1 file changed, 86 insertions(+), 77 deletions(-)

diff --git a/tests/i915/gem_exec_balancer.c b/tests/i915/gem_exec_balancer.c
index 44c9b05d..9fc5fe6d 100644
--- a/tests/i915/gem_exec_balancer.c
+++ b/tests/i915/gem_exec_balancer.c
@@ -27,6 +27,7 @@
 #include <sys/signal.h>
 
 #include "i915/gem.h"
+#include "i915/gem_vm.h"
 #include "igt.h"
 #include "igt_gt.h"
 #include "igt_perf.h"
@@ -122,6 +123,21 @@ static bool has_perf_engines(int i915)
 	return i915_perf_type_id(i915);
 }
 
+static int __set_vm(int i915, uint32_t ctx, uint32_t vm)
+{
+	struct drm_i915_gem_context_param p = {
+		.ctx_id = ctx,
+		.param = I915_CONTEXT_PARAM_VM,
+		.value = vm
+	};
+	return __gem_context_set_param(i915, &p);
+}
+
+static void set_vm(int i915, uint32_t ctx, uint32_t vm)
+{
+	igt_assert_eq(__set_vm(i915, ctx, vm), 0);
+}
+
 static int __set_engines(int i915, uint32_t ctx,
 			 const struct i915_engine_class_instance *ci,
 			 unsigned int count)
@@ -543,8 +559,6 @@ static void check_individual_engine(int i915,
 
 static void individual(int i915)
 {
-	uint32_t ctx;
-
 	/*
 	 * I915_CONTEXT_PARAM_ENGINE allows us to index into the user
 	 * supplied array from gem_execbuf(). Our check is to build the
@@ -553,8 +567,6 @@ static void individual(int i915)
 	 * was busy.
 	 */
 
-	ctx = gem_context_create(i915);
-
 	for (int class = 0; class < 32; class++) {
 		struct i915_engine_class_instance *ci;
 		unsigned int count;
@@ -564,17 +576,20 @@ static void individual(int i915)
 			continue;
 
 		for (int pass = 0; pass < count; pass++) { /* approx. count! */
+			uint32_t ctx;
+
 			igt_assert(sizeof(*ci) == sizeof(int));
 			igt_permute_array(ci, count, igt_exchange_int);
+			ctx = gem_context_create(i915);
 			set_load_balancer(i915, ctx, ci, count, NULL);
 			for (unsigned int n = 0; n < count; n++)
 				check_individual_engine(i915, ctx, ci, n);
+			gem_context_destroy(i915, ctx);
 		}
 
 		free(ci);
 	}
 
-	gem_context_destroy(i915, ctx);
 	gem_quiescent_gpu(i915);
 }
 
@@ -583,7 +598,7 @@ static void bonded(int i915, unsigned int flags)
 {
 	I915_DEFINE_CONTEXT_ENGINES_BOND(bonds[16], 1);
 	struct i915_engine_class_instance *master_engines;
-	uint32_t master;
+	uint32_t vm;
 
 	/*
 	 * I915_CONTEXT_PARAM_ENGINE provides an extension that allows us
@@ -591,7 +606,7 @@ static void bonded(int i915, unsigned int flags)
 	 * request submitted to another engine.
 	 */
 
-	master = gem_queue_create(i915);
+	vm = gem_vm_create(i915);
 
 	memset(bonds, 0, sizeof(bonds));
 	for (int n = 0; n < ARRAY_SIZE(bonds); n++) {
@@ -604,7 +619,7 @@ static void bonded(int i915, unsigned int flags)
 	for (int class = 0; class < 32; class++) {
 		struct i915_engine_class_instance *siblings;
 		unsigned int count, limit, *order;
-		uint32_t ctx;
+		uint32_t master, ctx;
 		int n;
 
 		siblings = list_engines(i915, 1u << class, &count);
@@ -617,6 +632,8 @@ static void bonded(int i915, unsigned int flags)
 		}
 
 		master_engines = list_engines(i915, ~(1u << class), &limit);
+		master = gem_context_create_ext(i915, I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE, 0);
+		set_vm(i915, master, vm);
 		set_engines(i915, master, master_engines, limit);
 
 		limit = min(count, limit);
@@ -626,9 +643,9 @@ static void bonded(int i915, unsigned int flags)
 			bonds[n].engines[0] = siblings[n];
 		}
 
-		ctx = gem_context_clone(i915,
-					master, I915_CONTEXT_CLONE_VM,
-					I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE);
+		ctx = gem_context_create_ext(i915, I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE, 0);
+		set_vm(i915, master, vm);
+		set_engines(i915, master, master_engines, limit);
 		set_load_balancer(i915, ctx, siblings, count, &bonds[limit - 1]);
 
 		order = malloc(sizeof(*order) * 8 * limit);
@@ -710,12 +727,11 @@ static void bonded(int i915, unsigned int flags)
 		}
 
 		free(order);
+		gem_context_destroy(i915, master);
 		gem_context_destroy(i915, ctx);
 		free(master_engines);
 		free(siblings);
 	}
-
-	gem_context_destroy(i915, master);
 }
 
 #define VIRTUAL_ENGINE (1u << 0)
@@ -760,7 +776,6 @@ static uint32_t create_semaphore_to_spinner(int i915, igt_spin_t *spin)
 
 static void bonded_slice(int i915)
 {
-	uint32_t ctx;
 	int *stop;
 
 	/*
@@ -773,13 +788,12 @@ static void bonded_slice(int i915)
 	stop = mmap(0, 4096, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
 	igt_assert(stop != MAP_FAILED);
 
-	ctx = gem_context_create(i915); /* NB timeline per engine */
-
 	for (int class = 0; class < 32; class++) {
 		struct i915_engine_class_instance *siblings;
 		struct drm_i915_gem_exec_object2 obj[3] = {};
 		struct drm_i915_gem_execbuffer2 eb = {};
 		unsigned int count;
+		uint32_t ctx;
 		igt_spin_t *spin;
 
 		siblings = list_engines(i915, 1u << class, &count);
@@ -803,6 +817,7 @@ static void bonded_slice(int i915)
 		 * XXX add explicit bonding options for A->B
 		 */
 
+		ctx = gem_context_create(i915); /* NB timeline per engine */
 		set_load_balancer(i915, ctx, siblings, count, NULL);
 
 		spin = __igt_spin_new(i915,
@@ -864,13 +879,13 @@ static void bonded_slice(int i915)
 
 		gem_close(i915, obj[2].handle);
 		igt_spin_free(i915, spin);
+		gem_context_destroy(i915, ctx);
 	}
 
-	gem_context_destroy(i915, ctx);
 	munmap(stop, 4096);
 }
 
-static void __bonded_chain(int i915, uint32_t ctx,
+static void __bonded_chain(int i915,
 			   const struct i915_engine_class_instance *siblings,
 			   unsigned int count)
 {
@@ -881,12 +896,14 @@ static void __bonded_chain(int i915, uint32_t ctx,
 	struct drm_i915_gem_execbuffer2 execbuf = {
 		.buffers_ptr = to_user_pointer(&batch),
 		.buffer_count = 1,
-		.rsvd1 = ctx,
 	};
 	igt_spin_t *spin;
 
 	for (int i = 0; i < ARRAY_SIZE(priorities); i++) {
+		uint32_t ctx;
 		/* A: spin forever on engine 1 */
+
+		ctx = gem_context_create(i915);
 		set_load_balancer(i915, ctx, siblings, count, NULL);
 		if (priorities[i] < 0)
 			gem_context_set_priority(i915, ctx, priorities[i]);
@@ -896,17 +913,13 @@ static void __bonded_chain(int i915, uint32_t ctx,
 				    .flags = (IGT_SPIN_POLL_RUN |
 					      IGT_SPIN_FENCE_OUT));
 		igt_spin_busywait_until_started(spin);
-		gem_context_set_priority(i915, ctx, 0);
-
-		/*
-		 * Note we replace the timelines between each execbuf, so
-		 * that any pair of requests on the same engine could be
-		 * re-ordered by the scheduler -- if the dependency tracking
-		 * is subpar.
-		 */
 
 		/* B: waits for A on engine 2 */
+		gem_context_destroy(i915, ctx);
+		ctx = gem_context_create(i915);
+		gem_context_set_priority(i915, ctx, 0);
 		set_load_balancer(i915, ctx, siblings, count, NULL);
+		execbuf.rsvd1 = ctx;
 		execbuf.rsvd2 = spin->out_fence;
 		execbuf.flags = I915_EXEC_FENCE_IN | I915_EXEC_FENCE_OUT;
 		execbuf.flags |= 2; /* opposite engine to spinner */
@@ -915,7 +928,6 @@ static void __bonded_chain(int i915, uint32_t ctx,
 		/* B': run in parallel with B on engine 1, i.e. not before A! */
 		if (priorities[i] > 0)
 			gem_context_set_priority(i915, ctx, priorities[i]);
-		set_load_balancer(i915, ctx, siblings, count, NULL);
 		execbuf.flags = I915_EXEC_FENCE_SUBMIT | I915_EXEC_FENCE_OUT;
 		execbuf.flags |= 1; /* same engine as spinner */
 		execbuf.rsvd2 >>= 32;
@@ -937,6 +949,7 @@ static void __bonded_chain(int i915, uint32_t ctx,
 		igt_assert_eq(sync_fence_status(execbuf.rsvd2 >> 32), 0);
 
 		igt_spin_free(i915, spin);
+		gem_context_destroy(i915, ctx);
 		gem_sync(i915, batch.handle);
 
 		igt_assert_eq(sync_fence_status(execbuf.rsvd2 & 0xffffffff), 1);
@@ -949,7 +962,7 @@ static void __bonded_chain(int i915, uint32_t ctx,
 	gem_close(i915, batch.handle);
 }
 
-static void __bonded_chain_inv(int i915, uint32_t ctx,
+static void __bonded_chain_inv(int i915,
 			       const struct i915_engine_class_instance *siblings,
 			       unsigned int count)
 {
@@ -960,12 +973,14 @@ static void __bonded_chain_inv(int i915, uint32_t ctx,
 	struct drm_i915_gem_execbuffer2 execbuf = {
 		.buffers_ptr = to_user_pointer(&batch),
 		.buffer_count = 1,
-		.rsvd1 = ctx,
 	};
 	igt_spin_t *spin;
 
 	for (int i = 0; i < ARRAY_SIZE(priorities); i++) {
+		uint32_t ctx;
+
 		/* A: spin forever on engine 1 */
+		ctx = gem_context_create(i915);
 		set_load_balancer(i915, ctx, siblings, count, NULL);
 		if (priorities[i] < 0)
 			gem_context_set_priority(i915, ctx, priorities[i]);
@@ -975,17 +990,13 @@ static void __bonded_chain_inv(int i915, uint32_t ctx,
 				    .flags = (IGT_SPIN_POLL_RUN |
 					      IGT_SPIN_FENCE_OUT));
 		igt_spin_busywait_until_started(spin);
-		gem_context_set_priority(i915, ctx, 0);
-
-		/*
-		 * Note we replace the timelines between each execbuf, so
-		 * that any pair of requests on the same engine could be
-		 * re-ordered by the scheduler -- if the dependency tracking
-		 * is subpar.
-		 */
 
 		/* B: waits for A on engine 1 */
+		gem_context_destroy(i915, ctx);
+		ctx = gem_context_create(i915);
+		gem_context_set_priority(i915, ctx, 0);
 		set_load_balancer(i915, ctx, siblings, count, NULL);
+		execbuf.rsvd1 = ctx;
 		execbuf.rsvd2 = spin->out_fence;
 		execbuf.flags = I915_EXEC_FENCE_IN | I915_EXEC_FENCE_OUT;
 		execbuf.flags |= 1; /* same engine as spinner */
@@ -994,7 +1005,6 @@ static void __bonded_chain_inv(int i915, uint32_t ctx,
 		/* B': run in parallel with B on engine 2, i.e. not before A! */
 		if (priorities[i] > 0)
 			gem_context_set_priority(i915, ctx, priorities[i]);
-		set_load_balancer(i915, ctx, siblings, count, NULL);
 		execbuf.flags = I915_EXEC_FENCE_SUBMIT | I915_EXEC_FENCE_OUT;
 		execbuf.flags |= 2; /* opposite engine to spinner */
 		execbuf.rsvd2 >>= 32;
@@ -1017,6 +1027,7 @@ static void __bonded_chain_inv(int i915, uint32_t ctx,
 
 		igt_spin_free(i915, spin);
 		gem_sync(i915, batch.handle);
+		gem_context_destroy(i915, ctx);
 
 		igt_assert_eq(sync_fence_status(execbuf.rsvd2 & 0xffffffff), 1);
 		igt_assert_eq(sync_fence_status(execbuf.rsvd2 >> 32), 1);
@@ -1030,32 +1041,26 @@ static void __bonded_chain_inv(int i915, uint32_t ctx,
 
 static void bonded_chain(int i915)
 {
-	uint32_t ctx;
-
 	/*
 	 * Given batches A, B and B', where B and B' are a bonded pair, with
 	 * B' depending on B with a submit fence and B depending on A as
 	 * an ordinary fence; prove B' cannot complete before A.
 	 */
 
-	ctx = gem_context_create(i915);
-
 	for (int class = 0; class < 32; class++) {
 		struct i915_engine_class_instance *siblings;
 		unsigned int count;
 
 		siblings = list_engines(i915, 1u << class, &count);
 		if (count > 1) {
-			__bonded_chain(i915, ctx, siblings, count);
-			__bonded_chain_inv(i915, ctx, siblings, count);
+			__bonded_chain(i915, siblings, count);
+			__bonded_chain_inv(i915, siblings, count);
 		}
 		free(siblings);
 	}
-
-	gem_context_destroy(i915, ctx);
 }
 
-static void __bonded_sema(int i915, uint32_t ctx,
+static void __bonded_sema(int i915,
 			  const struct i915_engine_class_instance *siblings,
 			  unsigned int count)
 {
@@ -1066,11 +1071,12 @@ static void __bonded_sema(int i915, uint32_t ctx,
 	struct drm_i915_gem_execbuffer2 execbuf = {
 		.buffers_ptr = to_user_pointer(&batch),
 		.buffer_count = 1,
-		.rsvd1 = ctx,
 	};
 	igt_spin_t *spin;
 
 	for (int i = 0; i < ARRAY_SIZE(priorities); i++) {
+		uint32_t ctx;
+
 		/* A: spin forever on seperate render engine */
 		spin = igt_spin_new(i915,
 				    .flags = (IGT_SPIN_POLL_RUN |
@@ -1085,16 +1091,21 @@ static void __bonded_sema(int i915, uint32_t ctx,
 		 */
 
 		/* B: waits for A (using a semaphore) on engine 1 */
+		ctx = gem_context_create(i915);
 		set_load_balancer(i915, ctx, siblings, count, NULL);
+		execbuf.rsvd1 = ctx;
 		execbuf.rsvd2 = spin->out_fence;
 		execbuf.flags = I915_EXEC_FENCE_IN | I915_EXEC_FENCE_OUT;
 		execbuf.flags |= 1;
 		gem_execbuf_wr(i915, &execbuf);
 
 		/* B': run in parallel with B on engine 2 */
+		gem_context_destroy(i915, ctx);
+		ctx = gem_context_create(i915);
 		if (priorities[i] > 0)
 			gem_context_set_priority(i915, ctx, priorities[i]);
 		set_load_balancer(i915, ctx, siblings, count, NULL);
+		execbuf.rsvd1 = ctx;
 		execbuf.flags = I915_EXEC_FENCE_SUBMIT | I915_EXEC_FENCE_OUT;
 		execbuf.flags |= 2;
 		execbuf.rsvd2 >>= 32;
@@ -1117,6 +1128,7 @@ static void __bonded_sema(int i915, uint32_t ctx,
 
 		igt_spin_free(i915, spin);
 		gem_sync(i915, batch.handle);
+		gem_context_destroy(i915, ctx);
 
 		igt_assert_eq(sync_fence_status(execbuf.rsvd2 & 0xffffffff), 1);
 		igt_assert_eq(sync_fence_status(execbuf.rsvd2 >> 32), 1);
@@ -1130,8 +1142,6 @@ static void __bonded_sema(int i915, uint32_t ctx,
 
 static void bonded_semaphore(int i915)
 {
-	uint32_t ctx;
-
 	/*
 	 * Given batches A, B and B', where B and B' are a bonded pair, with
 	 * B' depending on B with a submit fence and B depending on A as
@@ -1141,19 +1151,15 @@ static void bonded_semaphore(int i915)
 	 */
 	igt_require(gem_scheduler_has_semaphores(i915));
 
-	ctx = gem_context_create(i915);
-
 	for (int class = 1; class < 32; class++) {
 		struct i915_engine_class_instance *siblings;
 		unsigned int count;
 
 		siblings = list_engines(i915, 1u << class, &count);
 		if (count > 1)
-			__bonded_sema(i915, ctx, siblings, count);
+			__bonded_sema(i915, siblings, count);
 		free(siblings);
 	}
-
-	gem_context_destroy(i915, ctx);
 }
 
 static void __bonded_pair(int i915,
@@ -1804,7 +1810,7 @@ static void indices(int i915)
 	gem_quiescent_gpu(i915);
 }
 
-static void __bonded_early(int i915, uint32_t ctx,
+static void __bonded_early(int i915,
 			   const struct i915_engine_class_instance *siblings,
 			   unsigned int count,
 			   unsigned int flags)
@@ -1817,8 +1823,8 @@ static void __bonded_early(int i915, uint32_t ctx,
 	struct drm_i915_gem_execbuffer2 execbuf = {
 		.buffers_ptr = to_user_pointer(&batch),
 		.buffer_count = 1,
-		.rsvd1 = ctx,
 	};
+	uint32_t vm, ctx;
 	igt_spin_t *spin;
 
 	memset(bonds, 0, sizeof(bonds));
@@ -1832,6 +1838,11 @@ static void __bonded_early(int i915, uint32_t ctx,
 		bonds[n].engines[0] = siblings[(n + 1) % count];
 	}
 
+	/* We share a VM so that the spin cancel will work without a reloc */
+	vm = gem_vm_create(i915);
+
+	ctx = gem_context_create(i915);
+	set_vm(i915, ctx, vm);
 	set_load_balancer(i915, ctx, siblings, count,
 			  flags & VIRTUAL_ENGINE ? &bonds : NULL);
 
@@ -1842,6 +1853,7 @@ static void __bonded_early(int i915, uint32_t ctx,
 			    .flags = IGT_SPIN_NO_PREEMPTION);
 
 	/* B: runs after A on engine 1 */
+	execbuf.rsvd1 = ctx;
 	execbuf.flags = I915_EXEC_FENCE_OUT;
 	execbuf.flags |= spin->execbuf.flags & 63;
 	gem_execbuf_wr(i915, &execbuf);
@@ -1859,9 +1871,14 @@ static void __bonded_early(int i915, uint32_t ctx,
 
 	igt_debugfs_dump(i915, "i915_engine_info");
 
-	/* D: cancel the spinner from engine 2 (new timeline) */
-	set_load_balancer(i915, ctx, siblings, count, NULL);
+	/* D: cancel the spinner from engine 2 (new context) */
+	gem_context_destroy(i915, ctx);
+	ctx = gem_context_create(i915);
+	set_vm(i915, ctx, vm);
+	set_load_balancer(i915, ctx, siblings, count,
+			  flags & VIRTUAL_ENGINE ? &bonds : NULL);
 	batch.handle = create_semaphore_to_spinner(i915, spin);
+	execbuf.rsvd1 = ctx;
 	execbuf.flags = 0;
 	if(!(flags & VIRTUAL_ENGINE))
 		execbuf.flags |= 2;
@@ -1878,14 +1895,13 @@ static void __bonded_early(int i915, uint32_t ctx,
 	close(execbuf.rsvd2);
 	close(execbuf.rsvd2 >> 32);
 
+	gem_context_destroy(i915, ctx);
 	gem_close(i915, handle);
 	igt_spin_free(i915, spin);
 }
 
 static void bonded_early(int i915)
 {
-	uint32_t ctx;
-
 	/*
 	 * Our goal is to start the bonded payloads at roughly the same time.
 	 * We do not want to start the secondary batch too early as it will
@@ -1901,21 +1917,17 @@ static void bonded_early(int i915)
 	 * hang.
 	 */
 
-	ctx = gem_context_create(i915);
-
 	for (int class = 0; class < 32; class++) {
 		struct i915_engine_class_instance *siblings;
 		unsigned int count;
 
 		siblings = list_engines(i915, 1u << class, &count);
 		if (count > 1) {
-			__bonded_early(i915, ctx, siblings, count, 0);
-			__bonded_early(i915, ctx, siblings, count, VIRTUAL_ENGINE);
+			__bonded_early(i915, siblings, count, 0);
+			__bonded_early(i915, siblings, count, VIRTUAL_ENGINE);
 		}
 		free(siblings);
 	}
-
-	gem_context_destroy(i915, ctx);
 }
 
 static void busy(int i915)
@@ -2570,7 +2582,7 @@ static void ping(int i915, uint32_t ctx, unsigned int engine)
 
 static void semaphore(int i915)
 {
-	uint32_t block[2], scratch;
+	uint32_t scratch;
 	igt_spin_t *spin[3];
 
 	/*
@@ -2580,15 +2592,12 @@ static void semaphore(int i915)
 	 */
 	igt_require(gem_scheduler_has_preemption(i915));
 
-	block[0] = gem_context_create(i915);
-	block[1] = gem_context_create(i915);
-
 	scratch = gem_create(i915, 4096);
 	spin[2] = igt_spin_new(i915, .dependency = scratch);
 	for (int class = 1; class < 32; class++) {
 		struct i915_engine_class_instance *ci;
 		unsigned int count;
-		uint32_t vip;
+		uint32_t block[2], vip;
 
 		ci = list_engines(i915, 1u << class, &count);
 		if (!ci)
@@ -2601,6 +2610,7 @@ static void semaphore(int i915)
 		count = ARRAY_SIZE(block);
 
 		for (int i = 0; i < count; i++) {
+			block[i] = gem_context_create(i915);
 			set_load_balancer(i915, block[i], ci, count, NULL);
 			spin[i] = __igt_spin_new(i915,
 						 .ctx_id = block[i],
@@ -2616,17 +2626,16 @@ static void semaphore(int i915)
 		ping(i915, vip, 0);
 		gem_context_destroy(i915, vip);
 
-		for (int i = 0; i < count; i++)
+		for (int i = 0; i < count; i++) {
 			igt_spin_free(i915, spin[i]);
+			gem_context_destroy(i915, block[i]);
+		}
 
 		free(ci);
 	}
 	igt_spin_free(i915, spin[2]);
 	gem_close(i915, scratch);
 
-	gem_context_destroy(i915, block[1]);
-	gem_context_destroy(i915, block[0]);
-
 	gem_quiescent_gpu(i915);
 }
 
-- 
2.31.1



More information about the igt-dev mailing list