You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 7a219c6
Browse filesBrowse the repository at this point in the historyBrowse files
| Is it as fast on the **Apple GPU** with long context? |**Writing, yes; the first token, nearly.** From 4k to 32k Synapse writes 92–148 tokens/s, level with llama.cpp (93–141); MLX falls to 60 at 32k. The first token takes 1.04× llama.cpp's time at 32k and 1.5× at 4k; MLX is 1.6–1.8× faster to the first token. |
48
50
| Does it use less memory with long context? |**Less than llama.cpp when the window is large, 25× less than MLX.** At 32k: 534 MiB peak against 535 (llama.cpp) and 13,500 (MLX). With a 131k window and a 4k prompt: 234 MiB against 1,645, because Synapse's KV cache grows with use. |
49
51
| Is a second question about the same long document fast? |**Yes, with prefix reuse.** A second question about a 30,000-token document starts answering in 0.13 s instead of 23.8 s, with the same answer. |
52
+
| Does it run a 7B model on the Apple GPU? |**Yes.** Qwen2.5-7B-Instruct-1M Q8_0 writes llama.cpp's exact text at the same decode speed (17.5 tokens/s). The first token of a 3,528-token prompt is 1.5× slower (17–19 s against 11.5 s). |
53
+
| Does a Q4_K_M model run, and how small is it? |**Yes.** Qwen2.5-7B-Instruct-1M Q4_K_M peaks at 4.2 GB in Synapse, against 4.8 GB in llama.cpp and 7.2 GB for Q8_0, and writes llama.cpp's text. Its decode is 0.64× llama.cpp's (18 against 28 tokens/s). |
54
+
| Does the model have to be loaded whole? |**No.** A dropped layer's weights and KV are never loaded; each of the 7B's layers is about 240 MiB. Only 2 of its 28 layers are free to drop (−1.1% perplexity), and 8 cost +137%. Quantization saves more: the same model in Q4_K_M peaks at 4.2 GB. |
55
+
| Can a small model speed up a big one? |**Yes, with the same output.** Qwen2.5-0.5B drafts and the 7B checks: +23–35% decode on chat text. On code-heavy text the draft agrees too rarely to help. |
50
56
| Is the model still right on long prompts? |**As right as a 0.5B model gets.** Synapse, llama.cpp, and MLX give the same answers; the misses (a hidden number at 32k, keys among distractors, variable chains) happen in every engine, so they are the model's limits. |
51
57
| How does **Microsoft Foundry Local** do? |**Fast, but quality-limited in this test.** With separate ONNX weights on about 6 cores, Qwen2.5 0.5B reached 231 tokens/s and the 7B models 22–25 tokens/s; none of the 7 model/device variants fully completed the 128-token instruction. |
52
58
| Is it faster than the other .NET engine, dotLLM? |**In the same 8-token smoke, 14× faster.**|
@@ -129,6 +135,28 @@ its final GitHub job summary.
129
135
- Details, every engine and KV cache type, and CPU rows: runs Q–V in
130
136
[`benchmarks/README.md`](benchmarks/README.md).
131
137
138
+
### A 7B model, not loaded whole
139
+
140
+

141
+
142
+
-**Runs.** Qwen2.5-7B-Instruct-1M (head size 128) runs on Metal from Q8_0 and Q4_K_M files. For the pinned
143
+
prompt it writes llama.cpp's text with both.
144
+
-**Q4_K_M** (ADR-021). The same model in Q4_K_M peaks at 4.2 GB instead of 7.3, with no perplexity loss on
145
+
the test text. It uses less memory than llama.cpp, but decodes at 0.64× llama.cpp's speed. That kernel is the
146
+
next target.
147
+
-**Drop layers, never load them** (ADR-019). A qualified drop profile skips whole layers; their weights are
148
+
never mapped for the GPU and their KV is never allocated.
149
+
150
+
| Layers dropped (of 28) | Peak RSS | Perplexity | Same top-1 as dense |
151
+
|---:|---:|---:|---:|
152
+
| 0 | 7,255 MiB | 12.16 | 100% |
153
+
| 2 (qualified) | 6,780 MiB | −1.1% | 80% |
154
+
| 4 | 6,326 MiB | +39% | 66% |
155
+
| 8 | 5,381 MiB | +137% | 51% |
156
+
-**Small drafts, big checks** (ADR-020). The 0.5B proposes 3 tokens and the 7B verifies them in one pass. On
157
+
chat text the 7B Q8_0 decodes at 23 instead of 18 tokens/s, and the output is exactly the 7B's.
158
+
- Details: runs W, X, and Y in [`benchmarks/README.md`](benchmarks/README.md).
159
+
132
160
### Microsoft Foundry Local, 6 models
133
161
134
162

