[igt-dev] [Intel-gfx] [PATCH i-g-t] igt/gem_exec_gttfill: Avoid pwrite into busy handle
Tvrtko Ursulin
tvrtko.ursulin at linux.intel.com
Fri Jun 29 15:15:04 UTC 2018
On 28/06/2018 22:35, Chris Wilson wrote:
> The goal of gem_exec_gttfill is to exercise execbuf under heavy GTT
> pressure (by trying to execute more objects than may fit into the GTT).
> We spread the same set of handles across different processes, with the
> result that each would occasionally stall waiting for execution of an
> unrelated batch, limiting the pressure we were applying. If we using a
> steaming write via a WC pointer, we can avoid the serialisation penalty
> and so submit faster.
>
> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
> ---
> tests/gem_exec_gttfill.c | 66 +++++++++++++++++++++++++---------------
> 1 file changed, 42 insertions(+), 24 deletions(-)
>
> diff --git a/tests/gem_exec_gttfill.c b/tests/gem_exec_gttfill.c
> index 4097e4077..efd612bb6 100644
> --- a/tests/gem_exec_gttfill.c
> +++ b/tests/gem_exec_gttfill.c
> @@ -28,18 +28,25 @@ IGT_TEST_DESCRIPTION("Fill the GTT with batches.");
>
> #define BATCH_SIZE (4096<<10)
>
> -static void xchg_u32(void *array, unsigned i, unsigned j)
> +struct batch {
> + uint32_t handle;
> + void *ptr;
> +};
> +
> +static void xchg_batch(void *array, unsigned int i, unsigned int j)
> {
> - uint32_t *u32 = array;
> - uint32_t tmp = u32[i];
> - u32[i] = u32[j];
> - u32[j] = tmp;
> + struct batch *batches = array;
> + struct batch tmp;
> +
> + tmp = batches[i];
> + batches[i] = batches[j];
> + batches[j] = tmp;
> }
>
> static void submit(int fd, int gen,
> struct drm_i915_gem_execbuffer2 *eb,
> struct drm_i915_gem_relocation_entry *reloc,
> - uint32_t *handles, unsigned count)
> + struct batch *batches, unsigned int count)
> {
> struct drm_i915_gem_exec_object2 obj;
> uint32_t batch[16];
> @@ -80,7 +87,7 @@ static void submit(int fd, int gen,
>
> eb->buffers_ptr = to_user_pointer(&obj);
> for (unsigned i = 0; i < count; i++) {
> - obj.handle = handles[i];
> + obj.handle = batches[i].handle;
> reloc[0].target_handle = obj.handle;
> reloc[1].target_handle = obj.handle;
>
> @@ -88,8 +95,8 @@ static void submit(int fd, int gen,
> reloc[0].presumed_offset = obj.offset;
> reloc[1].presumed_offset = obj.offset;
>
> - gem_write(fd, obj.handle, eb->batch_start_offset,
> - batch, sizeof(batch));
> + memcpy(batches[i].ptr + eb->batch_start_offset,
> + batch, sizeof(batch));
>
> gem_execbuf(fd, eb);
> }
> @@ -103,7 +110,7 @@ static void fillgtt(int fd, unsigned ring, int timeout)
> struct drm_i915_gem_execbuffer2 execbuf;
> struct drm_i915_gem_relocation_entry reloc[2];
> volatile uint64_t *shared;
> - unsigned *handles;
> + struct batch *batches;
> unsigned engines[16];
> unsigned nengine;
> unsigned engine;
> @@ -145,29 +152,38 @@ static void fillgtt(int fd, unsigned ring, int timeout)
> if (gen < 6)
> execbuf.flags |= I915_EXEC_SECURE;
>
> - handles = calloc(count, sizeof(handles));
> - igt_assert(handles);
> - for (unsigned i = 0; i < count; i++)
> - handles[i] = gem_create(fd, BATCH_SIZE);
> + batches = calloc(count, sizeof(*batches));
> + igt_assert(batches);
> + for (unsigned i = 0; i < count; i++) {
> + batches[i].handle = gem_create(fd, BATCH_SIZE);
> + batches[i].ptr =
> + __gem_mmap__wc(fd, batches[i].handle,
> + 0, BATCH_SIZE, PROT_WRITE);
> + if (!batches[i].ptr) {
> + batches[i].ptr =
> + __gem_mmap__gtt(fd, batches[i].handle,
> + BATCH_SIZE, PROT_WRITE);
> + }
> + igt_require(batches[i].ptr);
Not assert?
> + }
>
> /* Flush all memory before we start the timer */
> - submit(fd, gen, &execbuf, reloc, handles, count);
> + submit(fd, gen, &execbuf, reloc, batches, count);
>
> igt_fork(child, nengine) {
> uint64_t cycles = 0;
> hars_petruska_f54_1_random_perturb(child);
> - igt_permute_array(handles, count, xchg_u32);
> + igt_permute_array(batches, count, xchg_batch);
> execbuf.batch_start_offset = child*64;
> execbuf.flags |= engines[child];
> igt_until_timeout(timeout) {
> - submit(fd, gen, &execbuf, reloc, handles, count);
> + submit(fd, gen, &execbuf, reloc, batches, count);
> for (unsigned i = 0; i < count; i++) {
> - uint32_t handle = handles[i];
> - uint64_t buf[2];
> + uint64_t offset, delta;
>
> - gem_read(fd, handle, reloc[1].offset, &buf[0], sizeof(buf[0]));
> - gem_read(fd, handle, reloc[0].delta, &buf[1], sizeof(buf[1]));
> - igt_assert_eq_u64(buf[0], buf[1]);
No flushing or domain management needed, especially since it can be
either wc or gtt mmap?
> + offset = *(uint64_t *)(batches[i].ptr + reloc[1].offset);
> + delta = *(uint64_t *)(batches[i].ptr + reloc[0].delta);
> + igt_assert_eq_u64(offset, delta);
> }
> cycles++;
> }
> @@ -176,8 +192,10 @@ static void fillgtt(int fd, unsigned ring, int timeout)
> }
> igt_waitchildren();
>
> - for (unsigned i = 0; i < count; i++)
> - gem_close(fd, handles[i]);
> + for (unsigned i = 0; i < count; i++) {
> + munmap(batches[i].ptr, BATCH_SIZE);
> + gem_close(fd, batches[i].handle);
> + }
>
> shared[nengine] = 0;
> for (unsigned i = 0; i < nengine; i++)
>
Regards,
Tvrtko
More information about the igt-dev
mailing list