[igt-dev] [PATCH i-g-t] i915/gem_exec_alignment: Exercise potential priority inversion
Chris Wilson
chris at chris-wilson.co.uk
Wed Apr 1 18:27:03 UTC 2020
From: Dominik Grzegorzek <dominik.grzegorzek at intel.com>
A low priority client should not block a high priority client. In this
case we check that if a low priority client poisons its own GTT and so
its execbuf may take ages to process, a high priority client can still
execute in parallel.
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek at intel.com>
Cc: Zbigniew Kempczyński <zbigniew.kempczynski at intel.com>
Reviewed-by: Chris Wilson <chris at chris-wilson.co.uk>
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
tests/i915/gem_exec_alignment.c | 116 ++++++++++++++++++++++++++++++++
tests/intel-ci/blacklist.txt | 1 -
2 files changed, 116 insertions(+), 1 deletion(-)
diff --git a/tests/i915/gem_exec_alignment.c b/tests/i915/gem_exec_alignment.c
index 2895aee1e..730d3b778 100644
--- a/tests/i915/gem_exec_alignment.c
+++ b/tests/i915/gem_exec_alignment.c
@@ -38,6 +38,8 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/ioctl.h>
+#include <signal.h>
+#include <sched.h>
#include "drm.h"
@@ -121,6 +123,118 @@ static uint32_t batch_create(int i915, unsigned long sz)
return handle;
}
+static void naughty_child(int i915, int link)
+{
+ struct drm_i915_gem_execbuffer2 execbuf;
+ struct drm_i915_gem_exec_object2 *obj;
+ uint64_t gtt_size, ram_size, count;
+ struct timespec tv = {};
+
+ gtt_size = gem_aperture_size(i915); /* We have to *share* our GTT! */
+ ram_size = intel_get_total_ram_mb();
+ ram_size *= 1024 * 1024;
+
+ count = min(gtt_size, ram_size) / 16384;
+ if (count > file_max()) /* vfs cap */
+ count = file_max();
+ intel_require_memory(count, 4096, CHECK_RAM);
+
+ /* Fill the low-priority address space */
+ obj = calloc(sizeof(*obj), count);
+ igt_assert(obj);
+ for (unsigned long i = 0; i < count; i++) {
+ obj[i].handle = batch_create(i915, 4096);
+ if ((gtt_size - 1) >> 32)
+ obj[i].flags |= EXEC_OBJECT_SUPPORTS_48B_ADDRESS;
+ obj[i].alignment = 4096;
+ }
+
+ memset(&execbuf, 0, sizeof(execbuf));
+ execbuf.buffers_ptr = to_user_pointer(obj);
+ execbuf.buffer_count = count;
+ execbuf.rsvd1 = gem_context_create(i915);
+ gem_execbuf(i915, &execbuf);
+
+ /* Calibrate a long execbuf() */
+ for (unsigned long i = 0; i < count; i++)
+ obj[i].alignment = 8192;
+
+ execbuf.buffer_count = 2;
+ while (igt_seconds_elapsed(&tv) < 2) {
+ execbuf.buffer_count <<= 1;
+ gem_execbuf(i915, &execbuf);
+ }
+ execbuf.buffer_count <<= 1;
+ if (execbuf.buffer_count > count)
+ execbuf.buffer_count = count;
+ igt_debug("Using %u buffers to delay execbuf\n", execbuf.buffer_count);
+
+ for (unsigned long i = 0; i < count; i++)
+ obj[i].alignment = 16384;
+
+ write(link, &tv, sizeof(tv));
+
+ igt_debug("Executing naughty execbuf\n");
+ igt_nsec_elapsed(memset(&tv, 0, sizeof(tv)));
+ gem_execbuf(i915, &execbuf); /* this should take over 2s */
+ igt_info("Naughty client took %'"PRIu64"ns\n",
+ igt_nsec_elapsed(&tv));
+
+ gem_context_destroy(i915, execbuf.rsvd1);
+ for (unsigned long i = 0; i < count; i++)
+ gem_close(i915, obj[i].handle);
+ free(obj);
+}
+
+static void prio_inversion(int i915)
+{
+ struct drm_i915_gem_exec_object2 obj = {
+ .handle = batch_create(i915, 4095)
+ };
+ struct drm_i915_gem_execbuffer2 execbuf = {
+ .buffers_ptr = to_user_pointer(&obj),
+ .buffer_count = 1,
+ };
+ struct timespec tv;
+ uint64_t elapsed;
+ int link[2];
+
+ /*
+ * First low priority client create mass of holes in their
+ * own address space, then launch a batch with oodles of object with
+ * alignment that doesn't match previous one. While lp execbufer
+ * is performing we want to start high priority task
+ * and we expect it will not be blocked.
+ */
+
+ igt_require(gem_uses_full_ppgtt(i915));
+ igt_assert(pipe(link) == 0);
+
+ /* Prime our prestine context */
+ gem_execbuf(i915, &execbuf);
+
+ igt_fork(child, 1)
+ naughty_child(i915, link[1]);
+
+ igt_debug("Waiting for naughty client\n");
+ read(link[0], &tv, sizeof(tv));
+ igt_debug("Ready...\n");
+ sleep(1); /* let the naughty execbuf begin */
+ igt_debug("Go!\n");
+
+ igt_nsec_elapsed(memset(&tv, 0, sizeof(tv)));
+ gem_execbuf(i915, &execbuf);
+ elapsed = igt_nsec_elapsed(&tv);
+ igt_info("Normal client took %'"PRIu64"ns\n", elapsed);
+
+ igt_waitchildren();
+ gem_close(i915, obj.handle);
+
+ igt_assert(elapsed < 10 * 1000 * 1000); /* 10ms */
+ close(link[0]);
+ close(link[1]);
+}
+
static void many(int fd, int timeout)
{
struct drm_i915_gem_exec_object2 *execobj;
@@ -281,4 +395,6 @@ igt_main
single(fd);
igt_subtest("many")
many(fd, 20);
+ igt_subtest("pi")
+ prio_inversion(fd);
}
diff --git a/tests/intel-ci/blacklist.txt b/tests/intel-ci/blacklist.txt
index 1b49e8bb7..c819fee51 100644
--- a/tests/intel-ci/blacklist.txt
+++ b/tests/intel-ci/blacklist.txt
@@ -24,7 +24,6 @@ igt at gem_ctx_switch(@.*)?
igt at gem_ctx_thrash(@.*)?
igt at gem_evict_alignment(@.*)?
igt at gem_evict_everything(@.*)?
-igt at gem_exec_alignment@(?!.*single).*
igt at gem_exec_big@(?!.*single).*
igt at gem_exec_capture@many-(?!4K-).*
igt at gem_exec_fence@(?!.*basic).*
--
2.26.0
More information about the igt-dev
mailing list