Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

Work behind a long event wait on an immediate command list is silently dropped (DG2, i915); host sync then hangs or reports completion

Aperta
#1,033 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
35/100
Tipo di issue
Bug
Chiarezza
Abbastanza chiara
Stato di attività
Attiva
Stack tecnologico
c, cpp, linux

Direzione di ricerca

Start by comparing the reported i915 fence timeout with the immediate-list submission and synchronization paths in the compute-runtime sources; the issue does not name those files. Build and run the supplied hostsync.c reproducer on an Arc A770 with i915, especially variants 3 and 6. Done means work resumes after the event is signaled, or synchronization reports a device error rather than losing work, hanging, or reporting false completion.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

On an Arc A770 (DG2) with the i915 kernel driver, work appended to an in-order immediate command list behind a wait on an event is silently dropped if the event stays unsignaled for more than about 10 seconds. Signaling the event afterwards doesn't run it. zeCommandListHostSynchronize on that list then either never returns, or returns ZE_RESULT_SUCCESS although the work never executed. The second case happens once another immediate list on the same engine submits work and synchronizes.

Each run logs two i915 messages, about 10 s after the work is blocked:

Fence expiration time out i915-0000:2f:00.0:hostsync[283317]:a!
Fence expiration time out i915-0000:2f:00.0:hostsync[283317]:8!

That matches CONFIG_DRM_I915_FENCE_TIMEOUT=10000 in this kernel. My guess is that each append is submitted as its own execbuf that implicitly waits for the previous, blocked one, and that i915 runs it anyway with an error once that wait times out, skipping its payload. I haven't verified that in the i915 sources.

Reproducer

hostsync.c below:

  1. Creates an in-order asynchronous immediate list S on ordinal 0.
  2. Appends a wait on an unsignaled host-visible event, then a fill of a host allocation with 42.
  3. Optionally does something else (selected with a command-line argument).
  4. Checks S with zeCommandListHostSynchronize(S, 0).
  5. Signals the event and synchronizes S again.

Build with cc -o hostsync hostsync.c -lze_loader.

Variant Between blocking S and re-checking it Result
0 nothing correct: NOT_READY, then 42 after signaling
1, 2 create a second immediate list T; also sync it while empty (2) correct
3 T submits a fill and is synchronized T's sync takes ~20 s (two fence expirations). Then S reports SUCCESS with the fill not executed, and signaling never runs it.
5 as 3, but S is busy with 200 large fills instead of waiting correct: T's sync waits for S
6 no T, sleep 25 s S correctly stays NOT_READY, but after signaling the fill never runs and zeCommandListHostSynchronize(S, UINT64_MAX) hangs forever
7 as 3, with a signal event on S's fill the event and S correctly stay NOT_READY, but after signaling the work is gone and synchronizing hangs

Variant 0, then variant 3:

device: Intel(R) Arc(TM) A770 Graphics, variant 0
S gated:         NOT_READY, buf=0
S re-checked:    NOT_READY, buf=0
after signaling: buf=42

device: Intel(R) Arc(TM) A770 Graphics, variant 3
S gated:         NOT_READY, buf=0
S re-checked:    SUCCESS, buf=0  <-- BUG: reported done, work not executed
after signaling: buf=0

With NEO_LogWaitingForCompletion=1, variant 3 shows that all lists share one CSR tag. S waits for task count 4, and T's submission moves the tag to 7, although S's work behind the wait never ran:

Waiting for task count 4 at location 0x7efe86a52000 with timeout 0. Current value: 2
Waiting completed. Current value: 2
S gated:         NOT_READY, buf=0
Waiting for task count 6 at location 0x7efe86a52000 with timeout 0. Current value: 2
Waiting completed. Current value: 7
Waiting for task count 4 at location 0x7efe86a52000 with timeout 0. Current value: 7
Waiting completed. Current value: 7
S re-checked:    SUCCESS, buf=0  <-- BUG: reported done, work not executed

