Skip to content
/ airelien.dev
Go back
Aurélien AMSELLEM

Lucebox sur Olares One — Épisode 7 : Issue #187, PR #188, et 6 hooks corrigés d'un coup

Le bug est identifié : 6 hooks dans HAMi-core ignorent le return de cuCtxGetDevice. Le fix tient en 50 lignes. Mais pour qu'il bénéficie à toute la communauté HAMi, il faut le pousser upstream. Voilà comment ça s'est passé.

Épisode 6 — diag complet : 6 hooks de HAMi-core ont tous le même bug d’uninitialized dev après cuCtxGetDevice ignored. Le fix est clair : initialiser, vérifier le return code, bail out gracieux si fail.

Maintenant, deux options :

  1. Patcher la lib en local sur mon Olares (un seul fichier .so à compiler, scp sur le host, restart les pods GPU). Solution rapide, ne bénéficie qu’à moi.

  2. Pousser le fix upstream chez Project-HAMi/HAMi-core. Solution propre, profite à toute la communauté HAMi.

Évidemment je fais les deux, en commençant par le PR upstream. Bon karma open source.

L’issue

Premier réflexe avant un PR : ouvrir une issue qui décrit le bug en détail, avec un repro minimal. Ça donne aux maintainers le contexte pour reviewer la PR ensuite.

Le repro est court. Un main C qui appelle cuMemCreate avec un prop.location.type = CU_MEM_LOCATION_TYPE_HOST_NUMA — c’est exactement le path que ggml prend pour son virtual address pool :

#include <stdio.h>
#include <cuda.h>

int main(void) {
    cuInit(0);
    CUdevice device; cuDeviceGet(&device, 0);
    CUcontext ctx;   cuCtxCreate(&ctx, 0, device);

    CUmemAllocationProp prop = {0};
    prop.type             = CU_MEM_ALLOCATION_TYPE_PINNED;
    prop.location.type    = CU_MEM_LOCATION_TYPE_HOST_NUMA;
    prop.location.id      = 0;

    size_t granularity;
    cuMemGetAllocationGranularity(&granularity, &prop, CU_MEM_ALLOC_GRANULARITY_MINIMUM);
    size_t size = ((1<<20) + granularity - 1) / granularity * granularity;

    CUmemGenericAllocationHandle handle;
    CUresult res = cuMemCreate(&handle, size, &prop, 0);
    printf("cuMemCreate returned %d\n", res);
    cuCtxDestroy(ctx);
    return 0;
}

nvcc -lcuda repro.c -o repro, run dans un pod managé par HAMi, et [HAMI-core ERROR ...]: Illegal device id: <random> apparaît immédiatement.

Issue : Project-HAMi/HAMi-core#187. Texte clair, repro complet, root cause identifiée, fix suggéré inline.

Le PR

Ensuite je fork le repo, branch fix/cumemcreate-uninit-dev, applique le fix.

Premier commitcuMemCreate (le hook spécifique qui m’a planté) :

// avant
CUdevice dev;                                          // uninitialised
int do_oom_check = (prop->location.type == CU_MEM_LOCATION_TYPE_DEVICE);
if (do_oom_check && cuCtxGetDevice(&dev) != CUDA_SUCCESS) {
    dev = prop->location.id;
}
// ...
if (res == CUDA_SUCCESS) {
    add_chunk_only(*handle, size, dev);                // peut être uninit
}
// après
CUdevice dev = prop->location.id;                      // initialisé up-front
int do_oom_check = (prop->location.type == CU_MEM_LOCATION_TYPE_DEVICE);
if (do_oom_check && cuCtxGetDevice(&dev) != CUDA_SUCCESS) {
    dev = prop->location.id;
}
// ...
if (res == CUDA_SUCCESS && do_oom_check) {             // skip non-DEVICE
    add_chunk_only(*handle, size, dev);
}

Plus le tightening de set_current_device_memory_limit pour return early :

if (dev < 0 || dev >= CUDA_DEVICE_MAX_COUNT) {
    LOG_ERROR("Illegal device id: %d", dev);
    return -1;                                         // était manquant
}

Deuxième commit — les 5 sites de allocator.c. Pattern identique partout :

// avant
CUdevice dev;
cuCtxGetDevice(&dev);
if (oom_check(dev, size)) ...

// après
CUdevice dev = -1;
if (cuCtxGetDevice(&dev) != CUDA_SUCCESS) {
    LOG_WARN("add_chunk: cuCtxGetDevice failed, skipping memory tracking");
    return CUDA_SUCCESS;
}
if (oom_check(dev, size)) ...

Stratégie : si on ne sait pas sur quel device l’allocation a lieu, on ne la track pas au lieu de tracker n’importe quoi et corrompre la shared memory. L’allocation CUDA sous-jacente continue normalement, simplement HAMi ne la compte pas dans ses quotas. Trade-off acceptable — un thread sans context cuda qui alloue est rare en steady state.

Total : +36 / -21 lignes. Deux fichiers touchés.

Le push et la review

git push -u origin fix/cumemcreate-uninit-dev
gh pr create --repo Project-HAMi/HAMi-core \
  --base main \
  --head aamsellem:fix/cumemcreate-uninit-dev \
  --title "fix(cuda,allocator): initialize dev in 6 hooks reading uninitialised stack on cuCtxGetDevice failure" \
  --body-file pr-body.md

PR live : Project-HAMi/HAMi-core#188.

Le body du PR explique :

Avec Signed-off-by: aamsellem <620182+aamsellem@users.noreply.github.com> parce que la plupart des projets NVIDIA-adjacents demandent du DCO.

Et là, j’attends.

Pour Olares concrètement

Le truc, c’est qu’Olares ne pull pas master direct. Olares utilise beclab/hami:v2.6.14, image Docker Hub publiée le 18 mars 2026 — donc elle ne contient pas les changements upstream récents. Il faudra :

  1. Que le PR #188 soit merged sur HAMi-core master
  2. Que beclab rebuilde leur image beclab/hami:v2.6.x from master
  3. Qu’Olares update leur Helm chart pour pointer la nouvelle image
  4. Qu’au prochain Olares update, votre cluster pull la nouvelle libvgpu.so

Donc avant que ça arrive en prod, faudra patienter. Probablement 2-4 semaines.

En attendant, deux workarounds :

Ce qu’on retient de cette saga (jusqu’ici)

Oui zéro. Parce qu’à l’heure où j’écris ces lignes, le pod ne boote toujours pas — il faut soit que le PR upstream soit merged + arrive sur Olares, soit que je compile manuellement libvgpu sur le host.

Épisode 8 — On a enfin les chiffres Lucebox sur Blackwell consumer, à venir dès qu’on dépasse cette dernière marche. À très vite !


Disclosure — Tous les benchmarks de ce post tournent sur mon propre Olares One. Si le contenu vous a été utile et que vous envisagez d’en acheter un, commander via ce lien de parrainage vous donne 400 $ de réduction (3 599 $ au lieu de 3 999 $) et me rapporte 200 $. Je le mentionne par transparence — et oui, accessoirement, ça aide à faire vivre le blog (hébergement, domaine, et le temps que je passe à écrire ici). Lien valable jusqu’à fin juin 2026 environ.

Share this post on:

Commentaires