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
>
next prev parent 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.