@@ -154,7 +182,9 @@ its final GitHub job summary.
154
182
|---|---|---|---|
155
183
| 🔴 | Hosted long-prompt first token and 128-token decode trail the CPU references | Profile prefill and decode on each runner |`experiments/Synapse.ReferenceBenchmarks`|
156
184
| 🔴 | Apple GPU first token is 1.5× llama.cpp's at 4k (1.04× at 32k); the prompt matrix multiply alone is 1.55× slower at 512 tokens | Profile the GEMM with GPU counters (tile, half, and layout experiments did not close it) |`native/synapse-gpu/.../metal/shaders/matmul.metal`|
157
-
| 🟡 | Past 32k the 0.5B model is out of its rated range | Head size 128 kernels, then Qwen2.5-7B-Instruct-1M |`native/synapse-gpu`, `gpu-kernels.plan.md` LONG.1 |
185
+
| 🔴 | Q4_K_M decode is 0.64× llama.cpp's and prefill 1.6× slower (the memory is already lower) | A pipelined K-quant GEMM and a `mul_mv_q4_K`-style matrix-vector kernel |`gpu-kernels.plan.md` Q4K.2 |
186
+
| 🟡 | A speculative check of 6–8 tokens costs about three single-token passes | A small-batch kernel that reads each weight once |`metal/shaders/matmul.metal`|
187
+
| 🟡 | The 7B's first token is 1.5× llama.cpp's on a 3.5k prompt | The same GEMM work as the 0.5B |`gpu-kernels.plan.md` LONG.1 |
158
188
| 🟡 | Prefix reuse lives in one process | Persistent prefix cache: KV on disk, metadata in ZoneTree | ADR-018 |
159
189
| 🟡 | CPU first token is 1.9× llama.cpp's at 8k | Tiled, vectorized prompt attention |`Qwen2CpuAttention.cs`|
160
190
| 🟡 | Smart context (query-aware KV pages) is proven only on CPU: +3.4% perplexity while reading 30% of an 8k context | Metal kernels matched to the C# selection, then measure speed and memory | ADR-016, `KvPageSelector.cs`|
@@ -170,6 +200,7 @@ All runs and raw data: [`benchmarks/README.md`](benchmarks/README.md).
170
200

Copy file name to clipboardExpand all lines: benchmarks/README.md
+71Lines changed: 71 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -32,6 +32,9 @@ measures Microsoft Foundry Local alone on six models from four families.
32
32
|**T. Context sweep, 4k to 32k, tokens + memory + speed (main README)**| Metal FP32/FP16 KV with prompt attention reading K/V directly; native CPU | GPU / CPU 8 | 1 warm-up + 2 measured, rotated |[JSON](results/2026-09-28-m2-pro-qwen2.5-0.5b-q8_0-context-sweep-diagnostic.json), [prompt IDs](scenarios/context-sweep/)|
33
33
| U. Dynamic KV memory, 131k window (ADR-017) | Metal FP16/FP32 KV, growing slots with reservation | GPU | 1 measured per row |[JSON](results/2026-09-29-m2-pro-qwen2.5-0.5b-q8_0-dynamic-kv-memory-diagnostic.json)|
34
34
| V. Second question about a 30k-token document (ADR-018) | Metal FP16 KV, prompt prefix reuse | GPU | 1 measured per row |[JSON](results/2026-09-29-m2-pro-qwen2.5-0.5b-q8_0-prefix-reuse-diagnostic.json)|
35
+
| W. Qwen2.5-7B-1M: layer drop quality and memory (ADR-019) | Metal FP16 KV, head size 128, weight segments | GPU | 1 run per drop set; memory 1–4 runs |[qualification 7B](results/2026-09-29-m2-pro-qwen2.5-7b-1m-q8_0-layer-drop-qualification.json), [qualification 0.5B](results/2026-09-29-m2-pro-qwen2.5-0.5b-q8_0-layer-drop-qualification.json), [memory](results/2026-09-29-m2-pro-qwen2.5-7b-1m-q8_0-layer-drop-memory-diagnostic.json)|
36
+
| Y. Qwen2.5-7B-1M Q4_K_M against Q8_0 and llama.cpp (ADR-021) | Metal FP16 KV, K-quant kernels | GPU | 2 alternating rounds |[JSON](results/2026-09-29-m2-pro-qwen2.5-7b-1m-k-quant-diagnostic.json)|
37
+
| X. Qwen2.5-7B-1M with a 0.5B draft (ADR-020) | Metal FP16 KV, exact greedy speculation | GPU | 2 alternating rounds |[JSON](results/2026-09-29-m2-pro-qwen2.5-7b-1m-speculative-decoding-diagnostic.json)|
35
38
36
39
Local machine: MacBook Pro, Apple M2 Pro (8 performance + 4 efficiency cores,
37
40
19-core GPU), 32 GB, macOS 27.0 arm64. Every CPU sample starts a new process.
@@ -311,6 +314,74 @@ haystack. One model asks two questions, 32 new tokens each.
311
314
persistent prefix cache across processes is the next step.
312
315
- One run per row: a diagnostic, not a paired verdict.
313
316
317
+
## W. Qwen2.5-7B-Instruct-1M: dropping layers (ADR-019)
318
+
319
+
**Quality.** Perplexity over 1,024 scored positions of the pinned haystack (`experiments layer-drop`); dense
320
+
12.163. Top-1 is the share of positions whose arg-max equals the dense model's.
0 commit comments