Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
08ac968
hexagon: use non-host bufs by default and make the backend fully async
max-krasnyansky Jul 17, 2026
dae8fba
hex-hb: remove optional hostbuf support and fix async copy
max-krasnyansky Jul 24, 2026
e8ce217
hex-unary: relax supported unary check
max-krasnyansky Jul 24, 2026
4369322
hex-bufs: use same get_alignment for host bufs
max-krasnyansky Jul 24, 2026
0948bbd
snapdragon: bump android_platform to 34
max-krasnyansky Jul 24, 2026
3ec10d7
hex-rows: super hacky get/set rows for q8_0
max-krasnyansky Jul 25, 2026
e36ee39
hex-get-rows: fix q8_0
max-krasnyansky Jul 25, 2026
a09e83d
hex-get-rows: supprot for f16 and cleanup for q8_0
max-krasnyansky Jul 25, 2026
72e31ae
hex-get-rows: generic macros and specialized thread funcs
max-krasnyansky Jul 26, 2026
2b3106e
hex-get-rows: add DMA pipeline, vtcm_layout and kernel params
max-krasnyansky Jul 26, 2026
b77ce3e
hex-set-rows: fix q8_0 support, add dma and tracing
max-krasnyansky Jul 26, 2026
ddeb85a
hex-tests: override nmse threshold for HTP of Q8_0 quants
max-krasnyansky Jul 26, 2026
60a2836
hex-fa: add support for Q8_0 with inplace dequantizers
max-krasnyansky Jul 26, 2026
7451872
hex-get-rows: simplify type dispatch
max-krasnyansky Jul 26, 2026
973f8c0
hex-rows: simplify GET/SET_ROWS DMA pipeline
max-krasnyansky Jul 26, 2026
9a1d7e6
hex-async: add events, set/get-tensor-async and rest of the async api…
max-krasnyansky Jul 27, 2026
48eab6d
hex-repack: use slice instead of expert in repack functions
max-krasnyansky Jul 27, 2026
3b9bca8
hex-cpy: update event/async-cpy logging
max-krasnyansky Jul 27, 2026
f123c63
hex-set-rows: optimize smaller tensors
max-krasnyansky Jul 27, 2026
a65cdbd
hex-geglu: fix perf regression with larger tensors
max-krasnyansky Jul 27, 2026
7880e34
hex-get-rows: add missing header
max-krasnyansky Jul 27, 2026
f222430
hex-set-rows: add missing header
max-krasnyansky Jul 27, 2026
7e6c159
hex-bufs: ressurect GGML_HEXAGON_HOSTBUF but disable it by default
max-krasnyansky Jul 27, 2026
f3a5ded
hexagon: do not reject ops with non-heaxon buffers
max-krasnyansky Jul 28, 2026
095bd2a
hex-get-rows: apply >=32 restriction only for q8_0
max-krasnyansky Jul 28, 2026
fa11d94
hex-res: bump vtcm acquire timeout to 10 seconds
max-krasnyansky Jul 28, 2026
d320758
hex-bufs: add support for cloning buffers between sessions to speed u…
max-krasnyansky Jul 28, 2026
4ad2c1c
hex-async: rework event recording and batch flushing and integrate wi…
max-krasnyansky Jul 28, 2026
35dcaba
hex-bufs: improved handling of repacked tensors
max-krasnyansky Jul 29, 2026
25f7ed4
hex-repack: handle get_tensor_2d offsets
max-krasnyansky Jul 29, 2026
76d2029
hex-dev: add support for devices with multiple NPUs
max-krasnyansky Jul 29, 2026
0de9b2b
hex-sync: add support for sync tokens to synchronize npu devices for …
max-krasnyansky Jul 30, 2026
fa52d01
hex-mmap: cleanup mmap calls and add a retry for robustness
max-krasnyansky Jul 31, 2026
e4c8e1a
hex-sync: add failsafe if sync wait gets stuck
max-krasnyansky Jul 31, 2026
8c2c9a8
hex-sync: use sync_seq to check for completed events
max-krasnyansky Jul 31, 2026
d7fd735
hex-sync: rotate tokens for extra robustness
max-krasnyansky Jul 31, 2026
8622255
hex-devs: add supprot for legacy device names for now
max-krasnyansky Jul 31, 2026
28965bc
hex-bufs: add support for auto-cloning buffers from diff sessions
max-krasnyansky Jul 31, 2026
59b5174
hex-fusion: simplify and optimize htp-opnode fusion handling
max-krasnyansky Jul 31, 2026
8ad6067
hex-sync: override opnode name so that it shows up in the profiles
max-krasnyansky Jul 31, 2026
5fc1762
hex-trace: update scripts to handle multiple devices
max-krasnyansky Jul 31, 2026
89b3ec1
hex-sync: bump the size of the opbatch queue and number of sync tokens
max-krasnyansky Jul 31, 2026
6b83eae
hex-cpy-sync: do not explicitly flush opbatches in cpy_tensor_async a…
max-krasnyansky Aug 1, 2026
4535b5e
hex-sync: add graph-flush threshold to avoid single op batches
max-krasnyansky Aug 1, 2026
3bdf310
hex-sync: add sync_peer so that we can flush peers we depend on durin…
max-krasnyansky Aug 1, 2026
479b446
hex-bufs: introduce tensor->extra and shadow_bufs for repacking
max-krasnyansky Aug 2, 2026
6f25c76
hex-l2: flush tiny tensors inline
max-krasnyansky Aug 2, 2026
2068d0d
hex-sync: use explicit l2flush for sync tokens
max-krasnyansky Aug 2, 2026
3ec9027
hex-extra: track weight flags via tensor extra
max-krasnyansky Aug 2, 2026
57c3b2d
hex-fence: rename sync to fence
max-krasnyansky Aug 2, 2026
2a396d3
hex-repack: proper handling of set-tensor-2d in the shadow_buf
max-krasnyansky Aug 2, 2026
4f40074
hex-trace: remove obsolete opstage mask that we used for profiling
max-krasnyansky Aug 3, 2026
f6adcac
hex-env: remove obsolete use_hmx variable
max-krasnyansky Aug 3, 2026
427e7a3
hexagon: new unified run.py and build.py and updated docs
max-krasnyansky Aug 3, 2026
a876e00
snapdragon: update run script to auto-escapt test-backend-op -p argument
max-krasnyansky Aug 3, 2026
90780a3
hex-scripts: fix trailing spaces
max-krasnyansky Aug 3, 2026
753cf71
hex-scripts: fix flake8 warnings
max-krasnyansky Aug 3, 2026
caec2aa
snapdragon: cleanup dst lib/bin dirs before copying new build
max-krasnyansky Aug 19, 2026
e19bdab
hex-ops: add support for allreduce
max-krasnyansky Aug 20, 2026
7826171
hex-ar: improved allreduce with dma pipeline
max-krasnyansky Aug 20, 2026
9c85ab3
hex-ar: align macros
max-krasnyansky Aug 20, 2026
9550d06
hex-ar: consistent use of fence_seq
max-krasnyansky Aug 21, 2026
e29d0c1
hex-ar: add AR_SELECT env var to select ALLREDUCE kernel or fallback
max-krasnyansky Aug 21, 2026
8933fb4
hex-ar: add proper synchronize handling for ALLREDUCE
max-krasnyansky Aug 21, 2026
3e693ea
hex-opbatch: looks like we now just rely on backend.synchronise to fl…
max-krasnyansky Aug 21, 2026
bc389ff
hex-ar: bump block size to improve dma efficiency
max-krasnyansky Aug 21, 2026
73da0e4
hex-ar: fused ALLREDUCE+ADD
max-krasnyansky Aug 21, 2026
6b4c8be
hex-ar: cleaner fence buffer management
max-krasnyansky Aug 21, 2026
6a04bda
hex-ar: futher allreduce tweaking to remove race conditions
max-krasnyansky Aug 22, 2026
ee07d2a
hex-ar: add simple solver and remove non-dma kernels
max-krasnyansky Aug 22, 2026
bad0496
hex-ar: add row-broadcast to fuse with bias ADD
max-krasnyansky Aug 22, 2026
70b1455
hex-fence: pass seq numbers via op_params
max-krasnyansky Aug 22, 2026
851de78
hex-ar: allow for both entry/exit seq for completing entry wait
max-krasnyansky Aug 22, 2026
8979c76
hex-ar: align macros
max-krasnyansky Aug 22, 2026
2a724e6
hex-ar: do not refetch broadcast row
max-krasnyansky Aug 22, 2026
7a9ba3b
hex-fusion: move all fusion into opbatch::add_op for consistency with…
max-krasnyansky Aug 23, 2026
5dedfdb
hex-fusion: fix incorrect MUL_MAT reordering
max-krasnyansky Aug 24, 2026
45a6dec
hex-mm: make fused 2x and 3x matmuls more generic
max-krasnyansky Aug 24, 2026
f3b8af3
hex-fusion: move tensor fusion tagging to graph_compute
max-krasnyansky Aug 24, 2026
c162cc2
hexagon: make sure to copy tensor->extra by value
max-krasnyansky Aug 24, 2026
9f1017c
hex-get-rows: fix offset calc with row-chunking
max-krasnyansky Aug 24, 2026
7a19989
hex-repack: get_tensor_2d fixes for non-zero offsets
max-krasnyansky Aug 24, 2026
740f1ba
snapdragon: make profile/trace scripts more robust and donot mix stdo…
max-krasnyansky Aug 25, 2026
203d611
hex-devices: use legacy device nameing by default to ease the transition
max-krasnyansky Aug 25, 2026
ff5e665
hex-devices: hardcode CDSP domain IDs for current devices for now
max-krasnyansky Aug 25, 2026
9fa9532
hex-optrace: improve multi-NPU timestamp alignment and overall handli…
max-krasnyansky Aug 25, 2026
6eb1a7a
hex-optrace: more robust handling of the fence events
max-krasnyansky Aug 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/backend/snapdragon/CMakeUserPresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"toolset": { "value": "host=x86_64", "strategy": "external" },
"cacheVariables": {
"ANDROID_ABI": "arm64-v8a",
"ANDROID_PLATFORM": "android-31",
"ANDROID_PLATFORM": "android-34",
"CMAKE_TOOLCHAIN_FILE": "$env{ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake",
"CMAKE_C_FLAGS": "-march=armv8.7a+fp16+dotprod+i8mm -fvectorize -ffp-model=fast -fno-finite-math-only -flto -D_GNU_SOURCE",
"CMAKE_CXX_FLAGS": "-march=armv8.7a+fp16+dotprod+i8mm -fvectorize -ffp-model=fast -fno-finite-math-only -flto -D_GNU_SOURCE",
Expand Down
212 changes: 100 additions & 112 deletions docs/backend/snapdragon/README.md

Large diffs are not rendered by default.

71 changes: 31 additions & 40 deletions docs/backend/snapdragon/developer.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,21 @@ the repacking.

## Large model handling

Hexagon NPU session (aka Process Domain (PD) in the Hexagon docs) is limited to a memory mapping of around 3.5GB.
In llama.cpp/GGML the Hexagon session is mapped to a single GGML backend device (HTP0, HTP1, etc).
Hexagon NPU sessions (aka Process Domains (PD) in the Hexagon SDK) are limited to a maximum memory mapping window of around 3.5GB.
In llama.cpp/GGML, each Hexagon session is mapped to a single GGML backend device (e.g., `HTP0:0`, `HTP0:1`, etc. when using
`GGML_HEXAGON_DEVICES`, or `HTP0`, `HTP1` in legacy mode).

In order to map models larger than 3.5GB we need to allocate multiple devices and split the model.
For this we're taking advantage of the llama.cpp/GGML multi-GPU layer-splitting support.
Each Hexagon device behaves like a GPU from the offload and model splitting perspective.
To support running models larger than 3.5GB on a single device, the Hexagon backend dynamically maps and unmaps execution buffers
during the graph execution cycle to stay within the Process Domain window. This enables large models to run successfully on a single
NPU device.

Here is an example of running GPT-OSS-20B model on a newer Snapdragon device with 16GB of DDR.
Alternatively, users can choose to use standard llama.cpp/GGML layer-splitting mode to partition and split the model across
multiple Hexagon devices or virtual sessions (which behave like multiple GPUs from the offload and splitting perspective).

Here is an example of running GPT-OSS-20B model on a Snapdragon device using 4 virtual sessions on a single NPU (physical index 0).

```
M=gpt-oss-20b-Q4_0.gguf NDEV=4 D=HTP0,HTP1,HTP2,HTP3 P=surfing.txt scripts/snapdragon/adb/run-completion.sh -f surfing.txt -n 32
...
LD_LIBRARY_PATH=/data/local/tmp/llama.cpp/lib
ADSP_LIBRARY_PATH=/data/local/tmp/llama.cpp/lib
GGML_HEXAGON_NDEV=4 ./bin/llama-cli --load-mode none -m /data/local/tmp/llama.cpp/../gguf/gpt-oss-20b-Q4_0.gguf
-t 4 --ctx-size 8192 --batch-size 128 -ctk q8_0 -ctv q8_0 -fa on -ngl 99 --device HTP0,HTP1,HTP2,HTP3 -no-cnv -f surfing.txt
~/src/llama.cpp$ ./scripts/snapdragon/run.py --target adb --devices HTP0:0,HTP0:1,HTP0:2,HTP0:3 -- llama-cli --load-mode none -m /data/local/tmp/gguf/gpt-oss-20b-Q4_0.gguf -t 4 --ctx-size 8192 --batch-size 128 -ctk q8_0 -ctv q8_0 -fa on -ngl 99 -no-cnv -f surfing.txt
...
llama_model_loader: - type f32: 289 tensors
llama_model_loader: - type q4_0: 96 tensors
Expand All @@ -63,47 +62,39 @@ llama_model_loader: - type mxfp4: 72 tensors
...
load_tensors: offloaded 25/25 layers to GPU
load_tensors: CPU model buffer size = 1182.09 MiB
load_tensors: HTP1 model buffer size = 6.64 MiB
load_tensors: HTP1-REPACK model buffer size = 2505.94 MiB
load_tensors: HTP3 model buffer size = 5.55 MiB
load_tensors: HTP3-REPACK model buffer size = 2088.28 MiB
load_tensors: HTP0 model buffer size = 7.75 MiB
load_tensors: HTP0-REPACK model buffer size = 2923.59 MiB
load_tensors: HTP2 model buffer size = 6.64 MiB
load_tensors: HTP2-REPACK model buffer size = 2505.94 MiB
load_tensors: HTP0:1 model buffer size = 2512.58 MiB
load_tensors: HTP0:3 model buffer size = 2093.83 MiB
load_tensors: HTP0:0 model buffer size = 2931.34 MiB
load_tensors: HTP0:2 model buffer size = 2512.58 MiB
...
llama_context: n_ctx_per_seq (8192) < n_ctx_train (131072) -- the full capacity of the model will not be utilized
llama_context: CPU output buffer size = 0.77 MiB
llama_kv_cache_iswa: creating non-SWA KV cache, size = 8192 cells
llama_kv_cache: HTP1 KV buffer size = 25.50 MiB
llama_kv_cache: HTP3 KV buffer size = 25.50 MiB
llama_kv_cache: HTP0 KV buffer size = 25.50 MiB
llama_kv_cache: HTP2 KV buffer size = 25.50 MiB
llama_kv_cache: HTP0:1 KV buffer size = 25.50 MiB
llama_kv_cache: HTP0:3 KV buffer size = 25.50 MiB
llama_kv_cache: HTP0:0 KV buffer size = 25.50 MiB
llama_kv_cache: HTP0:2 KV buffer size = 25.50 MiB
llama_kv_cache: size = 102.00 MiB ( 8192 cells, 12 layers, 1/1 seqs), K (q8_0): 51.00 MiB, V (q8_0): 51.00 MiB
llama_kv_cache_iswa: creating SWA KV cache, size = 256 cells
llama_kv_cache: HTP1 KV buffer size = 0.80 MiB
llama_kv_cache: HTP3 KV buffer size = 0.53 MiB
llama_kv_cache: HTP0 KV buffer size = 1.06 MiB
llama_kv_cache: HTP2 KV buffer size = 0.80 MiB
llama_kv_cache: HTP0:1 KV buffer size = 0.80 MiB
llama_kv_cache: HTP0:3 KV buffer size = 0.53 MiB
llama_kv_cache: HTP0:0 KV buffer size = 1.06 MiB
llama_kv_cache: HTP0:2 KV buffer size = 0.80 MiB
llama_kv_cache: size = 3.19 MiB ( 256 cells, 12 layers, 1/1 seqs), K (q8_0): 1.59 MiB, V (q8_0): 1.59 MiB
llama_context: HTP0 compute buffer size = 16.06 MiB
llama_context: HTP1 compute buffer size = 16.06 MiB
llama_context: HTP2 compute buffer size = 16.06 MiB
llama_context: HTP3 compute buffer size = 16.06 MiB
llama_context: HTP0:0 compute buffer size = 16.06 MiB
llama_context: HTP0:1 compute buffer size = 16.06 MiB
llama_context: HTP0:2 compute buffer size = 16.06 MiB
llama_context: HTP0:3 compute buffer size = 16.06 MiB
llama_context: CPU compute buffer size = 98.19 MiB
...
llama_perf_context_print: prompt eval time = 3843.67 ms / 197 tokens ( 19.51 ms per token, 51.25 tokens per second)
llama_perf_context_print: eval time = 1686.13 ms / 31 runs ( 54.39 ms per token, 18.39 tokens per second)
llama_perf_context_print: total time = 6266.30 ms / 228 tokens
llama_perf_context_print: graphs reused = 30
llama_memory_breakdown_print: | memory breakdown [MiB] | total free self model context compute unaccounted |
llama_memory_breakdown_print: | - HTP0 (Hexagon) | 2048 = 2048 + ( 0 = 0 + 0 + 0) + 0 |
llama_memory_breakdown_print: | - HTP1 (Hexagon) | 2048 = 2048 + ( 0 = 0 + 0 + 0) + 0 |
llama_memory_breakdown_print: | - HTP2 (Hexagon) | 2048 = 2048 + ( 0 = 0 + 0 + 0) + 0 |
llama_memory_breakdown_print: | - HTP3 (Hexagon) | 2048 = 2048 + ( 0 = 0 + 0 + 0) + 0 |
llama_memory_breakdown_print: | - HTP0:0 (Hexagon) | 2048 = 2048 + ( 0 = 0 + 0 + 0) + 0 |
llama_memory_breakdown_print: | - HTP0:1 (Hexagon) | 2048 = 2048 + ( 0 = 0 + 0 + 0) + 0 |
llama_memory_breakdown_print: | - HTP0:2 (Hexagon) | 2048 = 2048 + ( 0 = 0 + 0 + 0) + 0 |
llama_memory_breakdown_print: | - HTP0:3 (Hexagon) | 2048 = 2048 + ( 0 = 0 + 0 + 0) + 0 |
llama_memory_breakdown_print: | - Host | 1476 = 1208 + 105 + 162 |
llama_memory_breakdown_print: | - HTP1-REPACK | 2505 = 2505 + 0 + 0 |
llama_memory_breakdown_print: | - HTP3-REPACK | 2088 = 2088 + 0 + 0 |
llama_memory_breakdown_print: | - HTP0-REPACK | 2923 = 2923 + 0 + 0 |
llama_memory_breakdown_print: | - HTP2-REPACK | 2505 = 2505 + 0 + 0 |
```
69 changes: 52 additions & 17 deletions docs/backend/snapdragon/linux.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,37 @@
# Snapdragon-based Linux devices

## Docker Setup
The cross-compilation is performed using the Snapdragon Linux Docker toolchain image (see
[github.com/snapdragon-toolchain](https://github.com/snapdragon-toolchain)):

The easiest way to build llama.cpp for a Snapdragon-based Linux device is using the toolchain Docker image (see [github.com/snapdragon-toolchain](https://github.com/snapdragon-toolchain)).
This image includes OpenCL SDK, Hexagon SDK, CMake, and the ARM64 Linux cross-compilation toolchain.
* **Linux toolchain**: `ghcr.io/snapdragon-toolchain/arm64-linux:v0.7`

Cross-compilation is supported on **Linux X86** hosts. The resulting binaries are deployed to and run on the target **Qualcomm Snapdragon ARM64 Linux** device.
The unified build utility (`scripts/snapdragon/build.py`) automatically pulls
and orchestrates this container to perform target compilation. You only need to
ensure that Docker is running on your host machine.


## How to Build

### Using build.py script (Recommended)

The easiest way to build llama.cpp is by using the `scripts/snapdragon/build.py` script. It automatically copies the CMake presets,
launches the correct compilation Docker container, builds the libraries and tools,
installs them, and optionally pushes them to your target device.

Build and deploy for a Linux target (using SSH deployment alias `lnx` or `linux`):
```
~/src/llama.cpp$ docker run -it -u $(id -u):$(id -g) --volume $(pwd):/workspace --platform linux/amd64 ghcr.io/snapdragon-toolchain/arm64-linux:v0.1
[d]/> cd /workspace
$ ./scripts/snapdragon/build.py --target lnx:user@host --push
```

Note: The rest of the **Linux** build process assumes that you're running inside the toolchain container.
### Manual CMake Build

Alternatively, you can build llama.cpp manually by entering the cross-compilation Docker container and running the CMake commands:

## How to Build
```bash
# Start the cross-compilation container manually:
~/src/llama.cpp$ docker run -it --rm -u $(id -u):$(id -g) --volume $(pwd):/workspace --platform linux/amd64 ghcr.io/snapdragon-toolchain/arm64-linux:v0.7

Let's build llama.cpp with CPU, OpenCL, and Hexagon backends via CMake presets:

```
# Inside the container, build the project using presets:
[d]/workspace> cp docs/backend/snapdragon/CMakeUserPresets.json .

[d]/workspace> cmake --preset arm64-linux-snapdragon-release -B build-snapdragon
Expand All @@ -30,17 +42,19 @@ Let's build llama.cpp with CPU, OpenCL, and Hexagon backends via CMake presets:
To generate an installable "package" simply use cmake --install, then zip it:

```
[d]/workspace> cmake --install build-snapdragon --prefix pkg-snapdragon
[d]/workspace> zip -r pkg-snapdragon.zip pkg-snapdragon
[d]/workspace> cmake --install build-snapdragon --prefix pkg-linux
[d]/workspace> zip -r pkg-linux.zip pkg-linux
```

## How to Install

For this step, you will deploy the built binaries and libraries to the target Linux device. Transfer `pkg-snapdragon.zip` to the target device, then unzip it and set up the environment variables:
For this step, you will deploy the built binaries and libraries to the target
Linux device. Transfer `pkg-linux.zip` to the target device, then unzip it
and set up the environment variables:

```
$ unzip pkg-snapdragon.zip
$ cd pkg-snapdragon
$ unzip pkg-linux.zip
$ cd pkg-linux
$ export LD_LIBRARY_PATH=./lib
$ export ADSP_LIBRARY_PATH=./lib
```
Expand All @@ -52,7 +66,28 @@ $ wget https://huggingface.co/bartowski/Llama-3.2-3B-Instruct-GGUF/resolve/main/
```

## How to Run
Next, since we have setup the environment variables, we can run the llama-cli with the Hexagon backends:
You can run locally on the Snapdragon Linux device:
```
$ ./scripts/snapdragon/run.py --devices HTP0 -- llama-cli -m Llama-3.2-3B-Instruct-Q4_0.gguf -ngl 99 -p "what is the most popular cookie in the world?"
```

Or run remotely from your host development machine using the SSH target option:
```
$ ./scripts/snapdragon/run.py --target lnx:user@host --devices HTP0 -- llama-cli -m Llama-3.2-3B-Instruct-Q4_0.gguf -ngl 99 -p "what is the most popular cookie in the world?"
```

For multi-NPU systems, you can run a tensor split completion command targeting a remote Linux system:
```
$ ./scripts/snapdragon/run.py --target ubuntu:maxk@192.168.1.87 --device HTP0:0,HTP1:0 -- llama-completion -m models/gemma-2b-it-Q4_0.gguf -f prompts/sample_prompt_1024.txt --jinja -st --split-mode tensor --ctx-size 8192
```

This translates to the following command being executed remotely via SSH:
```
+ ssh maxk@192.168.1.87 "cd ~/llama.cpp && ulimit -c unlimited && LD_LIBRARY_PATH=./lib ADSP_LIBRARY_PATH=./lib GGML_HEXAGON_DEVICES=HTP0:0,HTP1:0 GGML_HEXAGON_OPPOLL=1 ./bin/llama-completion -m models/gemma-2b-it-Q4_0.gguf -f prompts/sample_prompt_1024.txt --jinja -st --split-mode tensor --ctx-size 8192 -v -n 16 --device HTP0:0,HTP1:0 -ngl 99 --ubatch-size 1024 -fa on -t 6"
```

Alternatively, you can run the binary directly on the device:
```
$ ./bin/llama-cli -m Llama-3.2-3B-Instruct-Q4_0.gguf --device HTP0 -ngl 99 -p "what is the most popular cookie in the world?"
```

28 changes: 22 additions & 6 deletions docs/backend/snapdragon/windows.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
# Snapdragon-based Windows devices

## Tool Dependencies

Native Windows 11 arm64 builds have the following tool dependencies:
- MS Visual Studio 2026 (Community Edition or Pro)
- MSVC arm64 standard and runtime libraries
- UCRT and Driver Kit
- LLVM core libraries and Clang compiler (winget)
- CMake, Git, Python (winget)
- Hexagon SDK Community Edition 6.6 or later (see below)
- OpenCL SDK 2.3 or later (see below)

Note: The rest of the **Windows** build process assumes that you're running natively in Powershell.

## Overview

The document covers procedures for installing the latest GPU and NPU drivers, and OpenCL and Hexagon SDKs.
Expand Down Expand Up @@ -53,7 +68,8 @@ Download the driver from

https://softwarecenter.qualcomm.com/catalog/item/Qualcomm_HND

After the automated installation and reboot please make sure that the Hexagon NPU device shows up in the `Device Manager` (under `Neural Processors`).
After the automated installation and reboot please make sure that the Hexagon NPU device shows up in the `Device Manager`
(under `Neural Processors`).

If the device is not available you can try installing all components (`qcnspmcdm8380`, `qcnspmcdm8380_ext`) manually.
The components are extracted into
Expand Down Expand Up @@ -130,12 +146,12 @@ However, additional settings are required for generating and signing HTP Ops lib

> cmake --preset arm64-windows-snapdragon-release -B build-wos
...
> cmake --install build-wos --prefix pkg-snapdragon
> cmake --install build-wos --prefix pkg-wos
```

Once the build is complete HTP ops libraries will be installed like this
```
> dir pkg-snapdragon/lib
> dir pkg-wos/lib
...
-a---- 1/22/2026 6:01 PM 187656 libggml-htp-v73.so
-a---- 1/22/2026 6:01 PM 191752 libggml-htp-v75.so
Expand All @@ -147,15 +163,15 @@ Once the build is complete HTP ops libraries will be installed like this
The .cat file, the signature and proper certificate installation can be verified with

```
> signtool.exe verify /v /pa .\pkg-snapdragon\lib\libggml-htp.cat
Verifying: .\pkg-snapdragon\lib\libggml-htp.cat
> signtool.exe verify /v /pa .\pkg-wos\lib\libggml-htp.cat
Verifying: .\pkg-wos\lib\libggml-htp.cat

Signature Index: 0 (Primary Signature)
Hash of file (sha256): 9820C664DA59D5EAE31DBB664127FCDAEF59CDC31502496BC567544EC2F401CF

Signing Certificate Chain:
Issued to: GGML.HTP.v1
...
Successfully verified: .\pkg-snapdragon\lib\libggml-htp.cat
Successfully verified: .\pkg-wos\lib\libggml-htp.cat
...
```
Loading
Loading