Aller au contenu
Sylvain Joffraud l4w
Retour

llama.cpp Snapdragon : le GPU Adreno génère 4× moins vite

Sur un Snapdragon X Elite, llama.cpp en OpenCL sur le GPU Adreno génère quatre fois moins vite que sur le CPU : 4-5 jetons/s contre 21 avec gemma-4-E4B. Le GPU ne gagne que 2 s sur la lecture à froid du prompt (20,1 s contre 22,1 s). Le mode hybride (lecture sur le GPU, génération sur le CPU) ne fait pas mieux que le CPU seul. J’ai donc gardé le CPU pour l’assistant du Journal des Nuisances, et cherché le gain du côté d’un modèle plus petit.

Le contexte : chercher un modèle plus rapide pour l’assistant

En mars, j’avais constaté qu’Ollama et LM Studio tournent en CPU seul sur Snapdragon, et que llama.cpp avait intégré un backend Adreno GPU via OpenCL. Voici la suite concrète : ce backend, mesuré sur une vraie charge.

La machine est pc-llm, un PC Snapdragon X Elite 64 Go (GPU Adreno X1-85). Elle sert l’assistant du Journal des Nuisances, une application de suivi de nuisances que j’ai co-fondée, avec gemma4:26b dérivé en assistant-gemma4 sur Ollama, CPU seul. La référence à battre, mesurée le 10 octobre 2026 :

ScénarioLecture du promptTotal
Première question34,8 s (27 jetons/s)35,8 s
Question suivante3,2 s7,3 s
Froid (prompt hors cache)~85 s—

Critère retenu : une lecture au moins trois fois plus rapide (≥ ~85 jetons/s), avec réutilisation du cache de préfixe du prompt sur l’accélérateur.

Pourquoi llama-server à côté d’Ollama

Ollama garde au plus deux modèles chargés (OLLAMA_MAX_LOADED_MODELS=2). Charger un candidat déchargerait l’un des deux modèles en service ; pour l’assistant, c’est 6 min 38 s avant de revenir. Et Ollama n’utilise pas l’Adreno. Les candidats tournent donc sur llama-server, le serveur HTTP de llama.cpp (build b11541), un port par backend : 8080 pour le CPU, 8081 pour OpenCL, 8082 pour Vulkan, ouverts au seul VPN.

llama.cpp publie trois archives Windows ARM64 : llama-b11541-bin-win-cpu-arm64.zip, llama-b11541-bin-win-opencl-adreno-arm64.zip et llama-b11541-bin-win-vulkan-arm64.zip. Pas de version précompilée du backend Hexagon pour le NPU (45 TOPS qui restent inutilisés) : il faudra le compiler, pour des modèles de moins de 4 milliards de paramètres.

⚠️ Au premier essai, le GPU était bloqué par Smart App Control, le filtrage d’applications de Windows 11. Je l’ai désactivé sur cette machine, isolée sur le VPN ; llama.cpp OpenCL a alors vu l’Adreno X1-85.

# tout sur le GPU ; -ngl 0 pour le mode hybride, binaire CPU pour le processeur
C:\llama-assistant\bin\opencl\llama-server.exe `
  -m C:\llama-assistant\modeles\gemma-4-E4B_q4_0-it.gguf `
  --host 10.66.0.20 --port 8081 -c 8192 -np 1 --jinja -ngl 99 --swa-full

--swa-full est indispensable avec Gemma 4 : ses couches à fenêtre glissante empêchent sinon llama.cpp de réutiliser le préfixe. Chaque requête porte aussi "cache_prompt": true.

Le GPU Adreno est-il plus rapide que le CPU avec llama.cpp ?

Mesures sur gemma-4-E4B (Q4_0), vrai prompt de l’assistant avec le contexte d’un journal de démonstration de 45 incidents, deux passages par mode :

ModeLecture à froid (3 499 jetons)Génération1ʳᵉ questionQuestion suivante
Processeur (binaire CPU)22,1 s21 jetons/s10,7 s6,5 s
Tout sur le GPU (OpenCL, -ngl 99)20,1 s4-5 jetons/s15,9-24,4 s18,3 s
Hybride (OpenCL, -ngl 0)19,7 s21 jetons/s9,0-9,2 s4,0-4,8 s

