From: "Sharma, Nishit" <nishit.sharma@intel.com>
To: Varun Gupta <varun.gupta@intel.com>, <igt-dev@lists.freedesktop.org>
Cc: <priyanka.dandamudi@intel.com>
Subject: Re: [PATCH i-g-t v2] tests/intel/xe_prefetch_fault: Add SVM and hit-under-miss validation
Date: Wed, 18 Mar 2026 14:30:13 +0530 [thread overview]
Message-ID: <06b18696-f088-474b-b5a6-515dbe6925dc@intel.com> (raw)
In-Reply-To: <20260318063528.2212823-1-varun.gupta@intel.com>
On 3/18/2026 12:05 PM, Varun Gupta wrote:
> Add a second batch to validate hit-under-miss behavior: placing the BB
> at PREFETCH_ADDR ensures the page is already mapped when the shader
> prefetch runs, so the prefetch fault counter should not increment.
>
> Add SVM mode (prefetch-fault-svm subtest) that creates the VM with
> CPU_ADDR_MIRROR and uses mmap() at PREFETCH_ADDR to make the page
> GPU-accessible before the hit-under-miss batch.
>
> Other changes:
> - Extract PREFETCH_ADDR and USER_FENCE_VALUE into defines
> - Update stat name to 'invalid_prefetch_pagefault_count'
> - Add missing cleanup (intel_buf_destroy, xe_exec_queue_destroy,
> xe_vm_destroy)
>
> v2:
> - Move xe_vm_create() before if(svm) as it is common to both paths (Nishit)
> - Separate SVM and non-SVM specific code into if/else blocks (Nishit)
> - Add BB_OFFSET and BB_OFFSET_SVM defines (Nishit)
> - Add comments wherever needed (Nishit)
>
> Signed-off-by: Varun Gupta <varun.gupta@intel.com>
> ---
> tests/intel/xe_prefetch_fault.c | 127 ++++++++++++++++++++++++++------
> 1 file changed, 103 insertions(+), 24 deletions(-)
>
> diff --git a/tests/intel/xe_prefetch_fault.c b/tests/intel/xe_prefetch_fault.c
> index 4a143374a..988cf940d 100644
> --- a/tests/intel/xe_prefetch_fault.c
> +++ b/tests/intel/xe_prefetch_fault.c
> @@ -25,6 +25,10 @@
> #define WALKER_Y_DIM 1
> #define PAGE_SIZE 4096
> #define COLOR_C4 0xC4C4C4C4
> +#define USER_FENCE_VALUE 0xdeadbeefdeadbeefull
> +#define PREFETCH_ADDR 0x1f000000
> +#define BB_OFFSET 0x1b000000
> +#define BB_OFFSET_SVM 0x2b000000
>
> struct dim_t {
> uint32_t x;
> @@ -118,7 +122,7 @@ static struct gpgpu_shader *get_prefetch_shader(int fd)
> static struct gpgpu_shader *shader;
>
> shader = gpgpu_shader_create(fd);
> - gpgpu_shader__prefetch_fault(shader, xe_canonical_va(fd, 0x1f000000));
> + gpgpu_shader__prefetch_fault(shader, xe_canonical_va(fd, PREFETCH_ADDR));
> gpgpu_shader__eot(shader);
>
> return shader;
> @@ -126,63 +130,127 @@ static struct gpgpu_shader *get_prefetch_shader(int fd)
>
> /**
> * SUBTEST: prefetch-fault
> - * Description: Validate L1/L2 cache prefetch fault.
> + * Description: Validate prefetch fault and hit-under-miss behavior
> + * Run type: FULL
> + *
> + * SUBTEST: prefetch-fault-svm
> + * Description: Validate prefetch fault and hit-under-miss behavior in SVM mode
> * Run type: FULL
> */
> -
> -static void test_prefetch(int fd, struct drm_xe_engine_class_instance *hwe)
> +static void test_prefetch_fault(int fd, struct drm_xe_engine_class_instance *hwe, bool svm)
> {
> - /* faulty address 0x1f000000 should be beyond bb_offset+bb_size. */
> - const uint64_t bb_offset = 0x1b000000;
> + const uint64_t bb_offset = BB_OFFSET;
> + /*
> + * For the hit-under-miss run, place the batch at PREFETCH_ADDR in
> + * non-SVM mode so the BO bind maps that page before the shader runs.
> + * In SVM mode PREFETCH_ADDR is reserved for the mmap, so use a
> + * separate offset that doesn't collide with it.
> + */
> + const uint64_t bb_offset2 = svm ? BB_OFFSET_SVM : PREFETCH_ADDR;
small nit: use simple variable name
const not required
> const size_t bb_size = 4096;
> - struct dim_t w_dim;
> + static const char *stat = "invalid_prefetch_pagefault_count";
> + struct dim_t w_dim = { .x = WALKER_X_DIM, .y = WALKER_Y_DIM };
> struct gpgpu_shader *shader;
> struct intel_bb *ibb;
> struct intel_buf *buf;
> - uint32_t *ptr;
> uint32_t exec_queue_id, vm;
> + void *cpu_data = NULL;
> int prefetch_pre, prefetch_pos;
small nit: should be prefetch_post
> - static const char *stat = "prefetch_pagefault_count";
> -
> - w_dim.x = WALKER_X_DIM;
> - w_dim.y = WALKER_Y_DIM;
> + uint32_t *ptr;
>
> buf = create_buf(fd, w_dim.x, w_dim.y, COLOR_C4);
>
> - prefetch_pre = xe_gt_stats_get_count(fd, hwe->gt_id, stat);
> -
> vm = xe_vm_create(fd, DRM_XE_VM_CREATE_FLAG_LR_MODE |
> DRM_XE_VM_CREATE_FLAG_FAULT_MODE, 0);
>
> + if (svm) {
> + /*
> + * Enable SVM: mirror the full VA space so GPU page faults are
> + * resolved via HMM against the CPU page tables.
> + */
> + struct xe_device *xe = xe_device_get(fd);
> + uint64_t vm_sync = 0;
> + struct drm_xe_sync sync[1] = {
> + { .type = DRM_XE_SYNC_TYPE_USER_FENCE, .flags = DRM_XE_SYNC_FLAG_SIGNAL,
> + .timeline_value = USER_FENCE_VALUE },
> + };
> +
> + sync[0].addr = to_user_pointer(&vm_sync);
> + __xe_vm_bind_assert(fd, vm, 0, 0, 0, 0, 0x1ull << xe->va_bits,
> + DRM_XE_VM_BIND_OP_MAP,
> + DRM_XE_VM_BIND_FLAG_CPU_ADDR_MIRROR,
> + sync, 1, 0, 0);
> + xe_wait_ufence(fd, &vm_sync, USER_FENCE_VALUE, 0, NSEC_PER_SEC);
> + }
> +
> exec_queue_id = xe_exec_queue_create(fd, vm, hwe, 0);
>
> - ibb = xe_bb_create_on_offset(fd, exec_queue_id, vm,
> - bb_offset, bb_size);
> + prefetch_pre = xe_gt_stats_get_count(fd, hwe->gt_id, stat);
> +
> + /* First run: PREFETCH_ADDR is unmapped, so each shader lane raises a prefetch fault. */
> + ibb = xe_bb_create_on_offset(fd, exec_queue_id, vm, bb_offset, bb_size);
> intel_bb_set_lr_mode(ibb, true);
>
> shader = get_prefetch_shader(fd);
> -
> gpgpu_shader_exec(ibb, buf, w_dim.x, w_dim.y, shader, NULL, 0, 0);
> -
> gpgpu_shader_destroy(shader);
> + intel_bb_sync(ibb);
> + intel_bb_destroy(ibb);
>
> + prefetch_pos = xe_gt_stats_get_count(fd, hwe->gt_id, stat);
> + igt_assert_eq(prefetch_pos, prefetch_pre + w_dim.x * w_dim.y);
> +
> + /*
> + * Hit-under-miss: ensure the page at PREFETCH_ADDR is already mapped
> + * before the prefetch shader runs again. The fault is resolved
> + * successfully so the prefetch counter must not change.
> + *
> + * SVM: mmap at PREFETCH_ADDR creates a CPU page table entry.
> + * The kernel resolves the GPU pagefault via HMM.
> + * Non-SVM: placing the batch buffer at PREFETCH_ADDR causes the
> + * BO fault path to map the page.
> + */
> + if (svm) {
> + cpu_data = mmap((void *)PREFETCH_ADDR, PAGE_SIZE,
> + PROT_READ | PROT_WRITE,
> + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
> + -1, 0);
> + igt_assert(cpu_data == (void *)PREFETCH_ADDR);
> + /* Touch the page to populate the CPU PTE so HMM can resolve the GPU fault. */
> + memset(cpu_data, 0xAB, PAGE_SIZE);
> + prefetch_pre = xe_gt_stats_get_count(fd, hwe->gt_id, stat);
> + } else {
> + prefetch_pre = prefetch_pos;
> + }
> + ibb = xe_bb_create_on_offset(fd, exec_queue_id, vm, bb_offset2, bb_size);
> + intel_bb_set_lr_mode(ibb, true);
> +
> + shader = get_prefetch_shader(fd);
> + gpgpu_shader_exec(ibb, buf, w_dim.x, w_dim.y, shader, NULL, 0, 0);
> + gpgpu_shader_destroy(shader);
> intel_bb_sync(ibb);
>
> - ptr = xe_bo_mmap_ext(fd, buf->handle, buf->size, PROT_READ);
> + prefetch_pos = xe_gt_stats_get_count(fd, hwe->gt_id, stat);
> + igt_assert_eq(prefetch_pos, prefetch_pre);
>
> + /* Verify buffer contents */
> + ptr = xe_bo_mmap_ext(fd, buf->handle, buf->size, PROT_READ);
> for (int j = 0; j < w_dim.y; j++)
> for (int i = 0; i < w_dim.x; i++) {
> igt_assert_f(ptr[j * w_dim.x + i] == COLOR_C4,
> "Expected 0x%02x, found 0x%02x at (%d,%d)\n",
> COLOR_C4, ptr[j * w_dim.x + i], i, j);
> }
> - /* Validate prefetch count. */
> - prefetch_pos = xe_gt_stats_get_count(fd, hwe->gt_id, stat);
> - igt_assert_eq(prefetch_pos, prefetch_pre + w_dim.x * w_dim.y);
> -
> munmap(ptr, buf->size);
>
> + /* Cleanup */
> + if (svm && cpu_data)
> + munmap(cpu_data, PAGE_SIZE);
> +
> intel_bb_destroy(ibb);
> + intel_buf_destroy(buf);
> + xe_exec_queue_destroy(fd, exec_queue_id);
> + xe_vm_destroy(fd, vm);
> }
>
> int igt_main()
> @@ -201,7 +269,18 @@ int igt_main()
> hwe->engine_class == DRM_XE_ENGINE_CLASS_COMPUTE) {
> igt_dynamic_f("%s%d", xe_engine_class_string(hwe->engine_class),
> hwe->engine_instance)
> - test_prefetch(fd, hwe);
> + test_prefetch_fault(fd, hwe, false);
> + }
> + }
> + }
> +
> + igt_subtest_with_dynamic("prefetch-fault-svm") {
> + xe_for_each_engine(fd, hwe) {
> + if (hwe->engine_class == DRM_XE_ENGINE_CLASS_RENDER ||
> + hwe->engine_class == DRM_XE_ENGINE_CLASS_COMPUTE) {
> + igt_dynamic_f("%s%d", xe_engine_class_string(hwe->engine_class),
> + hwe->engine_instance)
> + test_prefetch_fault(fd, hwe, true);
> }
> }
> }
LGTM
Reviewed-by: Nishit Sharma <nishit.sharma@intel.com>
next prev parent reply other threads:[~2026-03-18 9:00 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-18 6:35 [PATCH i-g-t v2] tests/intel/xe_prefetch_fault: Add SVM and hit-under-miss validation Varun Gupta
2026-03-18 7:19 ` ✓ Xe.CI.BAT: success for tests/intel/xe_prefetch_fault: Add SVM and hit-under-miss validation (rev2) Patchwork
2026-03-18 7:49 ` ✓ i915.CI.BAT: " Patchwork
2026-03-18 9:00 ` Sharma, Nishit [this message]
2026-03-19 11:56 ` ✓ i915.CI.Full: " Patchwork
2026-03-19 19:44 ` ✗ Xe.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=06b18696-f088-474b-b5a6-515dbe6925dc@intel.com \
--to=nishit.sharma@intel.com \
--cc=igt-dev@lists.freedesktop.org \
--cc=priyanka.dandamudi@intel.com \
--cc=varun.gupta@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