[igt-dev] [PATCH i-g-t v2 1/2] tests/gem_softpin: Add prime reopen eviction subtest
Kamil Konieczny
kamil.konieczny at linux.intel.com
Thu Dec 8 20:26:53 UTC 2022
On 2022-12-06 at 18:52:21 +0100, Zbigniew Kempczyński wrote:
> For set of objects exported via prime fd verify objects can be randomly
> opened, binded, executed and closed. Random open always returns same
> handle id so vma rebind is necessary. Exercise this when objects are
> opened in more opened drm fds.
>
> Signed-off-by: Zbigniew Kempczyński <zbigniew.kempczynski at intel.com>
>
Reviewed-by: Kamil Konieczny <kamil.konieczny at linux.intel.com>
> ---
> v2: put 'all' subtest in dynamic subtest, add sanity check with
> single thread.
> v3: move to prime fd instead flink, clean on dyn subtest failure
> ---
> tests/i915/gem_softpin.c | 181 +++++++++++++++++++++++++++++++++++++++
> 1 file changed, 181 insertions(+)
>
> diff --git a/tests/i915/gem_softpin.c b/tests/i915/gem_softpin.c
> index a85a366408..ad6d3f531c 100644
> --- a/tests/i915/gem_softpin.c
> +++ b/tests/i915/gem_softpin.c
> @@ -1149,6 +1149,167 @@ static void evict_single_offset(int fd, const intel_ctx_t *ctx, int timeout)
> igt_assert_eq(intel_detect_and_clear_missed_interrupts(fd), 0);
> }
>
> +struct thread {
> + pthread_t thread;
> + pthread_mutex_t *mutex;
> + pthread_cond_t *cond;
> + int *scratch;
> + const intel_ctx_t *ctx;
> + unsigned int engine;
> + int fd, *go;
> +};
> +
> +#define NUMOBJ 16
> +
> +static void *thread(void *data)
> +{
> + struct thread *t = data;
> + struct drm_i915_gem_exec_object2 obj[2];
> + struct drm_i915_gem_execbuffer2 execbuf;
> + const intel_ctx_t *ctx = NULL;
> + uint64_t offset_obj, offset_bb;
> + uint32_t batch = MI_BATCH_BUFFER_END;
> + int fd, ret, succeeded = 0;
> +
> + fd = gem_reopen_driver(t->fd);
> + ctx = intel_ctx_create(fd, &t->ctx->cfg);
> + offset_obj = gem_detect_safe_start_offset(fd);
> + offset_bb = ALIGN(offset_obj + 4096, gem_detect_safe_alignment(fd));
> + igt_debug("reopened fd: %d, ctx: %u, object offset: %llx, bb offset: %llx\n",
> + fd, ctx->id, (long long) offset_obj, (long long) offset_bb);
> +
> + pthread_mutex_lock(t->mutex);
> + while (*t->go == 0)
> + pthread_cond_wait(t->cond, t->mutex);
> + pthread_mutex_unlock(t->mutex);
> +
> + memset(obj, 0, sizeof(obj));
> + obj[0].offset = offset_obj;
> + obj[0].flags = EXEC_OBJECT_PINNED | EXEC_OBJECT_WRITE |
> + EXEC_OBJECT_SUPPORTS_48B_ADDRESS;
> + obj[1].handle = gem_create(fd, 4096);
> + obj[1].offset = offset_bb;
> + obj[1].flags |= EXEC_OBJECT_PINNED | EXEC_OBJECT_SUPPORTS_48B_ADDRESS;
> + gem_write(fd, obj[1].handle, 0, &batch, sizeof(batch));
> +
> + memset(&execbuf, 0, sizeof(execbuf));
> + execbuf.buffers_ptr = to_user_pointer(obj);
> + execbuf.buffer_count = 2;
> + execbuf.flags = t->engine;
> + execbuf.flags |= I915_EXEC_HANDLE_LUT;
> + execbuf.flags |= I915_EXEC_NO_RELOC;
> + execbuf.rsvd1 = ctx->id;
> +
> + igt_until_timeout(1) {
> + unsigned int x = rand() % NUMOBJ;
> +
> + obj[0].handle = prime_fd_to_handle(fd, t->scratch[x]);
> +
> + ret = __gem_execbuf(fd, &execbuf);
> + if (ret)
> + igt_debug("<fd: %d, ctx: %u, x: %2u, engine: %d> "
> + "object handle: %2u (prime fd: %2d), bb handle: %2u, "
> + "offsets: %llx, %llx [ret: %d, succeeded: %d]\n",
> + fd, ctx->id, x, t->engine,
> + obj[0].handle, t->scratch[x], obj[1].handle,
> + (long long) obj[0].offset,
> + (long long) obj[1].offset, ret, succeeded);
> + else
> + succeeded++;
> +
> + gem_close(fd, obj[0].handle);
> +
> + if (ret)
> + break;
> + }
> +
> + if (!ret)
> + igt_debug("<fd: %d, ctx: %u, engine: %d> succeeded: %d\n",
> + fd, ctx->id, t->engine, succeeded);
> + intel_ctx_destroy(fd, ctx);
> + gem_close(fd, obj[1].handle);
> + close(fd);
> +
> + return (void *) from_user_pointer(ret);
> +}
> +
> +static void evict_prime(int fd, const intel_ctx_t *ctx,
> + const struct intel_execution_engine2 *engine,
> + int numthreads)
> +{
> + unsigned int engines[I915_EXEC_RING_MASK + 1], nengine;
> + uint32_t handle[NUMOBJ];
> + int scratch[NUMOBJ];
> + struct thread *threads;
> + pthread_mutex_t mutex;
> + pthread_cond_t cond;
> + int go;
> + int i;
> + bool failed = false;
> +
> + igt_require(igt_allow_unlimited_files());
> +
> + nengine = 0;
> + if (!engine) {
> + struct intel_execution_engine2 *e;
> +
> + for_each_ctx_engine(fd, ctx, e)
> + engines[nengine++] = e->flags;
> + } else {
> + engines[nengine++] = engine->flags;
> + }
> + igt_require(nengine);
> +
> + for (i = 0; i < NUMOBJ; i++) {
> + handle[i] = gem_create(fd, 4096);
> + scratch[i] = prime_handle_to_fd(fd, handle[i]);
> + }
> +
> + threads = calloc(numthreads, sizeof(struct thread));
> + igt_assert(numthreads);
> +
> + intel_detect_and_clear_missed_interrupts(fd);
> + pthread_mutex_init(&mutex, 0);
> + pthread_cond_init(&cond, 0);
> + go = 0;
> +
> + for (i = 0; i < numthreads; i++) {
> + threads[i].fd = fd;
> + threads[i].ctx = ctx;
> + threads[i].engine = engines[i % nengine];
> + threads[i].scratch = scratch;
> + threads[i].mutex = &mutex;
> + threads[i].cond = &cond;
> + threads[i].go = &go;
> +
> + pthread_create(&threads[i].thread, 0, thread, &threads[i]);
> + }
> +
> + pthread_mutex_lock(&mutex);
> + go = numthreads;
> + pthread_cond_broadcast(&cond);
> + pthread_mutex_unlock(&mutex);
> +
> + for (i = 0; i < numthreads; i++) {
> + void *retp;
> + int ret;
> +
> + pthread_join(threads[i].thread, &retp);
> + ret = (int) to_user_pointer(retp);
> + if (ret)
> + failed = true;
> + }
> +
> + for (i = 0; i < NUMOBJ; i++) {
> + gem_close(fd, handle[i]);
> + close(scratch[i]);
> + }
> +
> + igt_assert_eq(intel_detect_and_clear_missed_interrupts(fd), 0);
> + free(threads);
> + igt_assert_eq(failed, false);
> +}
> +
> static void make_batch(int i915, uint32_t handle, uint64_t size)
> {
> uint32_t *bb = gem_mmap__device_coherent(i915, handle, 0, size, PROT_WRITE);
> @@ -1307,6 +1468,26 @@ igt_main
> igt_describe("Use same offset for all engines and for different handles.");
> igt_subtest("evict-single-offset")
> evict_single_offset(fd, ctx, 20);
> +
> + igt_describe("Check eviction of vma on importing prime fd in reopened "
> + "drm fd in single thread");
> + igt_subtest_with_dynamic("evict-prime-sanity-check") {
> + for_each_ctx_engine(fd, ctx, e) {
> + igt_dynamic(e->name)
> + evict_prime(fd, ctx, e, 1);
> + }
> + igt_dynamic("all")
> + evict_prime(fd, ctx, NULL, 1);
> + }
> + igt_describe("Check eviction of vma on importing prime fd in reopened drm fds");
> + igt_subtest_with_dynamic("evict-prime") {
> + for_each_ctx_engine(fd, ctx, e) {
> + igt_dynamic(e->name)
> + evict_prime(fd, ctx, e, 4);
> + }
> + igt_dynamic("all")
> + evict_prime(fd, ctx, NULL, 4);
> + }
> }
>
> igt_describe("Check start offset and alignment detection.");
> --
> 2.34.1
>
More information about the igt-dev
mailing list