Le mode hybride lance le binaire OpenCL sans couche sur le GPU : les poids et la génération restent sur le CPU, et llama.cpp confie au GPU les gros calculs de lecture du prompt (op offload). Il gagne 2,4 s sur la lecture à froid (19,7 s contre 22,1 s), une fois par journal. La lecture d’une question et la génération sont identiques au CPU ; les écarts de total viennent de la longueur des réponses.

Sur Snapdragon X Elite, l’Adreno en OpenCL accélère à peine la lecture du prompt et divise la génération par quatre : le CPU reste le bon choix.

Six petits modèles mesurés sur le CPU

Le gain est donc venu d’un modèle plus petit. Six bases denses sous licence Apache 2.0, mesurées le 10 octobre sur le CPU (réflexion désactivée, même prompt) :

CandidatFroid1ʳᵉ questionSuivanteGénérationVerdict
gemma-4-E2B13,0 s5,0 s1,5 s40 jetons/sbrève, à côté, n’invente rien
gemma-4-E4B24,3 s10,7 s6,5 s21 jetons/sla plus pertinente
qwen3-4B-250742,9 s23,1 s28,9 s9-13 jetons/strop lent à générer
smollm3-3B15,9 s8,7 s14,2 s14-23 jetons/sinvente des faits
luciole-1B11,4 s10,2 s16,7 s22-34 jetons/sinvente des faits
ministral-3-3B30,1 s22,0 s33,2 s7-13 jetons/sinvente des faits

Restent les deux Gemma 4 : E2B, 6 à 7 fois plus rapide que la référence, et E4B, 3 fois plus rapide.

Deux pièges de requête en chemin. Sans "chat_template_kwargs": {"enable_thinking": false}, Gemma 4 passait ses 400 jetons à réfléchir et la réponse arrivait vide. Et le gabarit de conversation de Ministral 3 refuse un second message system : il faut fusionner le socle et le contexte en un seul, dans le même ordre pour garder le préfixe.

Lessons learned

Questions fréquentes

llama.cpp utilise-t-il le GPU Adreno sur Windows ARM64 ?
Oui, avec la version OpenCL publiée pour Windows ARM64 (archive llama-b11541-bin-win-opencl-adreno-arm64.zip pour le build b11541). Ollama, lui, n’utilise pas l’Adreno. Sur un Snapdragon X Elite, le GPU n’était visible qu’après la désactivation de Smart App Control, qui le bloquait. Une fois actif, il s’est montré plus lent que le CPU pour la génération de texte.
Qu’est-ce que le mode hybride de llama.cpp avec OpenCL ?
Le mode hybride consiste à lancer le binaire OpenCL de llama.cpp avec -ngl 0 : aucune couche n’est placée sur le GPU, les poids et la génération restent sur le CPU, et llama.cpp confie au GPU les gros calculs de lecture du prompt (op offload). Sur un Snapdragon X Elite avec gemma-4-E4B, ce mode a donné la même vitesse que le CPU seul, à deux secondes près sur la lecture à froid (19,7 s contre 22,1 s).
Pourquoi Gemma 4 renvoie-t-il une réponse vide avec llama-server ?
Gemma 4 raisonne avant de répondre. Avec un max_tokens de 400, il passait tout son budget à réfléchir, et la réponse visible arrivait vide. La parade côté requête llama-server : "chat_template_kwargs": {"enable_thinking": false}, l’équivalent de think: false côté Ollama. La réflexion se désactive par le gabarit de conversation du modèle, pas par une option du serveur.
Peut-on utiliser le NPU Hexagon avec llama.cpp sur Windows ?
llama.cpp a un backend Hexagon pour le NPU des Snapdragon, mais ne publie pas de version Windows précompilée de ce backend, contrairement aux versions CPU, OpenCL Adreno et Vulkan. Il faut donc compiler llama.cpp soi-même. La limite mémoire de ce backend le réserve aux modèles de moins de 4 milliards de paramètres environ.

Partager cet article :

Article précédent
`navigator.share` après un PDF : `NotAllowedError`
Article suivant
BCMath : `bcmul` tronque, il n’arrondit pas