[igt-dev] [PATCH i-g-t] i915/gem_ctx_exec: Exploit resource contention to verify execbuf independence

Chris Wilson chris at chris-wilson.co.uk
Mon May 4 19:31:12 UTC 2020


Even if one client is blocked on a resource, that should not impact
another client.

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
 tests/i915/gem_ctx_exec.c | 122 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 121 insertions(+), 1 deletion(-)

diff --git a/tests/i915/gem_ctx_exec.c b/tests/i915/gem_ctx_exec.c
index ad2f9e545..d7cd56424 100644
--- a/tests/i915/gem_ctx_exec.c
+++ b/tests/i915/gem_ctx_exec.c
@@ -35,8 +35,9 @@
 #include <fcntl.h>
 #include <inttypes.h>
 #include <errno.h>
-#include <sys/stat.h>
 #include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/stat.h>
 #include <sys/time.h>
 
 #include <drm.h>
@@ -331,6 +332,122 @@ static void nohangcheck_hostile(int i915)
 	close(i915);
 }
 
+static void kill_children(int sig)
+{
+	sighandler_t old;
+
+	old = signal(sig, SIG_IGN);
+	kill(-getpgrp(), sig);
+	signal(sig, old);
+}
+
+static bool has_persistence(int i915)
+{
+	struct drm_i915_gem_context_param p = {
+		.param = I915_CONTEXT_PARAM_PERSISTENCE,
+	};
+	uint64_t saved;
+
+	if (__gem_context_get_param(i915, &p))
+		return false;
+
+	saved = p.value;
+	p.value = 0;
+	if (__gem_context_set_param(i915, &p))
+		return false;
+
+	p.value = saved;
+	return __gem_context_set_param(i915, &p) == 0;
+}
+
+static void pi_active(int i915)
+{
+	igt_spin_t *spin = igt_spin_new(i915);
+	unsigned long count = 0;
+	bool blocked = false;
+	struct pollfd pfd;
+	int lnk[2];
+	int *done;
+
+	igt_require(gem_scheduler_enabled(i915));
+	igt_require(has_persistence(i915)); /* for graceful error recovery */
+
+	done = mmap(NULL, 4096, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
+	igt_assert(done != MAP_FAILED);
+
+	igt_assert(pipe(lnk) == 0);
+
+	igt_fork(child, 1) {
+		struct sigaction sa = { .sa_handler = alarm_handler };
+
+		sigaction(SIGHUP, &sa, NULL);
+
+		do {
+			uint32_t ctx;
+
+			if (__gem_context_clone(i915, 0,
+						I915_CONTEXT_CLONE_ENGINES |
+						I915_CONTEXT_CLONE_VM,
+						0, &ctx))
+				break;
+
+			gem_context_set_persistence(i915, ctx, false);
+			if (READ_ONCE(*done))
+				break;
+
+			spin->execbuf.rsvd1 = ctx;
+			if (__execbuf(i915, &spin->execbuf))
+				break;
+
+			count++;
+			write(lnk[1], &count, sizeof(count));
+		} while (1);
+	}
+
+	pfd.fd = lnk[0];
+	pfd.events = POLLIN;
+	close(lnk[1]);
+
+	igt_until_timeout(90) {
+		if (poll(&pfd, 1, 1000) == 0) {
+			igt_info("Child blocked after %lu active contexts\n",
+				 count);
+			blocked = true;
+			break;
+		}
+		read(pfd.fd, &count, sizeof(count));
+	}
+
+	if (blocked) {
+		struct sigaction old_sa, sa = { .sa_handler = alarm_handler };
+		struct itimerval itv;
+
+		sigaction(SIGALRM, &sa, &old_sa);
+		itv.it_value.tv_sec = 0;
+		itv.it_value.tv_usec = 250000; /* 250ms */
+		setitimer(ITIMER_REAL, &itv, NULL);
+
+		igt_assert_f(__execbuf(i915, &spin->execbuf) == 0,
+			     "Active execbuf blocked for more than 250ms by %lu child contexts\n",
+			     count);
+
+		memset(&itv, 0, sizeof(itv));
+		setitimer(ITIMER_REAL, &itv, NULL);
+		sigaction(SIGALRM, &old_sa, NULL);
+	} else {
+		igt_info("Not blocked after %lu active contexts\n",
+			 count);
+	}
+
+	*done = 1;
+	kill_children(SIGHUP);
+	igt_waitchildren();
+	gem_quiescent_gpu(i915);
+	close(lnk[0]);
+
+	munmap(done, 4096);
+}
+
 igt_main
 {
 	const uint32_t batch[2] = { 0, MI_BATCH_BUFFER_END };
@@ -375,6 +492,9 @@ igt_main
 	igt_subtest("basic-nohangcheck")
 		nohangcheck_hostile(fd);
 
+	igt_subtest("basic-pi-active")
+		pi_active(fd);
+
 	igt_subtest("reset-pin-leak") {
 		int i;
 
-- 
2.26.2



More information about the igt-dev mailing list