Expected: work waiting on an event runs once the event is signaled, however long that takes. If the driver can't guarantee that, it should at least report an error (e.g. ZE_RESULT_ERROR_DEVICE_LOST) rather than drop the work, hang, or report a list as complete when it isn't.

This may be related to #904, which also involves synchronization after ~20 s on an A770.

hostsync.c
// zeCommandListHostSynchronize reports an in-order immediate command list as done while
// work on it is still blocked waiting for an unsignaled event.
//
// usage: hostsync [variant]
//   0: nothing else happens before re-checking S
//   1: create a second immediate list T
//   2: create T and host-synchronize it (empty)
//   3: create T, append a fill to it and host-synchronize it
//   4: host-synchronize S itself with a 100 ms timeout first (no other list)
//   5: like 3, but S is busy with large fills instead of waiting for an event
//   6: no other list, but wait 25 s (longer than i915's fence timeout) before re-checking
//   7: like 3, and also check an event signaled after S's work
#include <level_zero/ze_api.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>

#define CHECK(x) do { ze_result_t r = (x); if (r != ZE_RESULT_SUCCESS) { \
    fprintf(stderr, "%s:%d: %s = 0x%x\n", __FILE__, __LINE__, #x, r); exit(1); } } while (0)

static const char *res(ze_result_t r) {
    return r == ZE_RESULT_SUCCESS ? "SUCCESS" : r == ZE_RESULT_NOT_READY ? "NOT_READY" : "other";
}

static ze_command_list_handle_t immediate(ze_context_handle_t ctx, ze_device_handle_t dev) {
    ze_command_queue_desc_t desc = {ZE_STRUCTURE_TYPE_COMMAND_QUEUE_DESC};
    desc.ordinal = 0;
    desc.index = 0;
    desc.flags = ZE_COMMAND_QUEUE_FLAG_IN_ORDER;
    desc.mode = ZE_COMMAND_QUEUE_MODE_ASYNCHRONOUS;
    desc.priority = ZE_COMMAND_QUEUE_PRIORITY_NORMAL;
    ze_command_list_handle_t list;
    CHECK(zeCommandListCreateImmediate(ctx, dev, &desc, &list));
    return list;
}

int main(int argc, char **argv) {
    int variant = argc > 1 ? atoi(argv[1]) : 2;

    CHECK(zeInit(ZE_INIT_FLAG_GPU_ONLY));
    uint32_t n = 1;
    ze_driver_handle_t drv;
    CHECK(zeDriverGet(&n, &drv));
    n = 1;
    ze_device_handle_t dev;
    CHECK(zeDeviceGet(drv, &n, &dev));
    ze_device_properties_t props = {ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES};
    CHECK(zeDeviceGetProperties(dev, &props));
    ze_context_desc_t cdesc = {ZE_STRUCTURE_TYPE_CONTEXT_DESC};
    ze_context_handle_t ctx;
    CHECK(zeContextCreate(drv, &cdesc, &ctx));

    ze_device_mem_alloc_desc_t ddesc = {ZE_STRUCTURE_TYPE_DEVICE_MEM_ALLOC_DESC};
    ze_host_mem_alloc_desc_t hdesc = {ZE_STRUCTURE_TYPE_HOST_MEM_ALLOC_DESC};
    volatile uint32_t *buf;
    CHECK(zeMemAllocHost(ctx, &hdesc, 64, 64, (void **)&buf));
    buf[0] = 0;

    ze_event_pool_desc_t pdesc = {ZE_STRUCTURE_TYPE_EVENT_POOL_DESC};
    pdesc.flags = ZE_EVENT_POOL_FLAG_HOST_VISIBLE;
    pdesc.count = 2;
    ze_event_pool_handle_t pool;
    CHECK(zeEventPoolCreate(ctx, &pdesc, 1, &dev, &pool));
    ze_event_desc_t edesc = {ZE_STRUCTURE_TYPE_EVENT_DESC};
    edesc.index = 0;
    edesc.signal = ZE_EVENT_SCOPE_FLAG_HOST;
    edesc.wait = ZE_EVENT_SCOPE_FLAG_HOST;
    ze_event_handle_t gate;
    CHECK(zeEventCreate(pool, &edesc, &gate));
    ze_event_handle_t done;
    edesc.index = 1;
    CHECK(zeEventCreate(pool, &edesc, &done));

    ze_command_list_handle_t s = immediate(ctx, dev);
    // warm up S, so that its first submission isn't special
    uint32_t zero = 0;
    CHECK(zeCommandListAppendMemoryFill(s, (void *)buf, &zero, 4, 4, NULL, 0, NULL));
    CHECK(zeCommandListHostSynchronize(s, UINT64_MAX));

    // S: wait for the gate (or do lots of work), then write 42
    uint32_t val = 42;
    if (variant == 5) {
        size_t size = (size_t)1 << 30;
        void *big;
        CHECK(zeMemAllocDevice(ctx, &ddesc, size, 64, dev, &big));
        for (int i = 0; i < 200; i++)
            CHECK(zeCommandListAppendMemoryFill(s, big, &i, 4, size, NULL, 0, NULL));
    } else {
        CHECK(zeCommandListAppendWaitOnEvents(s, 1, &gate));
    }
    CHECK(zeCommandListAppendMemoryFill(s, (void *)buf, &val, 4, 4,
                                        variant == 7 ? done : NULL, 0, NULL));

    printf("device: %s, variant %d\n", props.name, variant);
    printf("S gated:         %s, buf=%u\n", res(zeCommandListHostSynchronize(s, 0)), buf[0]);

    ze_command_list_handle_t t = NULL;
    switch (variant) {
    case 0:
        break;
    case 1:
        t = immediate(ctx, dev);
        break;
    case 2:
        t = immediate(ctx, dev);
        CHECK(zeCommandListHostSynchronize(t, UINT64_MAX));
        break;
    case 3:
    case 5:
    case 7: {
        void *other;
        CHECK(zeMemAllocDevice(ctx, &ddesc, 64, 64, dev, &other));
        t = immediate(ctx, dev);
        CHECK(zeCommandListAppendMemoryFill(t, other, &zero, 4, 4, NULL, 0, NULL));
        CHECK(zeCommandListHostSynchronize(t, UINT64_MAX));
        break;
    }
    case 6:
        sleep(25);
        break;
    case 4:
        printf("S 100ms timeout: %s, buf=%u\n",
               res(zeCommandListHostSynchronize(s, 100000000)), buf[0]);
        break;
    }

    if (variant == 7)
        printf("done event:      %s, buf=%u\n", res(zeEventHostSynchronize(done, 0)), buf[0]);
    ze_result_t r = zeCommandListHostSynchronize(s, 0);
    printf("S re-checked:    %s, buf=%u%s\n", res(r), buf[0],
           r == ZE_RESULT_SUCCESS && buf[0] != 42 ? "  <-- BUG: reported done, work not executed" : "");

    CHECK(zeEventHostSignal(gate));
    CHECK(zeCommandListHostSynchronize(s, UINT64_MAX));
    printf("after signaling: buf=%u\n", buf[0]);
    return r == ZE_RESULT_SUCCESS && buf[0] != 42;
}
Environment
  • Intel Arc A770 (DG2), i915 kernel driver
  • Linux 7.2.11 (Arch), CONFIG_DRM_I915_FENCE_TIMEOUT=10000
  • compute-runtime 26.35.39758.10, level-zero loader 1.32.0

The same thing happens in oneAPI.jl's tests, which ship the same compute-runtime release. I haven't tried the xe kernel driver.

Lingua principale
C++
Stelle
1.5k
Fork
304
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di intel/compute-runtime

Tutte le issue di intel/compute-runtime

Issue simili

Altre issue su C++

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.