[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