* [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 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.