# Snapshots decoder /opt/Kazeia/kazeia-tts-decoder-ggml/src/ Le repo decoder est externe (mono-repo /opt/Kazeia, fichiers untracked en pratique). Ces snapshots gardent une trace des modifications apportées pour Phase 2 du chantier BigVGAN HMX. ## Modifications par fichier ### decoder.h - Ajout `std::vector backends` + `ggml_backend_sched_t sched` dans `struct Decoder`. - Ajout `bool owns_backends` pour la libération. - Nouvelle méthode `load_with_backends(path, devs)` : variante de `load_with_buft` qui prend une liste de backends et crée optionnellement un sched (gated par env `KZTTS_DECODER_SCHED`). - Nouvelle méthode `compute_graph(ctx, gf, n_threads)` qui dispatche vers `sched_compute` si sched actif, sinon `ggml_graph_compute_with_ctx` legacy. ### gguf_loader.cpp - Impl de `load_with_backends` : alloue les poids sur le buft du backend[0] (HTP si présent) via `load_with_buft`. Sched créé seulement si `KZTTS_DECODER_SCHED=1` (le sched complet nécessite refactor des stages). - Impl de `compute_graph` : sched path ou compute_with_ctx legacy. - `unload()` libère sched + backends si `owns_backends`. ### decoder.cpp - Ajout du timing par stage dans `Decoder::forward` (gated par `KZTTS_DECODER_PROFILE=1`). Imprime quant/preconv/pretr/upsample/bigvgan. - (pas d'autres modifs structurelles : le refactor stage_bigvgan en pattern sched-friendly reste à faire dans la session suivante) ## Modes de fonctionnement | Env | Effet | |---|---| | (rien) | path CPU pur historique, poids CPU buffer (default) | | `KZTTS_DECODER_HTP=1` | poids alloués sur HTP buffer, compute CPU pur via `opt_hostbuf=1` (HTP buffer CPU-mappable). Pas de gain HMX mais valide la chaîne. | | `KZTTS_DECODER_HTP=1 KZTTS_DECODER_SCHED=1` | sched créé, mais stages encore en compute_with_ctx → assertion `buffer_id >= 0` au premier compute. **NE FONCTIONNE PAS** sans refactor stages. | ## Phase 2b livrée — mais bloquée par limite backend Refactor stage_bigvgan en pattern sched-friendly **fait** : 1. ✅ snake constants pré-calculées au load (`ctx_const` + `buf_const`) 2. ✅ `stage_bigvgan_sched` (variante du stage_bigvgan legacy) 3. ✅ `ggml_init(no_alloc=true)` + `ggml_set_input/output` 4. ✅ `memset zeros + concat` remplacé par `ggml_pad_ext` 5. ✅ Wrapping sched_reset + alloc + tensor_set + compute + tensor_get 6. ✅ Switch dans `Decoder::forward` : `d.sched ? stage_bigvgan_sched : stage_bigvgan` **MAIS** : mesure montre que TOUS les nœuds tombent sur CPU malgré le sched. Le sched_debug (`GGML_SCHED_DEBUG=2`) confirme : - poids decoder bien sur HTP0 (buf_w 325 MB + buf_const 0.1 MB) - MUL_MAT/IM2COL/PAD/ADD assignés à CPU - decoder time = 3.95s (régression vs baseline 3.34s due aux copies inutiles) **Cause** : `ggml_hexagon_supported_mul_mat` rejette les MUL_MAT avec `ggml_nrows(src1) > 1024` (commentaire "no huge batches (for now)"). BigVGAN block 3 résiduels font conv1d k=7 sur T=59520 → im2col output a 59520 rows × 672 cols → `ggml_nrows(src1) >> 1024`. Tous les MUL_MAT BigVGAN sont au-dessus de la limite, donc rejetés par HTP, fallback CPU. ## Reprise Phase 2b plus tard Trois options pour débloquer : **(a) Modifier ggml-hexagon** pour supporter les gros batches MUL_MAT. Sous-chantier kernel hexagon (VTCM tiling, copies multiples). Semaines. **(b) Split BigVGAN MUL_MAT en chunks ≤ 1024 rows** côté graphe decoder. Refactor + copies CPU↔HTP par chunk. Gain incertain. **(c) Reprendre via étape F (CP HMX)** d'abord. CP a des MUL_MAT nrows(src1) ≤ 16 (1 prefill 2 tokens + 14 decode 1 token), largement sous la limite. Pattern identique au talker Qwen3.5 déjà validé. ## Rebuild ``` cd /opt/Kazeia/kazeia-tts-decoder-ggml/build-android-engine && \ make qwen3tts-decoder -j$(nproc) # puis côté Kazeia-engine cd /opt/Kazeia-engine/dist && ./build_tts_pipeline.sh ```