CoolFace
Modelpublic

patdev/k3-a40-bootstrap

sourceHugging Faceotherupdated 18d agoView on Hugging Face
0likes1.3kdownloads
RESULTS.md618 linesDownload Raw Back to root
1# Résultats mesurés — Kimi-K3, Kimi-Linear, Qwen3-Coder sur A402 3Toutes les valeurs ci-dessous sont **mesurées**, jamais estimées, sauf mention4explicite. Le coût au million est calculé depuis le tarif horaire RunPod et le5débit mesuré. Protocole commun : `bench_endpoint.sh`, publié à côté.6 7## Synthèse8 9| | Kimi-K3 REAP448 | Kimi-Linear 48B | Qwen3-Coder-30B |10|---|---|---|---|11| moteur | llama.cpp | vLLM 0.27.1 | vLLM 0.27.1 |12| matériel | 5× A40 | **1× A40** | **1× A40** |13| $/h | 2,20 | 0,44 | 0,44 |14| decode 1 flux | 7,29 tok/s | 67–71 tok/s | **77,6–130 tok/s** |15| agrégé 32 flux | ~14,5 (4 flux) | 780 tok/s | **1 166 tok/s** |16| prefill à froid | ~165 tok/s | **6 162 tok/s** | 3 957 tok/s |17| prefill à chaud | ~cache OK | 6 430 (pas de cache) | **63 315 tok/s** |18| contexte | 524 288 | **1 048 576** | 262 144 |19| $/1M à 32 flux | ~85 (1 flux) | 0,157 | **0,105** |20| français | cassé | fluide | correct |21| tool calling | — | oui (`kimi_k2`) | oui (`qwen3_coder`) |22 23## Kimi-K3 sur llama.cpp — la progression complète24 25```26Colibri CUDA custom, L40S            2,32 tok/s   point de depart27llama.cpp 2x A40, apres corrections  2,9428llama.cpp 5x A40, placement identique 5,44        <- effet vCPU (16 -> 41)29llama.cpp 5x A40, tout en VRAM       7,3530idem sur 600 tokens reels            7,2231idem contexte 262 144                7,2532idem contexte 524 288                7,29        <- plafond33idem contexte 1 048 576              OOM (29 Gio de KV f16)34```35 36Le débit est **plat sur 32× de contexte** : c'est la géométrie KDA+MLA qui le37permet (24 couches sur 93 mettent en cache, les 69 autres portent un état38récurrent de taille constante). 16 384 n'était pas une limite matérielle, juste39un défaut jamais testé.40 41### Ce qui bornait vraiment le débit42 43Six placements couvrant 60 à 88 Go de VRAM n'avaient rien changé. La cause n'est44ni le kernel ni la bande passante :45 46```471 flux    5,56 tok/s agrege482 flux    9,85 tok/s   1,77x494 flux   14,53 tok/s   2,61x50```51 52La concurrence monte, donc le matériel était **inactif** entre les tokens :53llama.cpp répartit les couches entre GPU et les exécute en séquence, un seul54calcule à la fois. Confirmation arithmétique indépendante : ~7 Go lus par token55à 138 ms = **51 Go/s contre 696 disponibles**, soit 7 % du plafond.56 57### Six hypothèses réfutées par la mesure58 59| hypothèse | ce qui la tue |60|---|---|61| le modèle est cassé | Tokyo/Washington/Stockholm corrects, récursion Fibonacci correcte, chinois fluide |62| le calcul CPU des experts domine | 16 → 8 experts ne donne que **+28 %** |63| les traversées CPU↔GPU dominent | autofit (1–2) ≈ n-cpu-moe 86 (172) |64| le kernel MoE est le goulot | fused SiTU **0 %**, warp-row **+1,2 %** |65| on est borné par la bande passante | 7 % du plafond mesuré |66| le code généré est cassé | test direct correct ; le prompt du selftest était ambigu |67 68### DSpark : zéro gain, zéro télémétrie69 70```71avec speculation   7,32 / 7,33 tok/s     aucune metrique draft_n72sans speculation   7,33 / 7,35 tok/s73```74 75Le mécanisme n'était pas cassé, le moteur l'était : la même idée sous vLLM donne76+86 % avec 68 % d'acceptation et une télémétrie complète.77 78## Kimi-Linear 48B — 1M de contexte sur une seule carte79 80```8127 couches = 7 MLA + 20 KDA      KV/token = 7 x (512+64) x 2 = 7,88 Ko82                                 (Kimi-K3 : 24 couches -> 27,6 Ko)83poids AWQ4 28,4 Gio + 7,88 Gio de KV a 1M  =  36,3 Go sur une carte de 4684```85 86vLLM le confirme au démarrage : **`GPU KV cache size: 1 416 566 tokens`**.87 88```89flux    agrege   /flux    $/1M90  1      67,4     67,4    1,81491  4     206,6     51,6    0,59292  8     352,4     44,0    0,34793 16     556,1     34,8    0,22094 32     779,9     24,4    0,15795```96 97### La spéculation n-gram y est cassée98 99L'échantillonnage par rejet est censé être **sans perte** : toute différence de100sortie est un bug. Elle corrompt le code, de façon reproductible :101 102```103              avec speculation                     sans104add()     return a -b):\n    return a -      return a - b\n\ndef multiply(a,105fibonacci fibonacci(n-1(n-1) + fibonacci(n-2) fibonacci(n-1) + fibonacci(n-2)106```107 108Signature : un fragment tout juste émis, recollé au mauvais endroit. La prose et109la copie littérale restent parfaites — c'est pourquoi il a fallu des sondes110ciblées : le code est dense en répétitions courtes (parenthèses, opérateurs) sur111lesquelles le n-gram s'accroche.112 113Elle est en plus **3 à 4× plus lente**, vLLM désactivant les CUDA graphs sous114spéculation sur `TritonMLABackend` :115 116```117flux       avec spec   sans spec   rapport118  1           23,1        71,2      3,1x119  4           58,7       249,6      4,3x120 32          203,9       781,0      3,8x121$/1M a 32     0,600       0,157122```123 124## Qwen3-Coder-30B — le meilleur compromis pour Claude Code125 126```127flux    agrege    /flux    $/1M128  1       77,6     77,6    1,575129  4      265,3     66,3    0,461130  8      496,8     62,1    0,246131 16      782,4     48,9    0,156132 32    1 165,6     36,4    0,105133 134prefill 38 494 tok a froid en 10,42 s = 3 693 tok/s ; a chaud 1,07 s = 63 315135decode a 119k de contexte : 34,3 tok/s136```137 138### La spéculation dépend du régime139 140Deux pods identiques tournant **simultanément**, pour éliminer la dérive d'hôte :141 142```143A. generation pure (aucun recouvrement)   102,21 -> 58,49 tok/s    -43 %144B. edition de code (la sortie reprend)    130,16 -> 242,39 tok/s   +86 %145```146 147Ce n'est pas un gain gratuit, c'est un **pari sur la répétition**. Claude Code148vit entièrement dans le régime B. Télémétrie : 706 acceptés sur 1035 = 68,2 %,149par position 179/156/131/120/120, longueur acceptée moyenne 3,41.150 151Mais elle **s'effondre sous concurrence**, car vLLM rabaisse152`max_num_scheduled_tokens` à 2048 :153 154```155                 1 flux    4      8      16      32156sans speculation   77,6   265,3  496,8   782,4  1165,6157avec speculation   79,2   110,1  154,4   271,2   296,1158```159 160## Comparaison externe161 162```163API Kimi-K3 officielle (RunPod)   29,2 tok/s   ~16 $/1M   pleine precision164notre Kimi-K3 auto-heberge         7,3 tok/s   ~85 $/1M   1,14 bit/poids165notre Qwen3-Coder-30B             77,6 tok/s  0,105-1,58  4 bits166```167 168L'auto-hébergement de Kimi-K3 sur A40 est dominé sur tous les axes. Il n'achète169ni le prix ni la qualité — il achète la confidentialité et le contrôle du170contexte.171 172### Travaux antérieurs (dépôt Kimi-K3-L4-GenAI-TurboQuant, 8 août 2026, 1× L4)173 174```175vLLM AWQ Qwen3.5-9B + LoRA K3 + MTP-1   32,320 tok/s   485/533 = 90,99 %176ORT GenAI CUDA INT4                     30,271177vLLM AWQ + LoRA K3, sans speculation    22,674178OpenVINO INT4 g128, 8 threads (CPU)      5,029179```180 181Cette lignée concluait déjà que **vLLM + AWQ est la bonne pile**. Le chemin suivi182ici y arrive indépendamment, en mesurant la sérialisation de llama.cpp.183 184Le benchmark TurboQuant MLA du même dépôt confirme par un chemin totalement185indépendant la dérivation faite ici : 4 718 592 octets/couche pour 4096 tokens =1861152 octets/token/couche × 24 couches = **27,6 Ko/token**, exactement la valeur187calculée depuis `config.json`. En TQ4 : compression 3,945×, **6,844 Gio pour 1M188tokens sur 24 couches** — de quoi mettre Kimi-K3 à 1M dans les ~25 Go restés189libres, si l'implémentation existait ailleurs que dans une opération ONNX190compilée en sm_89.191 192## Aucune donnée sur Qwen3-Coder-Next 80B193 194Trois tentatives, trois échecs d'infrastructure, zéro requête servie.195 196```1971   bloque 22 min a l'init NCCL peer-to-peer sur 2x A401982   NCCL_P2P_DISABLE=1 leve ce blocage, puis boucle ~10 min sur199    "No available shared memory broadcast block found in 60 seconds"2003   --enforce-eager passe la compilation et charge les poids (23,23 Gio/GPU)201    et le KV (16,23 Gio/GPU), puis rebloque au meme endroit202```203 204`NCCL_P2P_DISABLE=1` est **nécessaire** au tensor parallelism sur une paire205d'A40 RunPod. Le second blocage reste non diagnostiqué ; le suspect est206`VLLM_WORKER_MULTIPROC_METHOD=spawn`, que j'avais introduit en même temps que le207correctif NCCL — deux variables changées d'un coup, ce qui était une erreur de208méthode. Son log de démarrage a tout de même livré un point dur :209`enable_prefix_caching=False`, la même limitation hybride que Kimi-Linear.210 211## Limites d'exploitation mesurées212 213- **Proxy RunPod : coupure à ~125 s** (Cloudflare `524`). Un prefill à froid214  plus long ne passe pas en un appel — mesuré à ~40k tokens sur Kimi-K3 et215  ~232k sur Qwen. Parade : découper, chaque requête étendant le préfixe caché.216- **Prefill de Kimi-K3, dégradation douce** : 228,6 → 149,8 tok/s de 8k à 43k de217  contexte, soit −34 % pour 5× le contexte. Bien mieux que quadratique, puisque218  seules 24 des 93 couches ont une attention complète.219- **`--gpu-memory-utilization 0.93` fait échouer Kimi-Linear** au tout dernier220  pas, dans le rejection sampler qui réclame 160 Mio quand il en reste 143.221  0,90 laisse la marge et conserve plus d'1M de tokens de KV.222 223---224 225# Optimisation vers 500 tok/s — endpoint Anthropic, 1× A40226 227## Le résultat228 229```230edition de code, mono-flux, via /v1/completions (6 essais consecutifs)231   555,96  598,49  579,65  567,95  575,66  570,69 tok/s      moyenne 574,7232 233via /v1/messages, protocole Anthropic (le chemin de Claude Code)234   504,94  563,26  565,83 tok/s   non streame235   578,00 tok/s                   streame236```237 238Tous au-dessus de 500, y compris à travers le pont. Le coût tombe à239**0,21 $ / 1M de tokens en mono-flux** sur une carte à 0,44 $/h.240 241## Le levier, et l'indicateur trompeur242 243```244profondeur   debit         acceptation   longueur acceptee245n=5          259,2 tok/s      68,2 %          3,41246n=12         363,9 tok/s      26,9 %          3,23247n=24         574,7 tok/s      71,5 %         17,16248```249 250**Le taux d'acceptation n'est pas la métrique utile.** Il chute de 68 % à 27 %251entre n=5 et n=12 pendant que le débit monte de 40 % : ce qui compte est le252nombre de tokens émis *par passe avant*, pas la fraction acceptée. Suivre le253taux d'acceptation aurait conduit à conclure que n=12 était une régression.254 255Le signal exploitable était la **queue par position** : à n=12 elle restait256plate (257/118/82/72/71/63/61/59/59/58/58/51), donc le 12ᵉ token deviné était257encore accepté ~20 % du temps — la profondeur n'était pas saturée. À n=24, la258longueur acceptée moyenne atteint **17,16 tokens**, parce qu'en édition de code259la sortie est largement prédictible depuis le prompt.260 261Aucun motif de corruption détecté à n=24 sur Qwen, et les annotations de type262sont correctement appliquées.263 264## L'autre levier : `max-num-batched-tokens`265 266vLLM le rabaisse à 2048 dès que la spéculation est active, et prévient lui-même267que c'est sous-optimal. Le corriger à 16384 récupère une partie de268l'effondrement en concurrence :269 270```271flux                1      4      8     16     32272sans speculation  77,6  265,3  496,8  782,4  1165,6273spec n=5          79,2  110,1  154,4  271,2   296,1274spec n=12 + 16384 93,3  186,9  278,4  297,2   336,9275```276 277## Le compromis à assumer278 279La spéculation **gagne en mono-flux et perd en agrégé** : les brouillons280consomment le budget de batch. Il n'existe pas de réglage qui gagne partout.281 282```283un seul utilisateur (Claude Code)   speculation n=24   -> 575 tok/s, 0,21 $/1M284service multi-utilisateurs          speculation OFF    -> 1166 tok/s a 32 flux, 0,105 $/1M285```286 287Les deux franchissent 500 tok/s sur une seule A40, par des chemins opposés.288Le défaut du dépôt est la spéculation, puisque la cible visée est Claude Code.289 290## Le plafond physique, et pourquoi il est dépassé291 292```293poids actifs lus par token   ~4,7 Go / 696 Go/s      = 6,8 ms294plafond mono-flux SANS speculation                    ~147 tok/s theorique, ~130 mesure295```296 297575 tok/s en mono-flux dépasse ce plafond d'un facteur 4,4 — ce qui n'est298possible que parce que la spéculation émet plusieurs tokens par lecture des299poids. Sans elle, aucun réglage ne peut approcher 500 en mono-flux sur cette300carte.301 302---303 304# CORRECTION — le cache de préfixe fonctionne sur Kimi-Linear305 306Une section plus haut affirme que Kimi-Linear n'a pas de cache de préfixe, sur la307base d'un rapport froid/chaud de 1,04×. **C'était une erreur de configuration de308ma part, pas une limite du modèle** : le pod concerné ne passait pas309`--enable-prefix-caching`. Avec le flag explicite, sur la même carte :310 311```312                        sans le flag     avec le flag313prefill a froid          6 162 tok/s      7 647 tok/s314prefill a chaud          6 430 tok/s     36 257 tok/s315rapport                     1,04x            4,74x316```317 318Conséquence pour un client agent : un prompt système de 32k **est** mis en cache319sur Kimi-Linear. L'argument qui le disqualifiait pour Claude Code tombe.320 321## Kimi-Linear, mesures définitives (pod persistant, flags corrects)322 323```324flux         1      4      8     16     32325agrege    83,9  250,6  402,9  616,4  772,4 tok/s326$/1M     1,457  0,488  0,303  0,198  0,158327 328prefill froid   7 647 tok/s     (Qwen : 4 485)329prefill chaud  36 257 tok/s     (Qwen : 70 568)330edition de code   100,5 tok/s   (Qwen : 575)331contexte      1 048 576         KV 1 505 550 tokens332protocole Anthropic : les 5 controles passent333```334 335Kimi-Linear franchit 500 tok/s **en agrégé dès 16 flux** (616,4). Qwen les336franchit **en mono-flux** (575). Les deux tiennent la cible sur une seule A40,337par des chemins différents : la spéculation pour Qwen, la concurrence pour Kimi338— chez qui la spéculation reste inutilisable puisqu'elle corrompt le code.339 340## Choix recommandé341 342| besoin | modèle | pourquoi |343|---|---|---|344| Claude Code, un utilisateur | **Qwen3-Coder-30B** | 575 tok/s en édition de code, cache de préfixe 16×, 0,21 $/1M |345| contexte au-delà de 262k | **Kimi-Linear-48B** | 1 048 576 tokens sur une carte, prefill à froid 1,7× meilleur |346| service multi-utilisateurs | Qwen sans spéculation | 1 166 tok/s à 32 flux, 0,105 $/1M |347 348---349 350# Endurance agentique — 553 tours de codage en boucle351 352Un pic à 575 tok/s sur 900 tokens ne dit rien de la tenue sur une session. Test353simulant le régime réel de Claude Code : prompt système volumineux, tours354successifs avec résultats d'outils réinjectés, sorties de code, contexte qui355gonfle puis se compacte.356 357```358553 tours   387 100 tokens emis   contexte 2 484 -> 35 352359 360debit soutenu     268,2 tok/s        0,456 $ / 1M361par tour          min 108   mediane 330   max 453362premier tiers     301,0 tok/s363dernier tiers     304,6 tok/s      <- aucune derive364```365 366**Le débit ne se dégrade pas sur la durée.** La variation par tour suit le cycle367du cache de préfixe, pas une fatigue du serveur.368 369## Le compactage de l'historique décide de la moitié du débit370 371Première version du test : retirer les deux plus anciens messages **à chaque372tour** dès que l'historique dépasse une taille. Le préfixe change donc à chaque373requête, le cache est invalidé en permanence :374 375```376elagage tour par tour     173,8 tok/s soutenus377compactage par blocs      268,2 tok/s soutenus     +54 %378```379 380Visible dans le journal au tour 127 : le compactage retire 32 messages, le381contexte retombe de 35k à 19k, le tour suivant tombe à 165 tok/s le temps que382le cache se reconstruise, puis remonte immédiatement à 360-410.383 384**Un compactage rare et massif coûte un tour. Un élagage permanent coûte la385moitié du débit.** Cela vaut pour tout client agent qui gère une fenêtre.386 387## Les trois régimes, à ne pas confondre388 389```390pic, 900 tokens, contexte court        575 tok/s     0,21 $/1M391tour isole a 20k de contexte           421 tok/s392session soutenue, compactage compris   268 tok/s     0,46 $/1M393```394 395Le troisième est celui qui décrit un usage réel. C'est lui qu'il faut citer396pour dimensionner, et non le premier.397 398---399 400# Plusieurs sessions Claude Code simultanées401 402Deux mécanismes indépendants, qui tirent en sens contraire.403 404## Le cache de préfixe est global, et c'est un atout405 406Ce n'est pas un cache par session mais un arbre partagé entre toutes les407requêtes. Plusieurs clients Claude Code envoient le **même** prompt système :408il n'est donc prefillé qu'une fois pour tous.409 410```411sessions   blocs reutilisees412   2       96 %  (24 480 / 25 369)413   4       96 %  (49 104 / 50 997)414   8       92 %  (94 208 / 102 253)415```416 417Il survit aussi **entre** les campagnes : un second passage sur les mêmes418prompts est parti à 187,5 tok/s agrégés contre 115,1 au premier, sans autre419changement que le cache déjà chaud.420 421## La spéculation, elle, ne gagne que si l'on est seul422 423Sessions agentiques simultanées, même matériel, même protocole :424 425```426              AVEC spec n=24        SANS spec         ecart427sessions    agrege  /session     agrege  /session428   1           -        -         121,8   121,8429   2         187,5     93,8       204,2   102,1       +9 %430   4         240,4     60,1       333,9    83,5      +39 %431   8         323,8     40,5       503,2    62,9      +55 %432```433 434Les brouillons consomment le budget de batch : dès **deux** sessions la435spéculation coûte plus qu'elle ne rapporte, et l'écart se creuse. Elle reste436imbattable en solo sur de l'édition de code (575 tok/s), régime où elle émet43717,16 tokens par lecture des poids.438 439**Le défaut du dépôt est donc `VL_SPEC=off`.** Passer à `on` pour un usage440strictement mono-session.441 442## Ce que ça donne concrètement443 444```4451 session, edition de code, spec on     575 tok/s      0,21 $/1M4462 sessions, spec off                    102 tok/s ch.  0,60 $/1M4474 sessions, spec off                     83 tok/s ch.  0,37 $/1M4488 sessions, spec off                     63 tok/s ch.  0,24 $/1M449```450 451Le débit par session baisse, le coût au million s'améliore : la carte est452mieux occupée. Huit sessions Claude Code simultanées tiennent sur une seule453A40 à 0,44 $/h, à 63 tok/s chacune.454 455La capacité KV n'est pas le mur : ~450 000 tokens de cache pour des sessions456qui plafonnent autour de 35 000 chacune, soit une douzaine avant saturation.457 458---459 460# Le plafond de l'A40, et pourquoi 8 × 200 tok/s n'y tient pas461 462## La montée en charge, jusqu'au mur463 464```465sessions   agrege     /session    $/1M    cache partage466   1        122,9      122,9      0,995   76 %467   2        209,5      104,7      0,583   95 %468   4        331,2       82,8      0,369   94 %469   8        512,1       64,0      0,239   96 %470  16        776,8       48,5      0,157   93 %471  32      1 159,7       36,2      0,105   92 %472```473 474À 32 sessions : 36,25 pas par seconde × ~18 Go de poids lus par pas =475**660 Go/s sur les 696 disponibles, soit 95 % du plafond de bande passante**.476Le débit agrégé de ~1 160 tok/s est la limite matérielle, pas un défaut de477réglage.478 479Une cible de 8 × 200 = 1 600 tok/s demanderait 200 pas/s, soit **~2 000 Go/s** —480presque trois fois ce que la carte peut lire.481 482## L'ordonnancement asynchrone ne donne rien483 484vLLM le refusait tant que la spéculation tournait ; une fois celle-ci coupée, il485devient disponible. Résultat, dans le bruit :486 487```488sessions   sans async   avec async489   1         121,8        122,9490   2         204,2        209,5491   4         333,9        331,2492   8         503,2        505,5493```494 495Cohérent avec le reste : dans ce régime on est **borné par le GPU**, il n'y a496donc pas d'ordonnancement CPU à recouvrir.497 498## La spéculation perd à toute profondeur, dès deux sessions499 500Testée à deux profondeurs pour écarter l'idée qu'une profondeur faible501ménagerait le budget de batch :502 503```504sessions   sans spec   spec n=24   spec n=4505   4         83,5        60,1        25,3506   8         64,0        40,5        22,1507  16         48,5          -         23,1508```509 510`n=4` est **encore pire** que `n=24`. Le coût n'est donc pas le budget de batch511mais la **vérification payée sur chaque séquence** : plus il y a de séquences,512plus elle pèse. La spéculation reste imbattable en solo (575 tok/s en édition513de code, 17,16 tokens émis par lecture des poids) et perdante partout ailleurs.514 515## Comparatif matériel, sur ce qui borne vraiment516 517| | $/h | VRAM | bande passante | vs A40 | $/token relatif |518|---|---|---|---|---|---|519| **A40** | 0,44 | 48 Go | 696 Go/s | — | **référence** |520| RTX 4090 | 0,74 | 24 Go | 1008 Go/s | 1,45× | 1,16× |521| L40 | 0,82 | 48 Go | 864 Go/s | 1,24× | 1,50× |522| L40S | 0,99 | 48 Go | 864 Go/s | 1,24× | 1,81× |523| A100 SXM | 1,59 | 80 Go | 2039 Go/s | 2,93× | 1,23× |524 525**L'A40 est l'optimum économique** : toute alternative coûte plus cher au token.526Elles achètent de la latence, pas de l'économie. Le RTX 4090 est en outre527disqualifié par ses 24 Go, qui ne laissent presque rien au KV.528 529Une cible de 200 tok/s par session à 8 sessions n'est atteignable que sur A100530SXM (~190 tok/s attendus, extrapolés de la bande passante — non mesurés).531 532---533 534# L'élagage des experts ne donne rien — et ce que ça révèle535 536Hypothèse testée : à forte concurrence tous les experts finissent par être lus à537chaque pas, donc c'est la taille **totale** du modèle qui borne le débit, pas les5383 B actifs. Réduire la taille devrait donc augmenter le débit proportionnellement.539 540`mattbucci/Qwen3-Coder-REAP-25B-A3B-AWQ` : 103 experts au lieu de 128,541**12,9 Gio au lieu de 16,9** (−24 %). Gain attendu ~1,31×.542 543```544sessions    30B complet (16,9 Gio)   REAP-25B (12,9 Gio)545   1            122,9                    124,9546   8            512,1                    511,8547  32          1 159,7                  1 171,6548```549 550**Identique au bruit près.** L'hypothèse est réfutée : le débit n'est pas borné551par la lecture des poids.552 553## Ce que le mur n'est pas554 555```556lecture des poids   -24 % de poids -> 0 % de debit        refute557calcul brut         1171 tok/s x 3 G x 2 = ~7 TFLOPS558                    sur ~150 TFLOPS disponibles = 5 %     ecarte559ordonnancement CPU  --async-scheduling : dans le bruit    refute560speculation         perdante a n=24 ET a n=4              refute561```562 563Il reste **l'efficacité des kernels MoE** : la dispersion des tokens vers 128564experts, avec très peu de lignes par expert et par pas. C'est un mur565d'implémentation, pas de matériel — ce qui explique d'un coup pourquoi aucun des566quatre leviers testés n'a bougé le débit.567 568## Décision569 570Le modèle non élagué est conservé : le REAP coûte 20 % des experts pour zéro571gain mesuré, donc de la qualité perdue sans contrepartie. Il reste disponible572(`VL_MODEL=reap`) au cas où les 4 Go de VRAM libérés seraient utiles au KV.573 574---575 576# Le modèle dense : quatrième hypothèse réfutée577 578Expérience discriminante. Si le plafond venait de la dispersion des tokens vers579128 experts, un modèle **dense** de taille totale comparable devait se comporter580différemment. `cyankiwi/Qwen3.8-27B-AWQ-INT4` : 19,6 Gio, aucun expert.581 582```583sessions      MoE Coder-30B     Dense 27B        ecart584   1             122,9            26,2        4,7x plus lent585   8             512,1           167,1        3,1x plus lent586  32           1 159,7           320,8        3,6x plus lent587 588montee 32/1       9,4x            12,2x589```590 591Le dense monte légèrement mieux en concurrence, mais part de si bas que ça ne592compense jamais. **La dispersion MoE n'est pas le mur — c'est l'avantage** : le593MoE ne lit que ~5 Gio d'actifs par token là où le dense en lit 19,6.594 595## Ce que le plafond n'est pas596 597Cinq mécanismes testés, cinq réfutations :598 599```600lecture des poids     -24 % de poids -> 0 % de debit601calcul brut           MoE ~5 %, dense ~11 % du plafond FLOPS602bande passante        MoE ~45 %, dense ~30 % des 696 Go/s603dispersion MoE        le dense est 3 a 4x plus lent604ordonnancement CPU    --async-scheduling dans le bruit605speculation           perdante a n=24 ET a n=4606```607 608**Aucun mécanisme validé** n'explique le plafond de ~1 160 tok/s. Ce qui est609établi, c'est ce qu'il n'est pas. Publier cette liste vaut mieux qu'habiller une610sixième hypothèse en explication.611 612## Configuration retenue613 614`cyankiwi/Qwen3-Coder-30B-A3B-Instruct-AWQ-4bit`, spéculation coupée,615ordonnancement asynchrone, `max-num-seqs 64`, KV en fp8, contexte 262 144.616C'est la meilleure combinaison mesurée, et les six variantes essayées sont617documentées ci-dessus pour qu'on ne les retente pas.618