* [PATCH i-g-t 0/2] benchmarks/gem_wsim: explicit VM create/assign + LR mode
@ 2026-07-14 15:12 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-14 15:12 ` [PATCH i-g-t 2/2] benchmarks/gem_wsim: add compute/LR mode support for Xe VMs Marcin Bernatowicz
0 siblings, 2 replies; 3+ messages in thread
From: Marcin Bernatowicz @ 2026-07-14 15:12 UTC (permalink / raw)
To: igt-dev; +Cc: adam.miszczak, lukasz.laguna, tvrtko.ursulin, Marcin Bernatowicz
This series extends gem_wsim VM management for Xe.
Patch 1 adds explicit VM create/assign steps in workload descriptors:
V.N to create VM N and v.N.M to bind context M to VM N.
Patch 2 adds c.N to enable compute/LR mode on selected VMs.
README is updated with syntax and VM usage examples.
Marcin Bernatowicz (2):
benchmarks/gem_wsim: add explicit VM create/assign steps
benchmarks/gem_wsim: add compute/LR mode support for Xe VMs
benchmarks/gem_wsim.c | 310 ++++++++++++++++++++++++++++++++++++-----
benchmarks/wsim/README | 32 +++++
2 files changed, 311 insertions(+), 31 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH i-g-t 1/2] benchmarks/gem_wsim: add explicit VM create/assign steps
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 ` Marcin Bernatowicz
2026-07-14 15:12 ` [PATCH i-g-t 2/2] benchmarks/gem_wsim: add compute/LR mode support for Xe VMs Marcin Bernatowicz
1 sibling, 0 replies; 3+ messages in thread
From: Marcin Bernatowicz @ 2026-07-14 15:12 UTC (permalink / raw)
To: igt-dev; +Cc: adam.miszczak, lukasz.laguna, tvrtko.ursulin, Marcin Bernatowicz
Add explicit VM management to workload descriptors so Xe runs can model
VM topology directly.
Introduce two new descriptor steps:
- V.N create VM id N (1-based)
- v.N.M assign VM N to context M
Implementation details:
- Add VM_CREATE and CTX_VM step types and vm_id storage in w_step.
- Parse V/v syntax with validation and clear error messages.
- Add allocate_vms() pre-scan to size and allocate vm_list from V steps.
- Update xe_prepare_contexts() to support explicit VM mode:
- create all explicit VMs
- default contexts to VM 0
- apply per-context VM assignments from v steps
- retain implicit single-VM fallback when no V steps are present
- Make get_vm() use per-context VM linkage.
Documentation:
- Add VM management step documentation into benchmarks/wsim/README.
This keeps i915 behavior unchanged while enabling explicit VM topology
control for Xe workloads.
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 | 143 +++++++++++++++++++++++++++++++++++++----
benchmarks/wsim/README | 19 ++++++
2 files changed, 150 insertions(+), 12 deletions(-)
diff --git a/benchmarks/gem_wsim.c b/benchmarks/gem_wsim.c
index 8be44d0c8..b3c46772f 100644
--- a/benchmarks/gem_wsim.c
+++ b/benchmarks/gem_wsim.c
@@ -130,6 +130,8 @@ enum w_type {
TERMINATE,
SSEU,
WORKINGSET,
+ VM_CREATE,
+ CTX_VM,
};
struct dep_entry {
@@ -210,6 +212,7 @@ struct w_step {
struct bond bond;
int sseu;
struct working_set working_set;
+ int vm_id;
};
/* Implementation details */
@@ -241,6 +244,7 @@ struct w_step {
struct vm {
uint32_t id;
+ bool declared;
bool compute_mode;
uint64_t ahnd;
};
@@ -1240,6 +1244,55 @@ parse_workload(struct w_arg *arg, unsigned int flags, double scale_dur,
step.type = WORKINGSET;
goto add_step;
+ } else if (!strcmp(field, "V")) {
+ /*
+ * V.N - create VM with id N (xe only, ignored on i915)
+ * VM ids are 1-based in the descriptor.
+ */
+ 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_CREATE;
+ goto add_step;
+ } else if (!strcmp(field, "v")) {
+ /*
+ * v.N.M - assign VM N to ctx M
+ * (xe only, ignored on i915)
+ */
+ unsigned int nr = 0;
+ int vm = 0, ctx_id = 0;
+
+ while ((field = strtok_r(fstart, ".", &fctx))) {
+ fstart = NULL;
+ tmp = atoi(field);
+ if (nr == 0) {
+ check_arg(tmp <= 0,
+ "Invalid VM id at step %u!\n",
+ nr_steps);
+ vm = tmp;
+ } else if (nr == 1) {
+ check_arg(tmp <= 0,
+ "Invalid ctx id at step %u!\n",
+ nr_steps);
+ ctx_id = tmp;
+ } else {
+ check_arg(1,
+ "Too many fields in v step at step %u!\n",
+ nr_steps);
+ }
+ nr++;
+ }
+ check_arg(nr != 2,
+ "v step requires VM id and ctx id at step %u!\n",
+ nr_steps);
+ step.vm_id = vm;
+ step.context = ctx_id;
+ step.type = CTX_VM;
+ goto add_step;
}
if (!field) {
@@ -1665,6 +1718,14 @@ xe_get_eq(struct workload *wrk, const struct w_step *w)
static struct vm *
get_vm(struct workload *wrk, const struct w_step *w)
{
+ struct ctx *ctx = __get_ctx(wrk, w);
+
+ /* If the ctx has been linked to an explicit VM, use it; otherwise
+ * fall back to the implicit single vm_list[0].
+ */
+ if (ctx->vm)
+ return ctx->vm;
+
return wrk->vm_list;
}
@@ -2087,6 +2148,33 @@ static void xe_exec_queue_create_(struct ctx *ctx, struct xe_exec_queue *eq)
eq->id = create.exec_queue_id;
}
+static void allocate_vms(struct workload *wrk)
+{
+ int max_vm = 0;
+ struct w_step *w;
+
+ /*
+ * Slot 0 is always the implicit/default VM. Descriptor VM ids are
+ * 1-based and map directly to vm_list[N] for explicit V.N steps.
+ */
+ for_each_w_step(w, wrk) {
+ if (w->type != VM_CREATE)
+ continue;
+ if (w->vm_id > max_vm)
+ max_vm = w->vm_id;
+ }
+
+ wrk->nr_vms = max_vm + 1;
+ wrk->vm_list = calloc(wrk->nr_vms, sizeof(*wrk->vm_list));
+ igt_assert(wrk->vm_list);
+
+ for_each_w_step(w, wrk) {
+ if (w->type == VM_CREATE)
+ /* Mark only explicitly declared VMs; slot 0 stays implicit. */
+ wrk->vm_list[w->vm_id].declared = true;
+ }
+}
+
static void allocate_contexts(unsigned int id, struct workload *wrk)
{
int max_ctx = -1;
@@ -2094,13 +2182,19 @@ static void allocate_contexts(unsigned int id, struct workload *wrk)
/*
* Pre-scan workload steps to allocate context list storage.
+ * Skip VM management steps whose context field is unused.
*/
for_each_w_step(w, wrk) {
- int ctx = w->context + 1;
+ int ctx;
int delta;
w->wrk = wrk;
+ if (w->type == VM_CREATE)
+ continue;
+
+ ctx = w->context + 1;
+
if (ctx <= max_ctx)
continue;
@@ -2333,18 +2427,38 @@ static int xe_prepare_contexts(unsigned int id, struct workload *wrk)
struct ctx *ctx;
unsigned int i;
- /* shortcut, create one vm */
- wrk->nr_vms = 1;
- wrk->vm_list = calloc(wrk->nr_vms, sizeof(struct vm));
- igt_assert(wrk->vm_list);
- wrk->vm_list->compute_mode = false;
- xe_vm_create_(wrk->vm_list);
- wrk->vm_list->ahnd = intel_allocator_open(fd, wrk->vm_list->id,
- INTEL_ALLOCATOR_RELOC);
+ /* 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,
+ INTEL_ALLOCATOR_RELOC);
+
+ for (i = 1; i < wrk->nr_vms; i++) {
+ if (!wrk->vm_list[i].declared)
+ continue;
+
+ xe_vm_create_(&wrk->vm_list[i]);
+ wrk->vm_list[i].ahnd =
+ intel_allocator_open(fd, wrk->vm_list[i].id,
+ INTEL_ALLOCATOR_RELOC);
+ }
+
+ /*
+ * Process CTX_VM steps to link each ctx to an explicit VM. Contexts
+ * without a v.N.M mapping remain on the implicit VM in slot 0.
+ */
+ __for_each_ctx(ctx, wrk, ctx_idx)
+ ctx->vm = &wrk->vm_list[0];
+
+ for_each_w_step(w, wrk) {
+ if (w->type != CTX_VM)
+ continue;
+ igt_assert_lt((unsigned int)w->vm_id, wrk->nr_vms);
+ igt_assert(wrk->vm_list[w->vm_id].declared);
+ igt_assert_lt((unsigned int)w->context, wrk->nr_ctxs);
+ wrk->ctx_list[w->context].vm = &wrk->vm_list[w->vm_id];
+ }
__for_each_ctx(ctx, wrk, ctx_idx) {
- /* link with vm */
- ctx->vm = wrk->vm_list;
for_each_w_step(w, wrk) {
if (w->context != ctx_idx)
continue;
@@ -2537,6 +2651,9 @@ static int prepare_workload(unsigned int id, struct workload *wrk)
allocate_contexts(id, wrk);
+ if (is_xe)
+ allocate_vms(wrk);
+
if (is_xe)
ret = xe_prepare_contexts(id, wrk);
else
@@ -2857,7 +2974,9 @@ static void *run_workload(void *data)
w->type == ENGINE_MAP ||
w->type == LOAD_BALANCE ||
w->type == BOND ||
- w->type == WORKINGSET) {
+ w->type == WORKINGSET ||
+ w->type == VM_CREATE ||
+ w->type == CTX_VM) {
/* No action for these at execution time. */
continue;
}
diff --git a/benchmarks/wsim/README b/benchmarks/wsim/README
index e43813335..909c1f039 100644
--- a/benchmarks/wsim/README
+++ b/benchmarks/wsim/README
@@ -11,6 +11,8 @@ 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.<uint>.<uint>
f
For duration a range can be given from which a random value will be picked
@@ -39,6 +41,11 @@ Additional workload steps are also supported:
'W' - Shared working set.
'X' - Context preemption control.
+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).
+
Engine ids: DEFAULT, RCS, BCS, VCS, VCS1, VCS2, VECS
Example (leading spaces must not be present in the actual file):
@@ -88,6 +95,18 @@ 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:
+
+ V.1
+ M.1.VCS
+ v.1.1
+ B.1
+ 1.VCS.1000.0.0
+
+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.
+
Xe and i915 differences
------------------------
--
2.43.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH i-g-t 2/2] benchmarks/gem_wsim: add compute/LR mode support for Xe VMs
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-14 15:12 ` Marcin Bernatowicz
1 sibling, 0 replies; 3+ messages in thread
From: Marcin Bernatowicz @ 2026-07-14 15:12 UTC (permalink / raw)
To: igt-dev; +Cc: adam.miszczak, lukasz.laguna, tvrtko.ursulin, Marcin Bernatowicz
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
------------------------
--
2.43.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-07-14 15:14 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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-14 15:12 ` [PATCH i-g-t 2/2] benchmarks/gem_wsim: add compute/LR mode support for Xe VMs Marcin Bernatowicz
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox