Kazeia-engine/CHANTIER_HMX_DENSE.md

60 lines
4.2 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Chantier — matmul HMX robuste pour le DENSE sur HTP (crash 0x2e)
Objet : faire tourner le dense (qwen3) sur HTP en **HMX** (prefill ~295) au lieu de HVX (~40), maintenant
que le `.pte` est retiré (l'engine est le seul runtime LLM). Bloqueur = crash du matmul HMX sur le dense.
## Symptôme
Prefill dense (qwen3-4B Q4_0) sur HTP avec HMX (défaut) → `ggml-hex: dspqueue_read failed: 0x0000002e`
dans `flush_pending``llama_decode`, dès que le prompt dépasse ~12-16 tokens. HVX (`GGML_HEXAGON_USE_HMX=0`)
ne crashe pas. La 3.5 (hybride) ne crashe pas en HMX.
## Repro
```
GGML_HEXAGON_OPLOG=1 GGML_HEXAGON_OPBATCH=1 LD_LIBRARY_PATH=./lib ADSP_LIBRARY_PATH=./lib \
./llama-cli -m Qwen3-4B-Q4_0.gguf -ngl 99 -dev HTP0 -t 4 --reasoning off -cnv -st --temp 0 -n 2 \
-p 'un deux trois quatre cinq six sept huit neuf dix onze douze treize quatorze quinze seize'
```
## Hypothèse ÉCARTÉE : overflow fp16
Le matmul fautif a une **activation max-abs = 9.8** (mesuré via OPLOG `s1_amax`), très en-dessous de la plage
fp16 (65504). **Ce n'est PAS un overflow.** Confirmé : clamp ±65504 (conversion f32→f16) ET scaling activations
÷32 puis ÷256 (avec ×S en sortie) n'ont rien changé au crash. Donc ni l'entrée ni l'accumulateur fp16 ne débordent.
## Localisation (via instrumentation, voir plus bas)
Dernier op avant le 0x2e = un **MUL_MAT q4_0**, juste après `FLASH_ATTN_EXT` :
```
KZOP MUL_MAT dst=[2560,38,1,1] src0=q4_0[4096,2560] src1=f32[4096,38] s1_amax=9.8 <- CRASHE
```
C'est l'**o_proj** (projection de sortie d'attention : in 4096 = 32 têtes×128, out 2560 = hidden), donc **k=4096**.
Les autres MUL_MAT du graphe ont **k=2560** et passent (ffn gate/up `[2560,4096]`, qkv `[2560,1024]`).
**suspect : le chemin HMX pour k=4096** (n_dot_tiles = 4096/32 = 128). `OPFILTER=MUL_MAT` (matmuls→CPU)
supprime le crash, confirmant que c'est bien un MUL_MAT HMX.
## Instrumentation — ce qui marche / ne marche pas sur ce device (non-rooté)
-**FARF DSP** : bloqué. Le watcher cherche `<process>.farf` dans `/vendor/lib/rfsa/adsp` (lecture seule
sans root). `FARF(RUNTIME_HIGH)` ne sort pas en logcat sans ce fichier. `getenv` ne marche PAS côté skel DSP.
-**GGML_HEXAGON_VERBOSE** : utilise `GGML_LOG_DEBUG`, masqué par le cli.
-**OPLOG CPU-side** (committé) : `enqueue_op` (ggml-hexagon.cpp) logge en `fprintf(stderr)` chaque op
(type, dims, type/dims src, max-abs activation f32), gaté par `GGML_HEXAGON_OPLOG`. Combiné à
`GGML_HEXAGON_OPBATCH=1` (1 op par flush), le **dernier KZOP avant le 0x2e = l'op fautive**.
- Build debug FARF dispo si besoin : `cmake -DHEXAGON_HTP_DEBUG=ON` dans le sous-build htp-vNN → active
`FARF_HIGH=1` (logs par-matmul m/k/n), mais inutile ici faute de capture (root).
## Prochaines étapes
1. **Isoler le k=4096** : reproduire le matmul seul, q4_0 `[4096,2560] × f32[4096,38]` (k=4096, m=2560, n=38),
via test-backend-ops (ajouter le cas) ou un petit harness type `dual_ctx`. Confirmer le crash hors modèle.
Tester k=4096 avec n et m variés pour cerner si c'est k=4096 seul ou la combinaison.
2. **Comparer k=4096 vs k=2560** dans `hmx_matmul_q_f32` / `core_dot_chunk_fp16` (hmx-matmul-ops.c) :
- le VTCM chunking `hmx_compute_chunks` (taille des tuiles pour 128 dot-tiles vs 80),
- la boucle k par blocs de 32 et le `range = 2048*k_block - 1` (déborde-t-il un champ 16 bits cumulé ?),
- le staging poids dequant (`dequantize_x4x2_weight_chunk_to_fp16_tiles`) et la taille `vec_dot_size = k*2`
(8192 o/row pour k=4096) vs le budget VTCM → débordement d'index/buffer probable à 128 dot-tiles.
3. **Fix** : corriger le tiling/staging pour k=4096 (gate oracle = test-backend-ops -o MUL_MAT, mais ⚠ ce test a
des FAIL `CPU=nan` PRÉ-EXISTANTS sur les petits q4_0 — comparer au baseline, ne pas s'y fier aveuglément).
Fallback acceptable si le fix est trop lourd : gater le HMX pour k≥4096 → HVX (comme le gate SSM_CONV n_t>1).
## État
**Non-bloquant** : le dense tourne déjà sur HTP en **HVX** (~40 prefill, stable, cohérent) via le routage
auto du JNI (`USE_HMX=0` pour le dense). Ce chantier = optimisation (40→295). 3.5 intacte (HMX + option C).
Outils committés : OPLOG (`GGML_HEXAGON_OPLOG`, dormant par défaut).