Kazeia-engine/CHANTIER_HMX_DENSE.md

4.2 KiB
Raw Blame History

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_pendingllama_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).