We queue N low priority hanging batches across the engines and check that out high priority write over takes them. Signed-off-by: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx> --- lib/igt_dummyload.c | 20 ++++-- lib/igt_dummyload.h | 10 ++- tests/gem_busy.c | 4 +- tests/gem_exec_fence.c | 2 +- tests/gem_exec_reloc.c | 6 +- tests/gem_exec_schedule.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++ tests/gem_shrink.c | 4 +- tests/gem_spin_batch.c | 4 +- tests/gem_wait.c | 2 +- tests/kms_busy.c | 8 ++- tests/kms_flip.c | 4 +- tests/pm_rps.c | 2 +- 12 files changed, 197 insertions(+), 25 deletions(-) diff --git a/lib/igt_dummyload.c b/lib/igt_dummyload.c index 00c6a030..5ad386a5 100644 --- a/lib/igt_dummyload.c +++ b/lib/igt_dummyload.c @@ -46,6 +46,8 @@ #define ENGINE_MASK (I915_EXEC_RING_MASK | LOCAL_I915_EXEC_BSD_MASK) +#define MI_ARB_CHK (0x5 << 23) + static const int BATCH_SIZE = 4096; static IGT_LIST(spin_list); @@ -61,7 +63,8 @@ fill_reloc(struct drm_i915_gem_relocation_entry *reloc, } static void emit_recursive_batch(igt_spin_t *spin, - int fd, int engine, unsigned int dep) + int fd, uint32_t ctx, unsigned engine, + uint32_t dep) { #define SCRATCH 0 #define BATCH 1 @@ -112,9 +115,13 @@ static void emit_recursive_batch(igt_spin_t *spin, spin->batch = batch; spin->handle = obj[BATCH].handle; + /* Allow ourselves to be preempted */ + *batch++ = MI_ARB_CHK; + /* recurse */ fill_reloc(&relocs[obj[BATCH].relocation_count], - obj[BATCH].handle, 1, I915_GEM_DOMAIN_COMMAND, 0); + obj[BATCH].handle, (batch - spin->batch) + 1, + I915_GEM_DOMAIN_COMMAND, 0); if (gen >= 8) { *batch++ = MI_BATCH_BUFFER_START | 1 << 8 | 1; *batch++ = 0; @@ -135,6 +142,7 @@ static void emit_recursive_batch(igt_spin_t *spin, obj[BATCH].relocs_ptr = to_user_pointer(relocs); execbuf.buffers_ptr = to_user_pointer(obj + (2 - execbuf.buffer_count)); + execbuf.rsvd1 = ctx; for (i = 0; i < nengine; i++) { execbuf.flags &= ~ENGINE_MASK; @@ -144,14 +152,14 @@ static void emit_recursive_batch(igt_spin_t *spin, } igt_spin_t * -__igt_spin_batch_new(int fd, int engine, unsigned int dep) +__igt_spin_batch_new(int fd, uint32_t ctx, unsigned engine, uint32_t dep) { igt_spin_t *spin; spin = calloc(1, sizeof(struct igt_spin)); igt_assert(spin); - emit_recursive_batch(spin, fd, engine, dep); + emit_recursive_batch(spin, fd, ctx, engine, dep); igt_assert(gem_bo_busy(fd, spin->handle)); igt_list_add(&spin->link, &spin_list); @@ -175,11 +183,11 @@ __igt_spin_batch_new(int fd, int engine, unsigned int dep) * Structure with helper internal state for igt_spin_batch_free(). */ igt_spin_t * -igt_spin_batch_new(int fd, int engine, unsigned int dep) +igt_spin_batch_new(int fd, uint32_t ctx, unsigned engine, uint32_t dep) { igt_require_gem(fd); - return __igt_spin_batch_new(fd, engine, dep); + return __igt_spin_batch_new(fd, ctx, engine, dep); } static void notify(union sigval arg) diff --git a/lib/igt_dummyload.h b/lib/igt_dummyload.h index 340cada0..215425f7 100644 --- a/lib/igt_dummyload.h +++ b/lib/igt_dummyload.h @@ -37,8 +37,14 @@ typedef struct igt_spin { uint32_t *batch; } igt_spin_t; -igt_spin_t *__igt_spin_batch_new(int fd, int engine, unsigned int dep); -igt_spin_t *igt_spin_batch_new(int fd, int engine, unsigned int dep); +igt_spin_t *__igt_spin_batch_new(int fd, + uint32_t ctx, + unsigned engine, + uint32_t dep); +igt_spin_t *igt_spin_batch_new(int fd, + uint32_t ctx, + unsigned engine, + uint32_t dep); void igt_spin_batch_set_timeout(igt_spin_t *spin, int64_t ns); void igt_spin_batch_end(igt_spin_t *spin); void igt_spin_batch_free(int fd, igt_spin_t *spin); diff --git a/tests/gem_busy.c b/tests/gem_busy.c index 8702dd7e..58aa5ee5 100644 --- a/tests/gem_busy.c +++ b/tests/gem_busy.c @@ -460,7 +460,7 @@ static bool has_semaphores(int fd) static bool has_extended_busy_ioctl(int fd) { - igt_spin_t *spin = igt_spin_batch_new(fd, I915_EXEC_RENDER, 0); + igt_spin_t *spin = igt_spin_batch_new(fd, 0, I915_EXEC_RENDER, 0); uint32_t read, write; __gem_busy(fd, spin->handle, &read, &write); @@ -471,7 +471,7 @@ static bool has_extended_busy_ioctl(int fd) static void basic(int fd, unsigned ring, unsigned flags) { - igt_spin_t *spin = igt_spin_batch_new(fd, ring, 0); + igt_spin_t *spin = igt_spin_batch_new(fd, 0, ring, 0); struct timespec tv; int timeout; bool busy; diff --git a/tests/gem_exec_fence.c b/tests/gem_exec_fence.c index b094f585..5361390e 100644 --- a/tests/gem_exec_fence.c +++ b/tests/gem_exec_fence.c @@ -424,7 +424,7 @@ static void test_parallel(int fd, unsigned int master) /* Fill the queue with many requests so that the next one has to * wait before it can be executed by the hardware. */ - spin = igt_spin_batch_new(fd, master, c.handle); + spin = igt_spin_batch_new(fd, 0, master, c.handle); resubmit(fd, spin->handle, master, 16); /* Now queue the master request and its secondaries */ diff --git a/tests/gem_exec_reloc.c b/tests/gem_exec_reloc.c index edbc0f13..432a42a9 100644 --- a/tests/gem_exec_reloc.c +++ b/tests/gem_exec_reloc.c @@ -388,7 +388,7 @@ static void basic_reloc(int fd, unsigned before, unsigned after, unsigned flags) } if (flags & ACTIVE) { - spin = igt_spin_batch_new(fd, I915_EXEC_DEFAULT, obj.handle); + spin = igt_spin_batch_new(fd, 0, I915_EXEC_DEFAULT, obj.handle); if (!(flags & HANG)) igt_spin_batch_set_timeout(spin, NSEC_PER_SEC/100); igt_assert(gem_bo_busy(fd, obj.handle)); @@ -454,7 +454,7 @@ static void basic_reloc(int fd, unsigned before, unsigned after, unsigned flags) } if (flags & ACTIVE) { - spin = igt_spin_batch_new(fd, I915_EXEC_DEFAULT, obj.handle); + spin = igt_spin_batch_new(fd, 0, I915_EXEC_DEFAULT, obj.handle); if (!(flags & HANG)) igt_spin_batch_set_timeout(spin, NSEC_PER_SEC/100); igt_assert(gem_bo_busy(fd, obj.handle)); @@ -581,7 +581,7 @@ static void basic_range(int fd, unsigned flags) execbuf.buffer_count = n + 1; if (flags & ACTIVE) { - spin = igt_spin_batch_new(fd, 0, obj[n].handle); + spin = igt_spin_batch_new(fd, 0, 0, obj[n].handle); if (!(flags & HANG)) igt_spin_batch_set_timeout(spin, NSEC_PER_SEC/100); igt_assert(gem_bo_busy(fd, obj[n].handle)); diff --git a/tests/gem_exec_schedule.c b/tests/gem_exec_schedule.c index 1f5ed82b..634f8d1a 100644 --- a/tests/gem_exec_schedule.c +++ b/tests/gem_exec_schedule.c @@ -373,6 +373,153 @@ static void promotion(int fd, unsigned ring) munmap(ptr, 4096); } +static void preempt(int fd, unsigned ring) +{ + uint32_t result = gem_create(fd, 4096); + uint32_t *ptr = gem_mmap__gtt(fd, result, 4096, PROT_READ); + igt_spin_t *spin[16]; + uint32_t ctx[2]; + + ctx[LO] = gem_context_create(fd); + ctx_set_priority(fd, ctx[LO], -MAX_PRIO); + + ctx[HI] = gem_context_create(fd); + ctx_set_priority(fd, ctx[HI], MAX_PRIO); + + for (int n = 0; n < 16; n++) { + spin[n] = igt_spin_batch_new(fd, ctx[LO], ring, 0); + igt_debug("spin[%d].handle=%d\n", n, spin[n]->handle); + + store_dword(fd, ctx[HI], ring, result, 0, n + 1, 0, I915_GEM_DOMAIN_RENDER); + + gem_set_domain(fd, result, I915_GEM_DOMAIN_GTT, 0); + igt_assert_eq_u32(ptr[0], n + 1); + igt_assert(gem_bo_busy(fd, spin[0]->handle)); + } + + for (int n = 0; n < 16; n++) + igt_spin_batch_free(fd, spin[n]); + + gem_context_destroy(fd, ctx[LO]); + gem_context_destroy(fd, ctx[HI]); + + munmap(ptr, 4096); + gem_close(fd, result); +} + +static void preempt_other(int fd, unsigned ring) +{ + uint32_t result = gem_create(fd, 4096); + uint32_t *ptr = gem_mmap__gtt(fd, result, 4096, PROT_READ); + igt_spin_t *spin[16]; + unsigned int other; + unsigned int n, i; + uint32_t ctx[3]; + + /* On each engine, insert + * [NOISE] spinner, + * [LOW] write + * + * Then on our target engine do a [HIGH] write which should then + * prompt its dependent LOW writes in front of the spinner on + * each engine. The purpose of this test is to check that preemption + * can cross engines. + */ + + ctx[LO] = gem_context_create(fd); + ctx_set_priority(fd, ctx[LO], -MAX_PRIO); + + ctx[NOISE] = gem_context_create(fd); + + ctx[HI] = gem_context_create(fd); + ctx_set_priority(fd, ctx[HI], MAX_PRIO); + + n = 0; + for_each_engine(fd, other) { + spin[n] = igt_spin_batch_new(fd, ctx[NOISE], other, 0); + store_dword(fd, ctx[LO], other, + result, (n + 1)*sizeof(uint32_t), n + 1, + 0, I915_GEM_DOMAIN_RENDER); + n++; + } + store_dword(fd, ctx[HI], ring, + result, (n + 1)*sizeof(uint32_t), n + 1, + 0, I915_GEM_DOMAIN_RENDER); + + gem_set_domain(fd, result, I915_GEM_DOMAIN_GTT, 0); + + for (i = 0; i < n; i++) { + igt_assert(gem_bo_busy(fd, spin[i]->handle)); + igt_spin_batch_free(fd, spin[i]); + } + + n++; + for (i = 0; i <= n; i++) + igt_assert_eq_u32(ptr[i], i); + + gem_context_destroy(fd, ctx[LO]); + gem_context_destroy(fd, ctx[NOISE]); + gem_context_destroy(fd, ctx[HI]); + + munmap(ptr, 4096); + gem_close(fd, result); +} + +static void preempt_self(int fd, unsigned ring) +{ + uint32_t result = gem_create(fd, 4096); + uint32_t *ptr = gem_mmap__gtt(fd, result, 4096, PROT_READ); + igt_spin_t *spin[16]; + unsigned int other; + unsigned int n, i; + uint32_t ctx[3]; + + /* On each engine, insert + * [NOISE] spinner, + * [self/LOW] write + * + * Then on our target engine do a [self/HIGH] write which should then + * prompt its dependent self/LOW writes in front of the spinner on + * each engine. The purpose of this test is to check that preemption + * can cross engines. + */ + + ctx[NOISE] = gem_context_create(fd); + + ctx[HI] = gem_context_create(fd); + + n = 0; + ctx_set_priority(fd, ctx[HI], -MAX_PRIO); + for_each_engine(fd, other) { + spin[n] = igt_spin_batch_new(fd, ctx[NOISE], other, 0); + store_dword(fd, ctx[HI], other, + result, (n + 1)*sizeof(uint32_t), n + 1, + 0, I915_GEM_DOMAIN_RENDER); + n++; + } + ctx_set_priority(fd, ctx[HI], MAX_PRIO); + store_dword(fd, ctx[HI], ring, + result, (n + 1)*sizeof(uint32_t), n + 1, + 0, I915_GEM_DOMAIN_RENDER); + + gem_set_domain(fd, result, I915_GEM_DOMAIN_GTT, 0); + + for (i = 0; i < n; i++) { + igt_assert(gem_bo_busy(fd, spin[i]->handle)); + igt_spin_batch_free(fd, spin[i]); + } + + n++; + for (i = 0; i <= n; i++) + igt_assert_eq_u32(ptr[i], i); + + gem_context_destroy(fd, ctx[NOISE]); + gem_context_destroy(fd, ctx[HI]); + + munmap(ptr, 4096); + gem_close(fd, result); +} + static void deep(int fd, unsigned ring) { #define XS 8 @@ -726,6 +873,15 @@ igt_main igt_subtest_f("promotion-%s", e->name) promotion(fd, e->exec_id | e->flags); + igt_subtest_f("preempt-%s", e->name) + preempt(fd, e->exec_id | e->flags); + + igt_subtest_f("preempt-other-%s", e->name) + preempt_other(fd, e->exec_id | e->flags); + + igt_subtest_f("preempt-self-%s", e->name) + preempt_self(fd, e->exec_id | e->flags); + igt_subtest_f("deep-%s", e->name) deep(fd, e->exec_id | e->flags); diff --git a/tests/gem_shrink.c b/tests/gem_shrink.c index 8b09fc80..06f7a301 100644 --- a/tests/gem_shrink.c +++ b/tests/gem_shrink.c @@ -311,9 +311,9 @@ static void reclaim(unsigned engine, int timeout) } while (!*shared); } - spin = igt_spin_batch_new(fd, engine, 0); + spin = igt_spin_batch_new(fd, 0, engine, 0); igt_until_timeout(timeout) { - igt_spin_t *next = __igt_spin_batch_new(fd, engine, 0); + igt_spin_t *next = __igt_spin_batch_new(fd, 0, engine, 0); igt_spin_batch_set_timeout(spin, timeout_100ms); gem_sync(fd, spin->handle); diff --git a/tests/gem_spin_batch.c b/tests/gem_spin_batch.c index 941aa139..24c5d9b7 100644 --- a/tests/gem_spin_batch.c +++ b/tests/gem_spin_batch.c @@ -41,9 +41,9 @@ static void spin(int fd, unsigned int engine, unsigned int timeout_sec) struct timespec itv = { }; uint64_t elapsed; - spin = igt_spin_batch_new(fd, engine, 0); + spin = igt_spin_batch_new(fd, 0, engine, 0); while ((elapsed = igt_nsec_elapsed(&tv)) >> 30 < timeout_sec) { - igt_spin_t *next = __igt_spin_batch_new(fd, engine, 0); + igt_spin_t *next = __igt_spin_batch_new(fd, 0, engine, 0); igt_spin_batch_set_timeout(spin, timeout_100ms - igt_nsec_elapsed(&itv)); diff --git a/tests/gem_wait.c b/tests/gem_wait.c index 591690ad..cf8c8154 100644 --- a/tests/gem_wait.c +++ b/tests/gem_wait.c @@ -110,7 +110,7 @@ static void unplug(struct cork *c) static void basic(int fd, unsigned engine, unsigned flags) { struct cork cork = plug(fd, flags); - igt_spin_t *spin = igt_spin_batch_new(fd, engine, cork.handle); + igt_spin_t *spin = igt_spin_batch_new(fd, 0, engine, cork.handle); struct drm_i915_gem_wait wait = { flags & WRITE ? cork.handle : spin->handle }; diff --git a/tests/kms_busy.c b/tests/kms_busy.c index af7335db..7ff461a9 100644 --- a/tests/kms_busy.c +++ b/tests/kms_busy.c @@ -91,7 +91,8 @@ static void flip_to_fb(igt_display_t *dpy, int pipe, struct timespec tv = { 1, 0 }; struct drm_event_vblank ev; - igt_spin_t *t = igt_spin_batch_new(dpy->drm_fd, ring, fb->gem_handle); + igt_spin_t *t = igt_spin_batch_new(dpy->drm_fd, + 0, ring, fb->gem_handle); if (modeset) { /* @@ -203,7 +204,8 @@ static void test_flip(igt_display_t *dpy, unsigned ring, int pipe, bool modeset) static void test_atomic_commit_hang(igt_display_t *dpy, igt_plane_t *primary, struct igt_fb *busy_fb, unsigned ring) { - igt_spin_t *t = igt_spin_batch_new(dpy->drm_fd, ring, busy_fb->gem_handle); + igt_spin_t *t = igt_spin_batch_new(dpy->drm_fd, + 0, ring, busy_fb->gem_handle); struct pollfd pfd = { .fd = dpy->drm_fd, .events = POLLIN }; unsigned flags = 0; struct drm_event_vblank ev; @@ -290,7 +292,7 @@ static void test_pageflip_modeset_hang(igt_display_t *dpy, igt_display_commit2(dpy, dpy->is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY); - t = igt_spin_batch_new(dpy->drm_fd, ring, fb.gem_handle); + t = igt_spin_batch_new(dpy->drm_fd, 0, ring, fb.gem_handle); do_or_die(drmModePageFlip(dpy->drm_fd, dpy->pipes[pipe].crtc_id, fb.fb_id, DRM_MODE_PAGE_FLIP_EVENT, &fb)); diff --git a/tests/kms_flip.c b/tests/kms_flip.c index ede5fd2b..7fd18587 100644 --- a/tests/kms_flip.c +++ b/tests/kms_flip.c @@ -694,11 +694,11 @@ static unsigned int run_test_step(struct test_output *o) o->current_fb_id = !o->current_fb_id; if (o->flags & TEST_WITH_DUMMY_BCS) - spin_bcs = igt_spin_batch_new(drm_fd, I915_EXEC_BLT, + spin_bcs = igt_spin_batch_new(drm_fd, 0, I915_EXEC_BLT, o->fb_info[o->current_fb_id].gem_handle); if (o->flags & TEST_WITH_DUMMY_RCS) - spin_rcs = igt_spin_batch_new(drm_fd, I915_EXEC_RENDER, + spin_rcs = igt_spin_batch_new(drm_fd, 0, I915_EXEC_RENDER, o->fb_info[o->current_fb_id].gem_handle); if (o->flags & TEST_FB_RECREATE) diff --git a/tests/pm_rps.c b/tests/pm_rps.c index f0455e78..ce01c466 100644 --- a/tests/pm_rps.c +++ b/tests/pm_rps.c @@ -566,7 +566,7 @@ static void boost_freq(int fd, int *boost_freqs) int ring = -1; igt_spin_t *load; - load = igt_spin_batch_new(fd, ring, 0); + load = igt_spin_batch_new(fd, 0, ring, 0); /* Waiting will grant us a boost to maximum */ gem_wait(fd, load->handle, &timeout); -- 2.13.3 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx