Skip to content

metal: implement DSv4 Lightning Indexer - #25893

Merged
ggerganov merged 6 commits into
ggml-org:masterfrom
tarruda:dsv4-metal-lightning-indexer
Aug 3, 2026
Merged

metal: implement DSv4 Lightning Indexer#25893
ggerganov merged 6 commits into
ggml-org:masterfrom
tarruda:dsv4-metal-lightning-indexer

Conversation

@tarruda

@tarruda tarruda commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Overview

Metal backend for GGML_OP_LIGHTNING_INDEXER

Additional information

This is the first of a series of changes that target improving DSv4 performance on Apple Silicon. I extracted this commit from my dsv4-improvements branch, which includes metal backends for hyper-connections and a few other improvements.

On master branch, these are some performance numbers of DSv4 on my M1 Ultra (llama-bench --mmap 1, -fa 1, -p 512, -n 128; d=0/10k/20k/30k, benchmarking this quant):

  • pp512: 153.73 ± 0.87 t/s
  • tg128: 8.91 ± 0.04 t/s
  • pp512 @ d10000: 73.90 ± 0.39 t/s
  • tg128 @ d10000: 8.66 ± 0.03 t/s
  • pp512 @ d20000: 45.83 ± 0.18 t/s
  • tg128 @ d20000: 8.26 ± 0.03 t/s
  • pp512 @ d30000: 33.40 ± 0.21 t/s
  • tg128 @ d30000: 7.94 ± 0.01 t/s

With this commit, things improve slightly:

  • pp512: 155.19 ± 0.91 t/s
  • tg128: 8.95 ± 0.04 t/s
  • pp512 @ d10000: 86.95 ± 0.69 t/s
  • tg128 @ d10000: 9.00 ± 0.05 t/s
  • pp512 @ d20000: 62.01 ± 0.45 t/s
  • tg128 @ d20000: 8.68 ± 0.04 t/s
  • pp512 @ d30000: 49.18 ± 0.33 t/s
  • tg128 @ d30000: 8.60 ± 0.02 t/s

With all commits from my branch, this is what it looks like:

  • pp512: 168.67 ± 0.82 t/s
  • tg128: 23.59 ± 0.06 t/s
  • pp512 @ d10000: 151.10 ± 0.55 t/s
  • tg128 @ d10000: 20.87 ± 0.13 t/s
  • pp512 @ d20000: 145.98 ± 0.45 t/s
  • tg128 @ d20000: 20.68 ± 0.13 t/s
  • pp512 @ d30000: 141.91 ± 0.29 t/s
  • tg128 @ d30000: 20.56 ± 0.06 t/s

Requirements

  • I have read and agree with the contributing guidelines
  • AI usage disclosure: Yes, this is 100% generated by GPT 5.6 Sol. I have reviewed and tested the changes, but I am not a Metal kernel developer and thus cannot judge the quality of these changes. Hopefully the maintainers can extract something as the compounded performance improvements can make DSv4 flash very usable with a local coding harness. CC @ggerganov @fairydreaming

- Implement GGML_OP_LIGHTNING_INDEXER for 128-dimensional, 64-head inputs
  with F32 queries and weights plus F16 keys and masks.
- Add tiled and tail kernels and test KV lengths around 8- and 64-element
  boundaries.

llama-bench (--mmap 1, -fa 1, -p 512, -n 128; d=0/10k/20k/30k):

Before:
- pp512: 153.73 ± 0.87 t/s
- tg128: 8.91 ± 0.04 t/s
- pp512 @ d10000: 73.90 ± 0.39 t/s
- tg128 @ d10000: 8.66 ± 0.03 t/s
- pp512 @ d20000: 45.83 ± 0.18 t/s
- tg128 @ d20000: 8.26 ± 0.03 t/s
- pp512 @ d30000: 33.40 ± 0.21 t/s
- tg128 @ d30000: 7.94 ± 0.01 t/s

After:
- pp512: 155.19 ± 0.91 t/s
- tg128: 8.95 ± 0.04 t/s
- pp512 @ d10000: 86.95 ± 0.69 t/s
- tg128 @ d10000: 9.00 ± 0.05 t/s
- pp512 @ d20000: 62.01 ± 0.45 t/s
- tg128 @ d20000: 8.68 ± 0.04 t/s
- pp512 @ d30000: 49.18 ± 0.33 t/s
- tg128 @ d30000: 8.60 ± 0.02 t/s

Assisted-by: Codex
@github-actions github-actions Bot added testing Everything test related ggml changes relating to the ggml tensor library for machine learning Apple Metal https://en.wikipedia.org/wiki/Metal_(API) labels Jul 19, 2026
@am17an

am17an commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

@ggml-org/ggml-metal can someone review?

@am17an am17an mentioned this pull request Aug 1, 2026
13 tasks
@ggerganov ggerganov self-assigned this Aug 1, 2026
@tarruda

tarruda commented Aug 1, 2026

Copy link
Copy Markdown
Contributor Author

Since creating this, I've pushed GPT 5.6 Sol to add more optimizations to my dsv4-improvements branch.

These are the latest numbers of DSv4 on my M1 ultra:

% ./build/bin/llama-bench -m ~/ds4flash/DeepSeek-V4-Flash-IQ3_XXS-00001-of-00004.gguf -fa 1 -d 0,10000,20000,30000,40000,50000,60000,70000,80000,90000,100000,150000,200000,250000,300000,350000,400000,500000 -n 128 -p 2048 -b 2048 -ub 2048         
| model                          |       size |     params | backend    | threads | n_ubatch |  fa |            test |                  t/s |
| ------------------------------ | ---------: | ---------: | ---------- | ------: | -------: | --: | --------------: | -------------------: |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 |          pp2048 |        227.27 ± 0.66 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 |           tg128 |         22.86 ± 0.03 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | pp2048 @ d10000 |        215.96 ± 0.80 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 |  tg128 @ d10000 |         20.34 ± 0.06 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | pp2048 @ d20000 |        208.53 ± 0.84 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 |  tg128 @ d20000 |         20.04 ± 0.08 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | pp2048 @ d30000 |        202.02 ± 0.68 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 |  tg128 @ d30000 |         19.84 ± 0.06 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | pp2048 @ d40000 |        194.44 ± 0.48 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 |  tg128 @ d40000 |         19.70 ± 0.07 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | pp2048 @ d50000 |        188.00 ± 0.37 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 |  tg128 @ d50000 |         19.34 ± 0.01 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | pp2048 @ d60000 |        182.78 ± 0.41 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 |  tg128 @ d60000 |         19.16 ± 0.08 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | pp2048 @ d70000 |        177.57 ± 0.38 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 |  tg128 @ d70000 |         19.03 ± 0.05 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | pp2048 @ d80000 |        172.32 ± 0.33 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 |  tg128 @ d80000 |         18.91 ± 0.05 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | pp2048 @ d90000 |        167.00 ± 0.23 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 |  tg128 @ d90000 |         18.58 ± 0.10 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | pp2048 @ d100000 |        162.51 ± 0.45 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | tg128 @ d100000 |         18.45 ± 0.08 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | pp2048 @ d150000 |        142.93 ± 0.47 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | tg128 @ d150000 |         17.86 ± 0.05 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | pp2048 @ d200000 |        127.57 ± 0.26 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | tg128 @ d200000 |         17.03 ± 0.05 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | pp2048 @ d250000 |        115.05 ± 0.29 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | tg128 @ d250000 |         16.13 ± 0.09 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | pp2048 @ d300000 |        104.85 ± 0.21 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | tg128 @ d300000 |         15.58 ± 0.07 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | pp2048 @ d350000 |         96.51 ± 0.25 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | tg128 @ d350000 |         15.15 ± 0.12 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | pp2048 @ d400000 |         88.52 ± 0.09 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | tg128 @ d400000 |         14.84 ± 0.18 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | pp2048 @ d500000 |         76.15 ± 1.24 |
| deepseek4 ?B Q8_0              | 106.05 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | tg128 @ d500000 |         13.75 ± 0.13 |

In my tests, it is working better than antirez DS4 llama.cpp fork.

Besides the extra optimizations, using -ub 2048 and -b 2048 greatly improved prompt processing and the model is now 100% usable with the slow GPU (compared to nvidias) of the M1 ultra and a coding harness (and these are the best numbers I can get out of any 100B+ model with 500k prefill).

Besides the metal lightning indexer commit in this PR, there are about 10 commits. I can push them all together in a single PR, create stacked PRs or individual PRs (whatever is best for maintainers to review).

@am17an

am17an commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

@tarruda I think you can use MTP (#25784) and see how that goes

@tarruda

tarruda commented Aug 1, 2026

Copy link
Copy Markdown
Contributor Author

@am17an thanks I will try re-converting it later. if anyone wants to try the new 0731 gguf, I'm currently uploading IQ3_XXS with the 0731 template already embedded (and without MTP) here: https://huggingface.co/tarruda/DeepSeek-V4-Flash-0731-GGUF. IQ3_XXS seems to be the sweet spot for 128G

@forforever73

Copy link
Copy Markdown
Contributor

@tarruda Thanks for the contribution — this is a nice improvement.

A couple of comments.

kernel_lightning_indexer_f16_tail is currently the only _tail kernel in ggml-metal.metal. The main kernel uses the SIMD-group matrix units and rounds Q to FP16, while the tail kernel falls back to simd_sum(dot(...)) and keeps Q in FP32. Both are within tolerance, but having the numerics depend on which KV segment a key happens to land in isn't something we'd want to carry.

I'd rather handle the tail the same way we already do in kernel_flash_attn_ext_pad and FC_flash_attn_ext_has_kvpad: stage the last chunk, then run the same kernel over it.

I'd also rather not make this FP16-only. DSv4 is intended for very long contexts, where a quantized K cache is likely to be the configuration people will want to run.

The only thing preventing both is

simdgroup_load(mk[i], (device const half *) k_base + 8*i, ...)

simdgroup_half8x8 can only be loaded from FP16-formatted memory, so any non-FP16 K has to go through

device → dequantize → threadgroup (FP16) → simdgroup_load

That's already what the flash-attention quantized-K path does. The dequantization helpers already exist with a uniform interface, and kernel instantiation already follows the kernel_flash_attn_ext<...> pattern.

Once K is staged, the tail case becomes what CUDA already does in lightning-indexer.cu:

// staging
if (i_kv + r < args.n_kv) { /* load + dequantize K row */ } else { /* zero-fill */ }

// store
if (ik < args.n_kv) out[ik] = score + float(mask[ik]);

Zero-filling K naturally gives dot == 0, so ReLU(0) == 0 and the padded rows contribute nothing.

That lets us drop the tail kernel, support quantized K as well, and simplify ggml_metal_op_lightning_indexer quite a bit.

tarruda added 2 commits August 2, 2026 06:42
- Stage and dequantize K in F16 threadgroup memory before simdgroup matrix loads.
- Zero-fill partial tiles and guard stores so all KV segments use the same numerical path.
- Support F32, F16, BF16, Q4_0, Q4_1, Q5_0, Q5_1, and Q8_0 K caches.

llama-bench (--mmap 1, -fa on, -p 512, -n 128; d=0/10k/20k):

- pp512: 160.38 +/- 1.01 t/s
- tg128: 9.08 +/- 0.03 t/s
- pp512 @ d10000: 88.37 +/- 0.46 t/s
- tg128 @ d10000: 9.07 +/- 0.04 t/s
- pp512 @ d20000: 62.53 +/- 0.46 t/s
- tg128 @ d20000: 8.84 +/- 0.03 t/s

Assisted-by: Codex
@tarruda

tarruda commented Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

@forforever73 merged master branch and pushed a new commit. In the interest of full disclosure, I'd like to reinforce that I don't know what I'm doing and all I did was forward your comment to GPT 5.6 Sol.

I'm happy to keep using my codex subscription on this, but my blessing goes to you or anyone else that wants to create a new PR with this code cleaned up, improved or rewritten. This also applies to my dsv4-improvements branch. I'm happy as long as we end up getting good performance improvements on DSv4 inference.

@forforever73

Copy link
Copy Markdown
Contributor

@tarruda Thanks for being so open about it :) At the end of the day we're all after the same thing: getting the best possible DSv4 performance.

From a quick look, 5.6 Sol seems to have captured the direction I was suggesting. I'll probably just make a few changes directly on top of your branch to keep things moving.

@am17an

am17an commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

BTW, on top of this the HC ops probably seem to provide the most benefit for TG. Those should be a quick merge

@tarruda

tarruda commented Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

BTW, on top of this the HC ops probably seem to provide the most benefit for TG. Those should be a quick merge

Most commit messages in my branch contain llama-bench measurements for the change.

And yes, HC greatly improve token generation: 6ed571d

Another great improvement is in the sparse attention commits which follow, making prompt processing more stable with longer prefills: 551afb9

@ggerganov

Copy link
Copy Markdown
Member

@forforever73 Yes, feel free to move forward - I haven't gotten around to setup DSv4 in my environment yet, so any help with this is appreciated.

@tarruda

tarruda commented Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

@am17an when doing this I asked codex to split optimizations into common/metal commits. Can you see if these two are useful for other backends?

@am17an

am17an commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

The first one is similar to #25917, though I am not sure if that will be merged soon. The second commit also looks like a bit along the same lines.

@ggerganov

Copy link
Copy Markdown
Member

And yes, HC greatly improve token generation: 6ed571d

@tarruda Is there a PR with this commit? If not, I'll make one.

@tarruda

tarruda commented Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

@ggerganov no, I was going to open PRs in the same order of the commits as needed, but feel free to take anything out of that branch and create PRs yourself

@ggerganov

Copy link
Copy Markdown
Member

@ggerganov no, I was going to open PRs in the same order of the commits as needed, but feel free to take anything out of that branch and create PRs yourself

Ok, I'll fast-track that specific commit: #26459

@tarruda

tarruda commented Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @ggerganov, let me know if I can do anything else to assist.

@ggerganov

ggerganov commented Aug 2, 2026

Copy link
Copy Markdown
Member

Thanks @ggerganov, let me know if I can do anything else to assist.

Ok, let's wait for @forforever73 to update this branch and we can continue with the rest of the changes from your branch after merging the lightning indexer.

Assisted-by: Codex

# Conflicts:
#	ggml/src/ggml-metal/ggml-metal-device.cpp
#	ggml/src/ggml-metal/ggml-metal-device.h
#	ggml/src/ggml-metal/ggml-metal-device.m
#	ggml/src/ggml-metal/ggml-metal-impl.h
#	ggml/src/ggml-metal/ggml-metal-ops.cpp
#	ggml/src/ggml-metal/ggml-metal-ops.h
#	ggml/src/ggml-metal/ggml-metal.metal
@tarruda

tarruda commented Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

Ok, let's wait for @forforever73 to update this branch and we can continue with the rest of the changes from your branch after merging the lightning indexer.

Ok just pushed a merge commit with conflicts fixed for @forforever73

@forforever73

Copy link
Copy Markdown
Contributor

Test on my m4 max, it takes a long time

model size params backend threads n_ubatch fa test t/s
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 pp2048 301.51 ± 0.43
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 tg128 10.42 ± 0.08
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 pp2048 @ d10000 238.83 ± 0.62
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 tg128 @ d10000 10.36 ± 0.12
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 pp2048 @ d20000 200.27 ± 0.49
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 tg128 @ d20000 10.05 ± 0.09
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 pp2048 @ d30000 175.17 ± 0.34
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 tg128 @ d30000 9.94 ± 0.08
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 pp2048 @ d40000 157.00 ± 0.17
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 tg128 @ d40000 9.74 ± 0.06
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 pp2048 @ d50000 145.22 ± 0.26
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 tg128 @ d50000 9.78 ± 0.04
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 pp2048 @ d60000 134.40 ± 0.90
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 tg128 @ d60000 9.62 ± 0.07
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 pp2048 @ d70000 122.22 ± 0.19
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 tg128 @ d70000 9.46 ± 0.02
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 pp2048 @ d80000 116.79 ± 0.40
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 tg128 @ d80000 9.49 ± 0.08
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 pp2048 @ d90000 110.13 ± 0.27
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 tg128 @ d90000 9.22 ± 0.12
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 pp2048 @ d100000 105.51 ± 0.38
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 tg128 @ d100000 9.33 ± 0.05
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 pp2048 @ d150000 84.06 ± 0.17
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 tg128 @ d150000 8.87 ± 0.02
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 pp2048 @ d200000 76.97 ± 0.25
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 tg128 @ d200000 8.64 ± 0.11
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 pp2048 @ d250000 67.13 ± 0.27
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 tg128 @ d250000 8.23 ± 0.05
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 pp2048 @ d300000 62.43 ± 0.20
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 tg128 @ d300000 7.86 ± 0.04
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 pp2048 @ d350000 57.74 ± 0.22
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 tg128 @ d350000 7.69 ± 0.12
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 pp2048 @ d400000 52.09 ± 0.39
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 tg128 @ d400000 7.34 ± 0.07
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 pp2048 @ d500000 46.93 ± 0.15
deepseek4 IQ2_XXS - 2.0625 bpw 84.62 GiB 284.33 B MTL,BLAS 12 2048 1 tg128 @ d500000 6.73 ± 0.03

@forforever73
forforever73 marked this pull request as ready for review August 3, 2026 01:36
@forforever73
forforever73 requested a review from a team as a code owner August 3, 2026 01:36
@tarruda

tarruda commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

@forforever73 I think you started the test before the hyper-connections kernel was merged back into this PR (thus the 10 tps generation).

The pp2048 will greatly improve at longer context once sparse attention commits are added.

@forforever73

Copy link
Copy Markdown
Contributor

@tarruda Yes, exactly. So I think the current results are expected.

@forforever73 forforever73 added the merge ready A maintainer can use this label to indicate that they consider the changes final and ready to merge. label Aug 3, 2026
Comment thread ggml/src/ggml-metal/ggml-metal-ops.cpp
@ggerganov

Copy link
Copy Markdown
Member

Some quick numbers on M2 Ultra with https://huggingface.co/ggml-org/DeepSeek-V4-Flash-0731-GGUF:

| model                          |       size |     params | backend    | threads | n_ubatch |  fa |            test |                  t/s |
| ------------------------------ | ---------: | ---------: | ---------- | ------: | -------: | --: | --------------: | -------------------: |
| deepseek4 ?B MXFP4 MoE         | 144.34 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 |          pp2048 |        408.93 ± 0.49 |
| deepseek4 ?B MXFP4 MoE         | 144.34 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 |           tg128 |         27.60 ± 0.03 |
| deepseek4 ?B MXFP4 MoE         | 144.34 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | pp2048 @ d10000 |        212.07 ± 0.32 |
| deepseek4 ?B MXFP4 MoE         | 144.34 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 |  tg128 @ d10000 |         25.19 ± 0.20 |
| deepseek4 ?B MXFP4 MoE         | 144.34 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | pp2048 @ d20000 |        142.17 ± 0.13 |
| deepseek4 ?B MXFP4 MoE         | 144.34 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 |  tg128 @ d20000 |         23.44 ± 0.08 |
| deepseek4 ?B MXFP4 MoE         | 144.34 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 | pp2048 @ d30000 |        106.94 ± 0.08 |
| deepseek4 ?B MXFP4 MoE         | 144.34 GiB |   284.33 B | MTL,BLAS   |      16 |     2048 |   1 |  tg128 @ d30000 |         22.35 ± 0.01 |

@ggerganov
ggerganov merged commit 1464c62 into ggml-org:master Aug 3, 2026
1 check passed
@tarruda
tarruda deleted the dsv4-metal-lightning-indexer branch August 3, 2026 08:56
@tarruda

tarruda commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

@ggerganov these numbers are more than double the pp2048 I get with an M1 ultra. Can you share the llama-bench command you used? Curious if I missed some flags or if the M2 is that much better than the M1.

@ggerganov

Copy link
Copy Markdown
Member

I'm using your command from earlier:

sudo sysctl iogpu.wired_limit_mb=180000

make -j && bin/llama-bench -hf ggml-org/DeepSeek-V4-Flash-0731-GGUF -fa 1 -d 0,10000,20000,30000,40000,50000,60000,70000,80000,90000,100000,150000,200000,250000,300000,350000,400000,500000 -n 128 -p 2048 -b 2048 -ub 2048

Do you have this patch: #26465

@tarruda

tarruda commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

Yea I did. I guess it is just that the M1 GPU is significantly weaker than the M2.

BTW, I think the next best picks from my branch are the sparse attention ones which keep prompt processing more stable as context grows. Do you want me to open a new PR or want to pick the changes yourself?

@ggerganov

Copy link
Copy Markdown
Member

Do you want me to open a new PR or want to pick the changes yourself?

Yes, go ahead and open - I'll take a look.

@tarruda

tarruda commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

#26512

@JamePeng

JamePeng commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Hi @tarruda, this PR will cause the github action M1 Virtual Machine raise a error:

ggml_metal_library_init: error: Error Domain=MTLLibraryErrorDomain Code=3 "program_source:14536:27: error: no matching constructor for initialization of 'threadgroup metal::half4x4[512]' (aka 'threadgroup matrix<half, 4, 4>[512]')
    threadgroup half4x4   sk4x4[NK*DK16];
image

@tarruda

tarruda commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

@JamePeng do you know how I can run this test locally? Seems like it is causing an issue on unrelated model n_ctx_seq(256) < n_ctx_train(32768)

@ggerganov

Copy link
Copy Markdown
Member

It seems the paravirtual device does not allow to allocate half4x4 in the threadgroup memory.

I think you need to reserve the threadgroup memory in host-side using ggml_metal_encoder_set_threadgroup_memory_size and in the kernel implementation only use a pointer (similar to how we do in the rest of the metal kernels, for example flash_attn).

@tarruda

tarruda commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

@ggerganov I'm going to open a PR, but how can we validate the fix before merging? Was this not caught in the PR CI?

@ggerganov

ggerganov commented Aug 3, 2026

Copy link
Copy Markdown
Member

Our M1 virtual runners announce that simdgroup matrix multiplication is not supported, so the CI filters out those tests as unsupported:

https://github.com/ggml-org/llama.cpp/actions/runs/30784775242/job/91596148481#step:5:20121

Not sure how @JamePeng runs this.

@JamePeng

JamePeng commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Our M1 virtual runners announce that simdgroup matrix multiplication is not supported, so the CI filters out those tests as unsupported:

https://github.com/ggml-org/llama.cpp/actions/runs/30784775242/job/91596148481#step:5:20121

Not sure how @JamePeng runs this.

Simply loading the Qwen2.5-0.5B model and conducting some grammar tests.

@JamePeng

JamePeng commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

I submitted a fix #26646 , and it worked.

satindergrewal pushed a commit to satindergrewal/llama.cpp that referenced this pull request Aug 12, 2026
* metal: implement F16 Lightning Indexer

- Implement GGML_OP_LIGHTNING_INDEXER for 128-dimensional, 64-head inputs
  with F32 queries and weights plus F16 keys and masks.
- Add tiled and tail kernels and test KV lengths around 8- and 64-element
  boundaries.

llama-bench (--mmap 1, -fa 1, -p 512, -n 128; d=0/10k/20k/30k):

Before:
- pp512: 153.73 ± 0.87 t/s
- tg128: 8.91 ± 0.04 t/s
- pp512 @ d10000: 73.90 ± 0.39 t/s
- tg128 @ d10000: 8.66 ± 0.03 t/s
- pp512 @ d20000: 45.83 ± 0.18 t/s
- tg128 @ d20000: 8.26 ± 0.03 t/s
- pp512 @ d30000: 33.40 ± 0.21 t/s
- tg128 @ d30000: 7.94 ± 0.01 t/s

After:
- pp512: 155.19 ± 0.91 t/s
- tg128: 8.95 ± 0.04 t/s
- pp512 @ d10000: 86.95 ± 0.69 t/s
- tg128 @ d10000: 9.00 ± 0.05 t/s
- pp512 @ d20000: 62.01 ± 0.45 t/s
- tg128 @ d20000: 8.68 ± 0.04 t/s
- pp512 @ d30000: 49.18 ± 0.33 t/s
- tg128 @ d30000: 8.60 ± 0.02 t/s

Assisted-by: Codex

* metal: stage Lightning Indexer K tiles

- Stage and dequantize K in F16 threadgroup memory before simdgroup matrix loads.
- Zero-fill partial tiles and guard stores so all KV segments use the same numerical path.
- Support F32, F16, BF16, Q4_0, Q4_1, Q5_0, Q5_1, and Q8_0 K caches.

llama-bench (--mmap 1, -fa on, -p 512, -n 128; d=0/10k/20k):

- pp512: 160.38 +/- 1.01 t/s
- tg128: 9.08 +/- 0.03 t/s
- pp512 @ d10000: 88.37 +/- 0.46 t/s
- tg128 @ d10000: 9.07 +/- 0.04 t/s
- pp512 @ d20000: 62.53 +/- 0.46 t/s
- tg128 @ d20000: 8.84 +/- 0.03 t/s

Assisted-by: Codex

* dedup Lightning Indexer constants, fix flaky test

* cont : fix whitespace

---------

Co-authored-by: forforever73 <690105611@qq.com>
Co-authored-by: Georgi Gerganov <ggerganov@gmail.com>
brittlewis12 pushed a commit to brittlewis12/llama.cpp that referenced this pull request Aug 17, 2026
* metal: implement F16 Lightning Indexer

- Implement GGML_OP_LIGHTNING_INDEXER for 128-dimensional, 64-head inputs
  with F32 queries and weights plus F16 keys and masks.
- Add tiled and tail kernels and test KV lengths around 8- and 64-element
  boundaries.

llama-bench (--mmap 1, -fa 1, -p 512, -n 128; d=0/10k/20k/30k):

Before:
- pp512: 153.73 ± 0.87 t/s
- tg128: 8.91 ± 0.04 t/s
- pp512 @ d10000: 73.90 ± 0.39 t/s
- tg128 @ d10000: 8.66 ± 0.03 t/s
- pp512 @ d20000: 45.83 ± 0.18 t/s
- tg128 @ d20000: 8.26 ± 0.03 t/s
- pp512 @ d30000: 33.40 ± 0.21 t/s
- tg128 @ d30000: 7.94 ± 0.01 t/s

After:
- pp512: 155.19 ± 0.91 t/s
- tg128: 8.95 ± 0.04 t/s
- pp512 @ d10000: 86.95 ± 0.69 t/s
- tg128 @ d10000: 9.00 ± 0.05 t/s
- pp512 @ d20000: 62.01 ± 0.45 t/s
- tg128 @ d20000: 8.68 ± 0.04 t/s
- pp512 @ d30000: 49.18 ± 0.33 t/s
- tg128 @ d30000: 8.60 ± 0.02 t/s

Assisted-by: Codex

* metal: stage Lightning Indexer K tiles

- Stage and dequantize K in F16 threadgroup memory before simdgroup matrix loads.
- Zero-fill partial tiles and guard stores so all KV segments use the same numerical path.
- Support F32, F16, BF16, Q4_0, Q4_1, Q5_0, Q5_1, and Q8_0 K caches.

llama-bench (--mmap 1, -fa on, -p 512, -n 128; d=0/10k/20k):

- pp512: 160.38 +/- 1.01 t/s
- tg128: 9.08 +/- 0.03 t/s
- pp512 @ d10000: 88.37 +/- 0.46 t/s
- tg128 @ d10000: 9.07 +/- 0.04 t/s
- pp512 @ d20000: 62.53 +/- 0.46 t/s
- tg128 @ d20000: 8.84 +/- 0.03 t/s

Assisted-by: Codex

* dedup Lightning Indexer constants, fix flaky test

* cont : fix whitespace

---------

Co-authored-by: forforever73 <690105611@qq.com>
Co-authored-by: Georgi Gerganov <ggerganov@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Apple Metal https://en.wikipedia.org/wiki/Metal_(API) ggml changes relating to the ggml tensor library for machine learning merge ready A maintainer can use this label to indicate that they consider the changes final and ready to merge. testing Everything test related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants