Igt-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Adam Miszczak <adam.miszczak@linux.intel.com>
To: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>,
	igt-dev@lists.freedesktop.org
Cc: lukasz.laguna@intel.com, tvrtko.ursulin@igalia.com
Subject: Re: [PATCH i-g-t 2/2] benchmarks/gem_wsim: add compute/LR mode support for Xe VMs
Date: Mon, 3 Aug 2026 11:27:48 +0200	[thread overview]
Message-ID: <d9a2e9cc-5357-4c2c-93eb-5bfbd9935835@linux.intel.com> (raw)
In-Reply-To: <20260714151235.1246608-3-marcin.bernatowicz@linux.intel.com>

On 7/14/2026 5:12 PM, Marcin Bernatowicz wrote:
> Introduce new descriptor step:
>      'c' - Enable compute/LR mode for VM N (c.N).
>
> Example:
>
> gem_wsim -w "V.1,c.1,v.1.1,1.BCS.100.0.0,1.CCS.8000000.-1.0,1.BCS.100.-1.1"
> 8.009s elapsed (0.125 workloads/s)
>
> Creates VM 1, enables compute/LR mode on it, assigns context 1 to the VM,
> then runs BCS and CCS work with cross-step dependencies (8s CCS depends
> on the first BCS step, and the final BCS step depends on the CCS step).
>
> Suggested-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
> Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
> Cc: Adam Miszczak <adam.miszczak@linux.intel.com>
> Cc: Lukasz Laguna <lukasz.laguna@intel.com>
> Cc: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
> ---
>   benchmarks/gem_wsim.c  | 171 ++++++++++++++++++++++++++++++++++++-----
>   benchmarks/wsim/README |  17 +++-
>   2 files changed, 165 insertions(+), 23 deletions(-)
>
> diff --git a/benchmarks/gem_wsim.c b/benchmarks/gem_wsim.c
> index b3c46772f..d6638bcdf 100644
> --- a/benchmarks/gem_wsim.c
> +++ b/benchmarks/gem_wsim.c
> @@ -132,6 +132,7 @@ enum w_type {
>   	WORKINGSET,
>   	VM_CREATE,
>   	CTX_VM,
> +	VM_COMPUTE_MODE,
>   };
>   
>   struct dep_entry {
> @@ -246,6 +247,7 @@ struct vm {
>   	uint32_t id;
>   	bool declared;
>   	bool compute_mode;
> +	uint32_t bind_exec_queue;
>   	uint64_t ahnd;
>   };
>   
> @@ -323,6 +325,7 @@ static unsigned int master_prng;
>   static int verbose = 1;
>   static int fd;
>   static bool is_xe;
> +static const uint64_t user_fence_value = 0xdeadbeefdeadbeefull;
>   static struct drm_i915_gem_context_param_sseu device_sseu = {
>   	.slice_mask = -1 /* Force read on first use. */
>   };
> @@ -334,10 +337,18 @@ static struct drm_i915_gem_context_param_sseu device_sseu = {
>   
>   static void w_step_sync(struct w_step *w)
>   {
> -	if (is_xe)
> -		igt_assert(syncobj_wait(fd, &w->xe.syncs[0].handle, 1, INT64_MAX, 0, NULL));
> -	else
> +	if (is_xe) {
> +		if (w->xe.syncs[0].type == DRM_XE_SYNC_TYPE_USER_FENCE) {
> +			xe_wait_ufence(fd, &w->xe.data->spin.exec_sync,
> +				       w->xe.syncs[0].timeline_value, 0,
> +				       INT64_MAX);
> +		} else {
> +			igt_assert(syncobj_wait(fd, &w->xe.syncs[0].handle, 1,
> +						INT64_MAX, 0, NULL));
> +		}
> +	} else {
>   		gem_sync(fd, w->i915.obj[0].handle);
> +	}
>   }
>   
>   static int read_timestamp_frequency(int i915)
> @@ -1293,6 +1304,20 @@ parse_workload(struct w_arg *arg, unsigned int flags, double scale_dur,
>   				step.context = ctx_id;
>   				step.type = CTX_VM;
>   				goto add_step;
> +			} else if (!strcmp(field, "c")) {
> +				/*
> +				 * c.N  - enable compute/LR mode on VM N
> +				 * (xe only, ignored on i915)
> +				 */
> +				field = strtok_r(fstart, ".", &fctx);
> +				check_arg(!field,
> +					  "Missing VM id at step %u!\n", nr_steps);
> +				tmp = atoi(field);
> +				check_arg(tmp <= 0,
> +					  "Invalid VM id at step %u!\n", nr_steps);
> +				step.vm_id = tmp;
> +				step.type = VM_COMPUTE_MODE;
> +				goto add_step;
>   			}
>   
>   			if (!field) {
> @@ -1855,10 +1880,27 @@ xe_alloc_step_batch(struct workload *wrk, struct w_step *w)
>   				    vram_if_possible(fd, eq->hwe_list[0].gt_id),
>   				    DRM_XE_GEM_CREATE_FLAG_NEEDS_VISIBLE_VRAM);
>   	w->xe.data = xe_bo_map(fd, w->bb_handle, w->bb_size);
> +	w->xe.data->spin.exec_sync = 0;
> +	w->xe.data->vm_sync = 0;
>   	w->xe.exec.address =
>   		intel_allocator_alloc_with_strategy(vm->ahnd, w->bb_handle, w->bb_size,
>   						    0, ALLOC_STRATEGY_LOW_TO_HIGH);
> -	xe_vm_bind_sync(fd, vm->id, w->bb_handle, 0, w->xe.exec.address, w->bb_size);
> +	if (vm->compute_mode) {
> +		struct drm_xe_sync sync = {
> +			.type = DRM_XE_SYNC_TYPE_USER_FENCE,
> +			.flags = DRM_XE_SYNC_FLAG_SIGNAL,
> +			.addr = to_user_pointer(&w->xe.data->vm_sync),
> +			.timeline_value = user_fence_value,
> +		};
> +
> +		xe_vm_bind_async(fd, vm->id, vm->bind_exec_queue, w->bb_handle, 0,
> +				 w->xe.exec.address, w->bb_size, &sync, 1);
> +		xe_wait_ufence(fd, &w->xe.data->vm_sync, user_fence_value,
> +			       vm->bind_exec_queue, 10 * NSEC_PER_SEC);
> +		w->xe.data->vm_sync = 0;
> +	} else {
> +		xe_vm_bind_sync(fd, vm->id, w->bb_handle, 0, w->xe.exec.address, w->bb_size);
> +	}
>   	w->duration.requested_ticks = xe_spin_nsec_to_ticks(fd, eq->hwe_list[0].gt_id,
>   							    1000LL * get_duration(wrk, w));
>   	xe_spin_init_opts(&w->xe.data->spin,
> @@ -1875,8 +1917,15 @@ xe_alloc_step_batch(struct workload *wrk, struct w_step *w)
>   
>   		igt_assert(dep_idx >= 0 && dep_idx < w->idx);
>   		igt_assert(wrk->steps[dep_idx].type == BATCH);
> +		igt_assert(wrk->steps[dep_idx].xe.syncs);
>   
> -		w->xe.exec.num_syncs++;
> +		/*
> +		 * USER_FENCE is valid as an out-fence in LR mode, but cannot be
> +		 * consumed as an in-fence in xe_exec. Those deps are resolved in
> +		 * userspace before submission.
> +		 */
> +		if (wrk->steps[dep_idx].xe.syncs[0].type != DRM_XE_SYNC_TYPE_USER_FENCE)
> +			w->xe.exec.num_syncs++;
>   	}
>   	for_each_dep(dep, w->fence_deps) {
>   		int dep_idx = w->idx + dep->target;
> @@ -1884,34 +1933,70 @@ xe_alloc_step_batch(struct workload *wrk, struct w_step *w)
>   		igt_assert(dep_idx >= 0 && dep_idx < w->idx);
>   		igt_assert(wrk->steps[dep_idx].type == SW_FENCE ||
>   			   wrk->steps[dep_idx].type == BATCH);
> +		igt_assert(wrk->steps[dep_idx].xe.syncs);
>   
> -		w->xe.exec.num_syncs++;
> +		if (wrk->steps[dep_idx].xe.syncs[0].type != DRM_XE_SYNC_TYPE_USER_FENCE)
> +			w->xe.exec.num_syncs++;
>   	}
>   	w->xe.syncs = calloc(w->xe.exec.num_syncs, sizeof(*w->xe.syncs));
>   	/* fill syncs */
>   	i = 0;
>   	/* out fence */
> -	w->xe.syncs[i].handle = syncobj_create(fd, 0);
> -	w->xe.syncs[i].type = DRM_XE_SYNC_TYPE_SYNCOBJ;
> -	w->xe.syncs[i++].flags = DRM_XE_SYNC_FLAG_SIGNAL;
> +	if (vm->compute_mode) {
> +		w->xe.syncs[i].type = DRM_XE_SYNC_TYPE_USER_FENCE;
> +		w->xe.syncs[i].flags = DRM_XE_SYNC_FLAG_SIGNAL;
> +		w->xe.syncs[i].addr = w->xe.exec.address + offsetof(struct xe_spin, exec_sync);
> +		w->xe.syncs[i++].timeline_value = user_fence_value;
> +	} else {
> +		w->xe.syncs[i].handle = syncobj_create(fd, 0);
> +		w->xe.syncs[i].type = DRM_XE_SYNC_TYPE_SYNCOBJ;
> +		w->xe.syncs[i++].flags = DRM_XE_SYNC_FLAG_SIGNAL;
> +	}
>   	/* in fence(s) */
>   	for_each_dep(dep, w->data_deps) {
>   		int dep_idx = w->idx + dep->target;
>   
> -		igt_assert(wrk->steps[dep_idx].xe.syncs && wrk->steps[dep_idx].xe.syncs[0].handle);
> -		w->xe.syncs[i].handle = wrk->steps[dep_idx].xe.syncs[0].handle;
> -		w->xe.syncs[i++].type = DRM_XE_SYNC_TYPE_SYNCOBJ;
> +		igt_assert(wrk->steps[dep_idx].xe.syncs);
> +		if (wrk->steps[dep_idx].xe.syncs[0].type == DRM_XE_SYNC_TYPE_USER_FENCE)
> +			continue;
> +		w->xe.syncs[i] = wrk->steps[dep_idx].xe.syncs[0];
> +		w->xe.syncs[i++].flags &= ~DRM_XE_SYNC_FLAG_SIGNAL;
>   	}
>   	for_each_dep(dep, w->fence_deps) {
>   		int dep_idx = w->idx + dep->target;
>   
> -		igt_assert(wrk->steps[dep_idx].xe.syncs && wrk->steps[dep_idx].xe.syncs[0].handle);
> -		w->xe.syncs[i].handle = wrk->steps[dep_idx].xe.syncs[0].handle;
> -		w->xe.syncs[i++].type = DRM_XE_SYNC_TYPE_SYNCOBJ;
> +		igt_assert(wrk->steps[dep_idx].xe.syncs);
> +		if (wrk->steps[dep_idx].xe.syncs[0].type == DRM_XE_SYNC_TYPE_USER_FENCE)
> +			continue;
> +		w->xe.syncs[i] = wrk->steps[dep_idx].xe.syncs[0];
> +		w->xe.syncs[i++].flags &= ~DRM_XE_SYNC_FLAG_SIGNAL;
>   	}
>   	w->xe.exec.syncs = to_user_pointer(w->xe.syncs);
>   }
>   
> +static void xe_sync_user_fence_deps(struct workload *wrk, struct w_step *w)
> +{
> +	struct dep_entry *dep;
> +
> +	for_each_dep(dep, w->data_deps) {
> +		int dep_idx = w->idx + dep->target;
> +
> +		igt_assert(dep_idx >= 0 && dep_idx < w->idx);
> +		igt_assert(wrk->steps[dep_idx].xe.syncs);
> +		if (wrk->steps[dep_idx].xe.syncs[0].type == DRM_XE_SYNC_TYPE_USER_FENCE)
> +			w_step_sync(&wrk->steps[dep_idx]);
> +	}
> +
> +	for_each_dep(dep, w->fence_deps) {
> +		int dep_idx = w->idx + dep->target;
> +
> +		igt_assert(dep_idx >= 0 && dep_idx < w->idx);
> +		igt_assert(wrk->steps[dep_idx].xe.syncs);
> +		if (wrk->steps[dep_idx].xe.syncs[0].type == DRM_XE_SYNC_TYPE_USER_FENCE)
> +			w_step_sync(&wrk->steps[dep_idx]);
> +	}
> +}
> +
>   static bool set_priority(uint32_t ctx_id, int prio)
>   {
>   	struct drm_i915_gem_context_param param = {
> @@ -2190,7 +2275,7 @@ static void allocate_contexts(unsigned int id, struct workload *wrk)
>   
>   		w->wrk = wrk;
>   
> -		if (w->type == VM_CREATE)
> +		if (w->type == VM_CREATE || w->type == VM_COMPUTE_MODE)
>   			continue;
>   
>   		ctx = w->context + 1;
> @@ -2427,6 +2512,14 @@ static int xe_prepare_contexts(unsigned int id, struct workload *wrk)
>   	struct ctx *ctx;
>   	unsigned int i;
>   
> +	for_each_w_step(w, wrk) {
> +		if (w->type == VM_COMPUTE_MODE) {
> +			igt_assert_lt((unsigned int)w->vm_id, wrk->nr_vms);
> +			igt_assert(wrk->vm_list[w->vm_id].declared);
> +			wrk->vm_list[w->vm_id].compute_mode = true;
> +		}
> +	}
> +
>   	/* Slot 0 is the implicit/default VM. */
>   	xe_vm_create_(&wrk->vm_list[0]);
>   	wrk->vm_list[0].ahnd = intel_allocator_open(fd, wrk->vm_list[0].id,
> @@ -2437,6 +2530,9 @@ static int xe_prepare_contexts(unsigned int id, struct workload *wrk)
>   			continue;
>   
>   		xe_vm_create_(&wrk->vm_list[i]);
> +		if (wrk->vm_list[i].compute_mode)
> +			wrk->vm_list[i].bind_exec_queue =
> +				xe_bind_exec_queue_create(fd, wrk->vm_list[i].id, 0);
>   		wrk->vm_list[i].ahnd =
>   			intel_allocator_open(fd, wrk->vm_list[i].id,
>   					     INTEL_ALLOCATOR_RELOC);
> @@ -2767,11 +2863,22 @@ static void w_sync_to(struct workload *wrk, struct w_step *w, int target)
>   static void do_xe_exec(struct workload *wrk, struct w_step *w)
>   {
>   	struct xe_exec_queue *eq = xe_get_eq(wrk, w);
> +	struct vm *vm = get_vm(wrk, w);
>   
>   	igt_assert(w->emit_fence <= 0);
>   	if (w->emit_fence == -1)
>   		syncobj_reset(fd, &w->xe.syncs[0].handle, 1);
>   
> +	/*
> +	 * LR mode reuses the same user-fence location for completion.
> +	 * Re-arm it before every submit so waiters do not observe the
> +	 * previous iteration's signaled value.
> +	 */
> +	if (vm->compute_mode)
> +		w->xe.data->spin.exec_sync = 0;
> +
> +	xe_sync_user_fence_deps(wrk, w);
> +
>   	/* update duration if random */
>   	if (w->duration.max != w->duration.min) {
>   		w->duration.requested_ticks = xe_spin_nsec_to_ticks(fd, eq->hwe_list[0].gt_id,
> @@ -2976,7 +3083,8 @@ static void *run_workload(void *data)
>   				   w->type == BOND ||
>   				   w->type == WORKINGSET ||
>   				   w->type == VM_CREATE ||
> -				   w->type == CTX_VM) {
> +				   w->type == CTX_VM ||
> +				   w->type == VM_COMPUTE_MODE) {
>   				   /* No action for these at execution time. */
>   				continue;
>   			}
> @@ -3066,14 +3174,35 @@ static void *run_workload(void *data)
>   		for_each_w_step(w, wrk) {
>   			if (w->type == BATCH) {
>   				w_step_sync(w);
> -				syncobj_destroy(fd, w->xe.syncs[0].handle);
> +				if (w->xe.syncs[0].type == DRM_XE_SYNC_TYPE_SYNCOBJ)
> +					syncobj_destroy(fd, w->xe.syncs[0].handle);
>   				free(w->xe.syncs);
> -				xe_vm_unbind_sync(fd, get_vm(wrk, w)->id, 0, w->xe.exec.address,
> -						  w->bb_size);
> +				if (get_vm(wrk, w)->compute_mode) {
> +					struct vm *vm = get_vm(wrk, w);
> +					struct drm_xe_sync sync = {
> +						.type = DRM_XE_SYNC_TYPE_USER_FENCE,
> +						.flags = DRM_XE_SYNC_FLAG_SIGNAL,
> +						.addr = to_user_pointer(&w->xe.data->vm_sync),
> +						.timeline_value = user_fence_value,
> +					};
> +
> +					xe_vm_unbind_async(fd, vm->id, vm->bind_exec_queue,
> +							   0, w->xe.exec.address, w->bb_size,
> +							   &sync, 1);
> +					xe_wait_ufence(fd, &w->xe.data->vm_sync,
> +						       user_fence_value,
> +						       vm->bind_exec_queue,
> +						       10 * NSEC_PER_SEC);
> +					w->xe.data->vm_sync = 0;
> +				} else {
> +					xe_vm_unbind_sync(fd, get_vm(wrk, w)->id, 0,
> +							  w->xe.exec.address, w->bb_size);
> +				}
>   				gem_munmap(w->xe.data, w->bb_size);
>   				gem_close(fd, w->bb_handle);
>   			} else if (w->type == SW_FENCE) {
> -				syncobj_destroy(fd, w->xe.syncs[0].handle);
> +				if (w->xe.syncs[0].type == DRM_XE_SYNC_TYPE_SYNCOBJ)
> +					syncobj_destroy(fd, w->xe.syncs[0].handle);
>   				free(w->xe.syncs);
>   			}
>   		}
> diff --git a/benchmarks/wsim/README b/benchmarks/wsim/README
> index 909c1f039..7c180cfb5 100644
> --- a/benchmarks/wsim/README
> +++ b/benchmarks/wsim/README
> @@ -11,7 +11,7 @@ P|S|X.<uint>.<int>
>   d|p|s|t|q|a|T.<int>,...
>   b.<uint>.<str>[|<str>].<str>
>   w|W.<uint>.<str>[/<str>]...
> -V.<uint>
> +V|c.<uint>
>   v.<uint>.<uint>
>   f
>   
> @@ -45,6 +45,7 @@ VM management steps (Xe: active; i915: ignored):
>   
>    'V' - Create VM with id N (V.N, VM ids are 1-based).
>    'v' - Assign VM N to context/queue M (v.N.M).
> + 'c' - Enable compute/LR mode for VM N (c.N).
>   
>   Engine ids: DEFAULT, RCS, BCS, VCS, VCS1, VCS2, VECS
>   
> @@ -95,7 +96,7 @@ Batch durations can also be specified as infinite by using the '*' in the
>   duration field. Such batches must be ended by the terminate command ('T')
>   otherwise they will cause a GPU hang to be reported.
>   
> -VM Example:
> +VM Examples:
>   
>     V.1
>     M.1.VCS
> @@ -107,6 +108,18 @@ Creates VM 1, configures context 1 with a VCS engine map, assigns context 1
>   to VM 1, enables load balancing for context 1, and runs a single 1ms VCS
>   batch.
>   
> +  V.1
> +  c.1
> +  v.1.1
> +  v.1.2
> +  1.BCS.5000.0.0
> +  2.CCS.7000000.-1.0
> +  1.BCS.5000.-1.1
> +
> +Creates VM 1, enables compute/LR mode on it, assigns contexts 1 and 2 to the
> +same VM, then runs BCS and CCS work with cross-step dependencies (CCS depends
> +on the first BCS step, and the final BCS step depends on the CCS step).
> +
>   Xe and i915 differences
>   ------------------------
>   

LGTM,
Reviewed-by: Adam Miszczak <adam.miszczak@linux.intel.com>


Regards,
Adam

  reply	other threads:[~2026-08-03  9:28 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-14 15:12 [PATCH i-g-t 0/2] benchmarks/gem_wsim: explicit VM create/assign + LR mode Marcin Bernatowicz
2026-07-14 15:12 ` [PATCH i-g-t 1/2] benchmarks/gem_wsim: add explicit VM create/assign steps Marcin Bernatowicz
2026-07-16 14:27   ` Kamil Konieczny
2026-08-03  9:26   ` Adam Miszczak
2026-07-14 15:12 ` [PATCH i-g-t 2/2] benchmarks/gem_wsim: add compute/LR mode support for Xe VMs Marcin Bernatowicz
2026-08-03  9:27   ` Adam Miszczak [this message]
2026-07-14 20:26 ` ✗ Xe.CI.BAT: failure for benchmarks/gem_wsim: explicit VM create/assign + LR mode Patchwork
2026-07-14 20:39 ` ✗ i915.CI.BAT: " Patchwork
2026-07-15  4:17 ` ✗ Xe.CI.FULL: " Patchwork
2026-07-15 13:36 ` [PATCH i-g-t 0/2] " Tvrtko Ursulin
2026-07-17  8:03   ` Bernatowicz, Marcin
2026-07-17 12:09     ` Bernatowicz, Marcin
2026-07-17 12:32       ` Tvrtko Ursulin

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=d9a2e9cc-5357-4c2c-93eb-5bfbd9935835@linux.intel.com \
    --to=adam.miszczak@linux.intel.com \
    --cc=igt-dev@lists.freedesktop.org \
    --cc=lukasz.laguna@intel.com \
    --cc=marcin.bernatowicz@linux.intel.com \
    --cc=tvrtko.ursulin@igalia.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