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

Lucebox sur Olares One — Épisode 9 : la tentative à 106 t/s qui s'écrase à 88,7 t/s, et pourquoi

PR #94 de Lucebox annonce 67 → 106 t/s (+57%) sur RTX 4090 avec le matched 3.6 SWA draft. Je le porte sur 5090M Blackwell. Spoiler : 88,5 → 88,7 t/s. Sweep DDTree budget complet, et l'explication honnête du pourquoi.

Épisode 8 — j’avais Lucebox qui tournait à 88,5 t/s sur Olares One via le hot-swap libvgpu + trois workarounds. Nouveau champion, 0,5 t/s devant vLLM Turbo. Et puis je vois passer la PR #94 sur Lucebox-hub, postée le matin même : “Support Qwen3.6-27B-DFlash draft (SWA layers) — 106 t/s on RTX 4090”. Avec un sweep DDTree budget qui montre +57% vs le drafter mismatched 3.5 (67,4 → 106,1 t/s sur RTX 4090).

Ada sm_89 → 106 t/s. Si ça scale linéairement à Blackwell sm_120 (qui a globalement plus de bandwidth), on devrait taper 120-130 t/s sur Olares.

Spoiler dès maintenant : 88,7 t/s. +0,2 vs hier. Dans le bruit de mesure. Voilà l’enquête.

La promesse PR #94

Trois changements dans la PR :

  1. Matched 3.6 draft au lieu de mismatched 3.5 — le draft z-lab/Qwen3.6-27B-DFlash (4 sliding-window-attention layers + 1 full-attention) au lieu du draft 3.5 (5 full-attention layers). Layer types lus depuis config.json sibling au safetensors.

  2. SWA mask plumbed dans qwen3_dflash_graph.cpp via ggml_flash_attn_ext.

  3. Build flag DFLASH27B_ENABLE_BSA=ON active Block-Sparse-Attention (path PFlash, mais aussi utile pour le drafter).

Le sweep RTX 4090 du PR :

budget=6:   93,9 t/s
budget=10: 106,1 t/s ← sweet spot
budget=14:  96,5
budget=18: 102,7
budget=22: 103,5

Sweet spot à 10. Logique : budget plus bas = moins de verify parallèle = moins de chunks = bien sur cartes avec bandwidth limité.

Le build

Je rebuild une image v1.6.0 sur cette branche :

RUN git clone --depth 1 --branch feat/dflash-qwen36-swa-draft \
    --recurse-submodules \
    https://github.com/Quitetall/lucebox-hub /src/lucebox

RUN cmake -B build -S . \
    -DCMAKE_BUILD_TYPE=Release \
    -DGGML_CUDA=ON -DGGML_CUDA_NO_VMM=ON \
    -DCMAKE_CUDA_ARCHITECTURES="120" \
    -DDFLASH27B_ENABLE_BSA=ON \
    -DCMAKE_EXE_LINKER_FLAGS="-Wl,-rpath-link,/usr/local/cuda/lib64/stubs" \
    -DCMAKE_SHARED_LINKER_FLAGS="-Wl,-rpath-link,/usr/local/cuda/lib64/stubs" \
    && cmake --build build --target test_dflash test_flashprefill_kernels -j$(nproc)

Build : 100 min sur OrbStack cross-arch. Image v1.6.0 = 5,39 Go (vs 4,17 Go pour v1.4.0 = +1,2 Go = les kernels BSA).

Premier bench — config par défaut

Default chart config (héritée v1.4.4) : --cache-type-k tq3_0 --cache-type-v tq3_0 --budget 22 (default).

Run 1: 87,45 t/s
Run 2: 89,22 t/s
Run 3: 88,09 t/s

88,25 t/s avg. Identique à hier (88,5). Ouch. La PR #94 ne se voit pas ?

Je vérifie que la PR est bien active. grep "SWA layers" source/safetensors_draft.cpp → la fonction est bien là, qui parse config.json. cat /models/draft/config.jsonlayer_types: [sliding × 4, full × 1], sliding_window: 2048 — exactement ce que la PR attend.

Mais le log diagnostic [draft] SWA layers: 4/5 (window=2048) n’apparaît pas dans la sortie de test_dflash. Soit la code path s’exécute silencieusement, soit le log va sur stderr qu’on ne capture pas dans kubectl logs (on capture stdout+stderr en théorie, mais pas sûr pour les sous-processus daemon spawned par server.py).

Verdict : probablement actif mais sans gain visible ici.

Hypothèse 1 : config par défaut sub-optimale

La PR #94 documente un setup spécifique pour le 106 t/s :

DFLASH27B_KV_K=q4_0 DFLASH27B_KV_V=q4_0 DFLASH27B_FA_WINDOW=0 \
  python scripts/run.py --budget 10 --max-ctx 4096 ...

Trois différences vs ma config :

Je patch via kubectl patch deployment (au lieu de bumper la chart, plus rapide).

Et je lance un sweep complet : 6, 10, 14, 18, 22, 26, 30. Sept builds × 5 min boot + 30 s bench = ~40 min. Je laisse tourner.

Le sweep complet

BudgetStatust/s avg
6crash 503 1er request
10crash 503
14crash 503
18OK84,8 [83,5-85,9]
22OK ← peak88,7 [87,5-89,4]
26OK mais drop76,7 [75,5-77,5]
301 run OK puis crash 50368,3 → instable

La courbe en dôme. Peak à 22.

+0,2 t/s vs ma v1.4.4 baseline (88,5). Dans le bruit de mesure.

Trois explications possibles

1. Le matched 3.6 SWA draft ne brille pas sur prompts courts

Mon prompt Space Invaders fait ~25 tokens. SWA optimisations (window=2048) sur le drafter ne se manifestent que quand la séquence du draft dépasse la fenêtre. À 25 tokens, le drafter voit tout, comme un full-attention layer normal.

Le sweep RTX 4090 du PR #94 a probablement utilisé bench_he.py qui run HumanEval (prompts plus longs, code complet à compléter). Plus en accord avec là où SWA gagne.

Pour valider, faudrait re-tester avec un prompt 8K-16K tokens. Mais notre Space Invaders bench est notre standard depuis le début, et c’est révélateur de cas d’usage chat normal.

2. Le sweet spot diffère par architecture GPU

PR #94 sur RTX 4090 (Ada sm_89) = sweet spot budget 10, max 106 t/s. Mon Olares One RTX 5090M (Blackwell sm_120) = sweet spot budget 22, max 88,7 t/s.

Différence radicale. Pourquoi ?

DDTree budget contrôle la largeur du verify batch. Plus c’est grand, plus on parallélise mais plus la mémoire requise grimpe. Blackwell consumer (5090M) a moins de tensor core resources par SM que Ada datacenter — verify trop large = bandwidth-bound. Sweet spot plus haut sur Blackwell parce que… non, c’est pas logique. Plus haut = plus de batch = plus de bandwidth nécessaire.

Hypothèse plus probable : avec q4_0 KV cache la mémoire-par-token est plus dense. Budget faible (6, 10, 14) → trop de fragmentation et le daemon OOM dès le premier request (503). Budget 22 = sweet spot où on a assez de mémoire pour le verify batch sans crasher. Budget 26+ = verify dominate l’overhead, drop.

C’est cohérent avec le fait que mes budget 6/10/14 crashent 503 alors que le RTX 4090 du PR #94 les gère. Le 4090 desktop 24 Go a plus de free VRAM après modèle + drafter (probablement parce que pas de HAMi vGPU en plus).

3. La PR #94 est en cours, peut-être pas finalisée

PR #94 reste OPEN (4 mai). Pas encore mergée. Le fait que mon test ne reproduise pas le 106 t/s pourrait simplement vouloir dire que la branche n’est pas encore à son état final. Sandropuppo a peut-être des commits supplémentaires en local pas encore push.

À surveiller. Si la PR merge avec un fix qui change la donne sur sm_120 spécifiquement, je rebuild.

Le verdict honnête de la journée

Plateau à ~88 t/s sur Qwen3.6-27B / RTX 5090M / 24 Go. Trois stacks distincts y arrivent, à 0,5 t/s près :

Stackt/s avg
vLLM Turbo (Sandermage Genesis + TurboQuant K8V4 + MTP n=3)88,0
Lucebox v1.4.4 (tq3_0 KV + DDTree 22)88,5
Lucebox v1.6.0 (PR #94 + q4_0 KV + DDTree 22)88,7
buun-llama-cpp DFlash + Q8_0 GGUF drafter80
llama.cpp standard (sans spec)33-36

Pour breakthrough au-delà de 90 t/s, plusieurs voies upstream à attendre :

Aucune de ces voies n’est actionnable aujourd’hui. 88 t/s est notre cap pratique sur ce hardware fin 2026-Q2.

La leçon de cet épisode

Pas tous les benchmarks upstream se reproduisent sur n’importe quel hardware. PR #94 sur RTX 4090 desktop 24 Go = +57%. Sur RTX 5090M Blackwell mobile 24 Go = +0,2%. Même VRAM, même modèle, même quantization — différence d’architecture GPU et de configuration mémoire suffit à invalider le claim.

Et la transparence sur les résultats négatifs est aussi utile que la transparence sur les positifs. Quelqu’un d’autre va lire la PR #94, voir 106 t/s annoncé, tenter de reproduire sur son 5090. Ce post lui économise un build de 2 h et lui dit où regarder.

Prochaines étapes

Voilà ! Si quelqu’un sur 5090M ou autre Blackwell consumer 24 Go reproduit ces chiffres ou trouve le déblocage qui m’échappe, je veux savoir comment.


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