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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox