Kazeia-engine/dist/BUG_pte_inapp_qnn_version_m...

6.3 KiB

BUG in-app .pte 7B/8B (err 5010) — RÉSOLU : mauvaise version de backend QNN chargée par l'app

Date : 17/06/2026 · Sévérité : bloquant in-app pour les .pte denses multi-context (≥7B, num_sharding=2) Statut : cause isolée — ce n'est NI le .pte, NI le wrapper libkazeia_pte.so. C'est l'intégration app (résolution de lib QNN).

⚠️ Rétracte BUG_pte_multicontext_offset_overflow.md (théorie « overflow int32 » du .pte) : réfutée par le test CLI ci-dessous. Le .pte 8B (2ᵉ context group à 3,24 G > 2 GiB) charge et génère sans problème avec le bon runtime. Pas d'overflow.


1. TL;DR

L'erreur in-app Context group 1 does not exist / Error 5010 est la signature d'un backend QNN trop ancien (≠ QAIRT 2.42) qui ne sait pas désérialiser la structure multi-context (sharding=2) des .pte ≥7B. Le backend 2.42 (ship_runtime/) les charge parfaitement. L'app charge un autre libQnnHtp.so/backend que celui livré (collision de SONAME, très probablement avec la pile ORT-QNN du STT, ou une lib d'une autre version restée sur le chemin du linker).

Fix : garantir que c'est bien la pile QNN 2.42 qui est mappée dans le process app au moment du chargement .pte (pas la version du STT/Maven). Aucun changement de .pte ni de wrapper.


2. Preuve d'isolation (décisive)

Sur le même device, avec le ship_runtime/ 2.42 livré, sur le même .pte Qwen3-8B (le cas « échec » de la théorie overflow) :

Test sur Qwen3-8B (5,5 G, 2ᵉ context group à 3,24 G > 2 GiB) Résultat
Runner CLI qnn_llama_runner + ship_runtime 2.42 313 tokens, 9,65 tok/s, FR cohérent, EOS propre
Wrapper libkazeia_pte.so (notre JNI) + ship_runtime 2.42 41 tokens, 10,3 tok/s, cohérent

Dans les deux cas, le log montre QnnContextCustomProtocol expected magic 0x5678abcd but get 0x2000000 ET génère quand mêmece message est un INFO bénin présent dans les chargements qui marchent, pas la cause de l'échec. L'app, elle, enchaîne sur Context group 1 does not exist / err 5010 : c'est un second symptôme, propre à l'app, qui ne sort PAS avec le backend 2.42.

Conclusion logique : si c'était un overflow d'offset dans le .pte ou dans notre backend, le CLI et le wrapper échoueraient aussi. Ils réussissent. Donc l'app exécute un backend différent.


3. Cause racine — collision de version libQnnHtp / backend

libkazeia_pte.so ne NEEDED que libqnn_executorch_backend.so (le reste statique). Mais ce backend charge à son tour libQnnHtp.so / libQnnSystem.so par SONAME. Si l'APK contient plusieurs versions de ces libs — typiquement :

  • la pile ORT-QNN du STT (qui embarque sa propre libQnnHtp.so, possiblement une autre version QAIRT),
  • d'anciennes libs LLM (ère 2.32/2.37) restées dans jniLibs,
  • une AAR QNN Maven,

…le linker Android n'en mappe qu'une seule par SONAME. Si la version gagnante n'est pas 2.42, le backend ExecuTorch reçoit un libQnnHtp incompatible → Context group N does not exist / err 5010 sur les .pte multi-context.

Pourquoi 4B marche et 7B/8B non : un backend trop ancien gère encore le layout de contexte simple du 4B, mais pas la structure multi-context (2 groups) des modèles plus gros. La forensique avait raison de voir « 2 context groups » sur les 7B/8B — mais la cause n'est pas un overflow dans le .pte, c'est le backend de l'app qui ne sait pas les parser. Le 2.42 les parse (prouvé §2).


4. Diagnostic à faire côté dev (confirme la cause en 2 min)

Quelle version de libQnnHtp est RÉELLEMENT mappée dans le process app ?

PID=$(adb shell pidof com.kazeia)
adb shell run-as com.kazeia cat /proc/$PID/maps | grep -iE 'libQnnHtp|libqnn_executorch_backend|libQnnSystem' | awk '{print $NF}' | sort -u
# puis pour chaque .so mappé :
adb shell run-as com.kazeia strings <chemin_mappé>/libQnnHtp.so | grep -m1 AISW_VERSION   # doit être 2.42.0

Si la version mappée ≠ 2.42.0, la cause est confirmée.

Vérifier les doublons de QNN dans l'APK :

unzip -l app-release.apk | grep -iE 'libQnnHtp|libQnnSystem|libqnn'   # ne doit PAS y avoir 2 origines/versions

SHA256 attendus (libs 2.42 de ship_runtime/) — ceux livrés dans jniLibs/arm64-v8a/ DOIVENT matcher :

95d01368b556f0c6…  libqnn_executorch_backend.so
10eb1923b34ac9a7…  libQnnHtp.so
a69cfc4350c16b22…  libQnnSystem.so
a08fb34747345125…  libQnnHtpV79Stub.so
7ee72b438c97c13c…  libQnnHtpV79Skel.so
2daafb376fe6904a…  libQnnHtpPrepare.so
a3bc48674377a042…  libQnnHtpNetRunExtensions.so

5. Fix

  1. Une seule version de QNN dans l'app = 2.42 (celle de ship_runtime/), pour le STT et le LLM .pte. Concrètement :
    • Retirer de jniLibs toute libQnnHtp*.so/libQnnSystem.so qui n'est pas du build 2.42 (anciennes libs LLM, AAR Maven d'une autre version).
    • Si le STT (ORT-QNN) impose une version QNN différente, aligner les deux sur 2.42 (le STT marche sur 2.42 ; ORT-QNN EP est tolérant à la version de libQnnHtp tant qu'elle ≥ celle de compilation). À défaut, isoler (process séparé) — mais l'alignement sur 2.42 est le plus simple.
  2. Re-vérifier le /proc/pid/maps : libQnnHtp.so mappé = 2.42.0.
  3. Aucun ré-export de .pte, aucun rebuild de libkazeia_pte.so nécessaires.

6. Reproduction de la PREUVE (artefact sain)

# device, dossier avec le .pte 8B + tokenizer + ship_runtime/ 2.42 + prompt_ids.bin (uint64 LE)
ADSP_LIBRARY_PATH=. LD_LIBRARY_PATH=. ./qnn_llama_runner \
  -model_path qwen3_8b.pte -tokenizer_path tokenizer.json \
  -tokenized_prompt p8b_ids.bin -decoder_model_version qwen3 -eval_mode 1 -seq_len 512 -temperature 0
# Attendu : génère ~300 tokens à ~9-10 tok/s. PAS d'err 5010.

Le ship_runtime/ contient qnn_llama_runner + les 7 libs 2.42 : c'est l'oracle « bon backend ».


7. Données

  • .pte validés (génèrent avec 2.42) : qwen3_4b_seq1024/, qwen3_8b_seq512/, qwen2_5_7b_seq512/, kazeia-tablet-backup/llm/hybrid_llama_qnn_guard4b.pte.
  • Runtime de référence : dist/lib-pte/ (QAIRT 2.42, libQnnHtp = AISW_VERSION 2.42.0).
  • À fournir pour clore : /proc/<pid>/maps du process app pendant un load 8B + liste unzip -l des libQnn* de l'APK.