Igt-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Matthew Brost <matthew.brost@intel.com>
To: Jan Maslak <jan.maslak@intel.com>
Cc: <igt-dev@lists.freedesktop.org>
Subject: Re: [PATCH v2 1/2] tests/intel/xe_exec_basic: Add timeline syncobj exec tests
Date: Fri, 31 Jul 2026 02:14:20 -0700	[thread overview]
Message-ID: <amxnbPvazpIPZK6z@gsse-cloud1.jf.intel.com> (raw)
In-Reply-To: <20260622122009.3350724-2-jan.maslak@intel.com>

On Mon, Jun 22, 2026 at 02:20:08PM +0200, Jan Maslak wrote:
> Add Xe-specific timeline syncobj coverage for xe_exec.
> 
> The input test covers waiting on an older completed timeline point
> after the same syncobj has already advanced to a later point. This is
> the shape that exposed the historical xe_exec regression when exec
> parsing reached an input timeline sync with no backing fence.
> 
> Also add a timeline syncobj output test to verify Xe signals the
> requested timeline point when execution completes.
> 
> Keep the coverage in xe_exec_basic so the test exercises the Xe exec
> uAPI directly instead of only the generic syncobj timeline helpers.
> 
> Signed-off-by: Jan Maslak <jan.maslak@intel.com>
> ---
>  tests/intel/xe_exec_basic.c | 223 ++++++++++++++++++++++++++++++++++++
>  1 file changed, 223 insertions(+)
> 
> diff --git a/tests/intel/xe_exec_basic.c b/tests/intel/xe_exec_basic.c
> index 5335bffc41..7b5318919f 100644
> --- a/tests/intel/xe_exec_basic.c
> +++ b/tests/intel/xe_exec_basic.c
> @@ -31,6 +31,209 @@
>  #define DEFER_BIND		(0x1 << 6)
>  #define SPARSE			(0x1 << 7)
>  
> +static void write_store_dword_batch(uint32_t *batch, size_t batch_size,
> +				    uint64_t addr, uint32_t value)
> +{
> +	int b = 0;
> +
> +	/* Build a minimal batch that stores one dword and then terminates. */
> +	batch[b++] = MI_STORE_DWORD_IMM_GEN4;
> +	batch[b++] = addr;
> +	batch[b++] = addr >> 32;
> +	batch[b++] = value;
> +	batch[b++] = MI_BATCH_BUFFER_END;
> +	igt_assert_lte(b, batch_size);
> +	igt_assert_eq(b, 5);
> +}
> +
> +struct timeline_exec_data {
> +	uint32_t batch[16];
> +	uint64_t pad;
> +	uint32_t data;
> +};
> +
> +struct timeline_exec_ctx {
> +	struct timeline_exec_data *data;
> +	struct drm_xe_exec exec;
> +	uint64_t addr;
> +	uint64_t batch_addr;
> +	uint64_t sdi_addr;
> +	uint32_t vm;
> +	uint32_t exec_queue;
> +	uint32_t bo;
> +	size_t bo_size;
> +};
> +
> +static void timeline_exec_ctx_init(int fd,
> +				   struct drm_xe_engine_class_instance *eci,
> +				   struct timeline_exec_ctx *ctx)
> +{
> +	uint64_t batch_offset;
> +	uint64_t sdi_offset;
> +
> +	memset(ctx, 0, sizeof(*ctx));
> +	ctx->addr = 0x1a0000;
> +	ctx->vm = xe_vm_create(fd, 0, 0);
> +	ctx->bo_size = xe_bb_size(fd, sizeof(*ctx->data));
> +	ctx->bo = xe_bo_create(fd, ctx->vm, ctx->bo_size,
> +			       vram_if_possible(fd, eci->gt_id),
> +			       DRM_XE_GEM_CREATE_FLAG_NEEDS_VISIBLE_VRAM);
> +	ctx->data = xe_bo_map(fd, ctx->bo, ctx->bo_size);
> +	ctx->exec_queue = xe_exec_queue_create(fd, ctx->vm, eci, 0);
> +
> +	batch_offset = (char *)&ctx->data->batch - (char *)ctx->data;
> +	ctx->batch_addr = ctx->addr + batch_offset;
> +	sdi_offset = (char *)&ctx->data->data - (char *)ctx->data;
> +	ctx->sdi_addr = ctx->addr + sdi_offset;
> +
> +	ctx->exec = (struct drm_xe_exec) {
> +		.num_batch_buffer = 1,
> +		.exec_queue_id = ctx->exec_queue,
> +		.address = ctx->batch_addr,
> +	};
> +	xe_vm_bind_sync(fd, ctx->vm, ctx->bo, 0, ctx->addr, ctx->bo_size);
> +}
> +
> +static void timeline_exec_ctx_fini(int fd, struct timeline_exec_ctx *ctx)
> +{
> +	xe_vm_unbind_sync(fd, ctx->vm, 0, ctx->addr, ctx->bo_size);
> +	xe_exec_queue_destroy(fd, ctx->exec_queue);
> +	munmap(ctx->data, ctx->bo_size);
> +	gem_close(fd, ctx->bo);
> +	xe_vm_destroy(fd, ctx->vm);
> +}
> +
> +/**
> + * SUBTEST: timeline-syncobj-exec-completed-point-in
> + * Description: Submit xe_exec with an input dependency on an older completed
> + *              timeline point after the same syncobj has already advanced to a
> + *              later point, and verify Xe still accepts the completed
> + *              dependency and runs the batch.
> + * Test category: functionality test
> + */
> +
> +static void
> +test_timeline_syncobj_exec_completed_point_in(int fd,
> +					      struct drm_xe_engine_class_instance *eci)
> +{
> +	struct timeline_exec_ctx ctx;
> +	struct drm_xe_exec exec;
> +	uint64_t input_wait_point = 1;
> +	uint64_t input_signal_point = 2;
> +	uint32_t input_syncobj;
> +	uint32_t completion_syncobj;
> +	struct drm_xe_sync prime_sync;
> +	struct drm_xe_sync input_sync;
> +	struct drm_xe_sync completion_sync;
> +	const uint32_t prime_value = 0x1234abcd;
> +	const uint32_t expected = 0xc0ffee;
> +
> +	timeline_exec_ctx_init(fd, eci, &ctx);
> +	exec = ctx.exec;
> +	input_syncobj = syncobj_create(fd, 0);
> +
> +	/* Step 1: signal point 1 on this timeline from Xe work. */
> +	write_store_dword_batch(ctx.data->batch, ARRAY_SIZE(ctx.data->batch),
> +				ctx.sdi_addr, prime_value);
> +	ctx.data->data = 0;
> +	prime_sync = (struct drm_xe_sync) {
> +		.type = DRM_XE_SYNC_TYPE_TIMELINE_SYNCOBJ,
> +		.flags = DRM_XE_SYNC_FLAG_SIGNAL,
> +		.handle = input_syncobj,
> +		.timeline_value = input_wait_point,
> +	};
> +	exec.syncs = to_user_pointer(&prime_sync);
> +	exec.num_syncs = 1;
> +	xe_exec(fd, &exec);
> +	igt_assert(syncobj_timeline_wait(fd, &input_syncobj,
> +					 &input_wait_point, 1,
> +					 INT64_MAX, 0, NULL));
> +	igt_assert_eq(ctx.data->data, prime_value);
> +
> +	/* Step 2: signal point 2 on the same timeline so point 1 becomes older. */
> +	ctx.data->data = 0;
> +	prime_sync.timeline_value = input_signal_point;
> +	xe_exec(fd, &exec);
> +	igt_assert(syncobj_timeline_wait(fd, &input_syncobj,
> +					 &input_signal_point, 1,
> +					 INT64_MAX, 0, NULL));
> +	igt_assert_eq(ctx.data->data, prime_value);
> +
> +	/* Step 3: submit the real exec with point 1 as the input dependency. */
> +	write_store_dword_batch(ctx.data->batch, ARRAY_SIZE(ctx.data->batch),
> +				ctx.sdi_addr, expected);
> +	ctx.data->data = 0;
> +	input_sync = (struct drm_xe_sync) {
> +		.type = DRM_XE_SYNC_TYPE_TIMELINE_SYNCOBJ,
> +		.flags = 0,
> +		.handle = input_syncobj,
> +		.timeline_value = input_wait_point,
> +	};
> +	completion_syncobj = syncobj_create(fd, 0);
> +
> +	/* Use a binary completion fence so the input-only case stays input-only. */
> +	completion_sync = (struct drm_xe_sync) {
> +		.type = DRM_XE_SYNC_TYPE_SYNCOBJ,
> +		.flags = DRM_XE_SYNC_FLAG_SIGNAL,
> +		.handle = completion_syncobj,
> +	};
> +	{
> +		struct drm_xe_sync exec_syncs[] = { input_sync, completion_sync };
> +
> +		/* Wait for timeline point 1, then signal the binary completion syncobj. */
> +		exec.syncs = to_user_pointer(exec_syncs);
> +		exec.num_syncs = ARRAY_SIZE(exec_syncs);
> +		xe_exec(fd, &exec);
> +	}
> +	igt_assert(syncobj_wait(fd, &completion_syncobj, 1, INT64_MAX, 0, NULL));
> +	igt_assert_eq(ctx.data->data, expected);
> +
> +	syncobj_destroy(fd, completion_syncobj);
> +	syncobj_destroy(fd, input_syncobj);
> +	timeline_exec_ctx_fini(fd, &ctx);
> +}
> +
> +/**
> + * SUBTEST: timeline-syncobj-exec-out
> + * Description: Submit xe_exec with a timeline syncobj output and verify Xe
> + *              signals the requested timeline point when execution completes.
> + * Test category: functionality test
> + */
> +
> +static void test_timeline_syncobj_exec_out(int fd,
> +					   struct drm_xe_engine_class_instance *eci)
> +{
> +	struct timeline_exec_ctx ctx;
> +	struct drm_xe_exec exec;
> +	uint64_t output_point = 2;
> +	uint32_t output_syncobj;
> +	struct drm_xe_sync output_sync;
> +	const uint32_t expected = 0xc0ffee;
> +
> +	timeline_exec_ctx_init(fd, eci, &ctx);
> +	exec = ctx.exec;
> +	output_syncobj = syncobj_create(fd, 0);
> +
> +	write_store_dword_batch(ctx.data->batch, ARRAY_SIZE(ctx.data->batch),
> +				ctx.sdi_addr, expected);
> +	ctx.data->data = 0;
> +	output_sync = (struct drm_xe_sync) {
> +		.type = DRM_XE_SYNC_TYPE_TIMELINE_SYNCOBJ,
> +		.flags = DRM_XE_SYNC_FLAG_SIGNAL,
> +		.handle = output_syncobj,
> +		.timeline_value = output_point,
> +	};
> +	exec.syncs = to_user_pointer(&output_sync);
> +	exec.num_syncs = 1;
> +	xe_exec(fd, &exec);
> +	igt_assert(syncobj_timeline_wait(fd, &output_syncobj, &output_point, 1,
> +					 INT64_MAX, 0, NULL));
> +	igt_assert_eq(ctx.data->data, expected);
> +
> +	syncobj_destroy(fd, output_syncobj);
> +	timeline_exec_ctx_fini(fd, &ctx);
> +}
> +
>  /**
>   * SUBTEST: once-%s
>   * Description: Run %arg[1] test only once
> @@ -348,6 +551,26 @@ int igt_main()
>  	igt_fixture()
>  		fd = drm_open_driver(DRIVER_XE);
>  
> +	igt_subtest_with_dynamic("timeline-syncobj-exec-completed-point-in") {
> +		igt_require(igt_has_drm_cap(fd, DRM_CAP_SYNCOBJ_TIMELINE));
> +
> +		xe_for_each_engine(fd, hwe)
> +			igt_dynamic_f("%s%d",
> +				      xe_engine_class_short_string(hwe->engine_class),
> +				      hwe->engine_instance)
> +				test_timeline_syncobj_exec_completed_point_in(fd, hwe);
> +	}

My preference would be a flag to existing sections which says 'use
timesync objs' and the main test loop switches between normal syncobjs
or timelines.

Matt 

> +
> +	igt_subtest_with_dynamic("timeline-syncobj-exec-out") {
> +		igt_require(igt_has_drm_cap(fd, DRM_CAP_SYNCOBJ_TIMELINE));
> +
> +		xe_for_each_engine(fd, hwe)
> +			igt_dynamic_f("%s%d",
> +				      xe_engine_class_short_string(hwe->engine_class),
> +				      hwe->engine_instance)
> +				test_timeline_syncobj_exec_out(fd, hwe);
> +	}
> +
>  	for (const struct section *s = sections; s->name; s++) {
>  		igt_subtest_with_dynamic_f("once-%s", s->name)
>  			xe_for_each_engine(fd, hwe)
> -- 
> 2.43.0
> 

  reply	other threads:[~2026-07-31  9:15 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-22 12:20 [PATCH v2 0/2] tests/intel: Add Xe timeline syncobj coverage Jan Maslak
2026-06-22 12:20 ` [PATCH v2 1/2] tests/intel/xe_exec_basic: Add timeline syncobj exec tests Jan Maslak
2026-07-31  9:14   ` Matthew Brost [this message]
2026-06-22 12:20 ` [PATCH v2 2/2] tests/intel/xe_vm: Add timeline syncobj vm_bind tests Jan Maslak
2026-06-22 21:19 ` ✓ Xe.CI.BAT: success for tests/intel: Add Xe timeline syncobj coverage Patchwork
2026-06-22 21:20 ` ✓ i915.CI.BAT: " Patchwork
2026-06-23  2:31 ` ✓ Xe.CI.FULL: " Patchwork
2026-06-23  4:32 ` ✗ i915.CI.Full: failure " Patchwork

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=amxnbPvazpIPZK6z@gsse-cloud1.jf.intel.com \
    --to=matthew.brost@intel.com \
    --cc=igt-dev@lists.freedesktop.org \
    --cc=jan.maslak@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox