Skip to content

Commit 056b132

Browse files
Leonardoclaude
andcommitted
docs: lead with verified Arm64-cloud results (2.0x); commit CI evidence
GitHub ubuntu-24.04-arm runner (4 vCPU aarch64) + KleidiAI: n-max=3 gives 2.0x decode (5.99->12.01 tok/s), 1.87x lower latency, 76% accept, 99.1% similarity. README now leads with these; M4 laptop (1.54x) kept as reference. results/ holds the raw CI JSON; workflow skips re-running on docs-only pushes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent cf5a3a8 commit 056b132

5 files changed

Lines changed: 112 additions & 25 deletions

File tree

.github/workflows/arm-bench.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ on:
66
workflow_dispatch: {} # run manually from the Actions tab
77
push:
88
branches: [ main ]
9+
paths-ignore: # don't re-run the expensive bench on docs-only changes
10+
- '**.md'
11+
- 'docs/**'
12+
- 'results/**'
13+
- 'patches/**'
914

1015
jobs:
1116
bench:

README.md

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
# self-draft - drop-in latency optimization for LLM inference servers on Arm64 cloud
22

3-
**One flag. Your model's own Multi-Token-Prediction heads become the draft. ~1.5x
4-
lower-latency decoding for agentic/reasoning workloads on AWS Graviton - zero extra
5-
model download, measurable cost-per-token reduction, stacked on Arm KleidiAI kernels.**
3+
**One flag. Your model's own Multi-Token-Prediction heads become the draft. Up to ~2x
4+
lower-latency decoding for agentic/reasoning workloads on Arm64 cloud - zero extra
5+
model download, ~50% lower cost-per-token, stacked on Arm KleidiAI kernels.**
6+
7+
> **Verified on a free GitHub-hosted Arm64 runner (4 vCPU aarch64): 2.0x speedup,
8+
> 1.87x lower latency, 99.1% output similarity, n-max=3** - reproducible in CI, see below.
69
710
> **Arm Create: AI Optimization Challenge - Cloud AI track.**
811
> Target: AWS Graviton (Arm64) inference serving. Dev/validation: Apple Silicon (Arm64).
@@ -33,35 +36,42 @@ python3 selfdraft/sd.py run models/gemma-4-12b-it-Q4_K_M.gguf --ngl 0 # CPU =
3336

3437
## Results (measured)
3538

36-
`gemma-4-12b-it` Q4_K_M, MTP draft `mtp-gemma-4-12b-it.gguf` (0.47 GB), greedy,
37-
reasoning/code workload, CPU-only (`--ngl 0`, the Graviton-equivalent path).
38-
**Dev numbers below are Apple M4 Pro (Arm64); reproduce on Graviton with
39-
[`scripts/graviton.sh`](scripts/graviton.sh).**
39+
`gemma-4-12b-it`, MTP draft `mtp-gemma-4-12b-it.gguf` (0.47 GB), greedy, reasoning/code
40+
workload, CPU-only (`--ngl 0`, the native Arm64-cloud path).
41+
42+
### Arm64 cloud (headline) - free GitHub `ubuntu-24.04-arm` runner, 4 vCPU aarch64, Q4_0 + KleidiAI
43+
44+
Fully reproducible in CI ([`.github/workflows/arm-bench.yml`](.github/workflows/arm-bench.yml)):
4045

4146
**Draft-length autotune** (`sd.py autotune`):
4247

4348
| n-max | tok/s | speedup | accept |
4449
|------:|------:|--------:|-------:|
45-
| vanilla | 18.6 | 1.00x | - |
46-
| 2 | 20.2 | 1.09x | 86% |
47-
| **3** | **28.6** | **1.54x** | 81% |
48-
| 4 | 28.3 | 1.52x | 77% |
49-
| 6 | 20.5 | 1.10x | 65% |
50-
51-
**Server metrics + cost** (`sd.py bench --price`, n-max=3; $/hr is illustrative
52-
c7g.xlarge - replace with your Graviton numbers):
53-
54-
| | tok/s | TTFT | latency | $/1M tok |
55-
|---|------:|-----:|--------:|---------:|
56-
| vanilla | 21.3 | 3267 ms | 10.8 s | $1.89 |
57-
| **self-draft** | **27.8** | 3049 ms | **8.8 s** | **$1.45 (-23%)** |
58-
59-
**Agent loop** (`sd.py agent`, ReAct + calculator tool, correct answer both):
60-
~1.1-1.2x end-to-end (short per-step generations are TTFT-bound; the decode win
50+
| vanilla | 5.99 | 1.00x | - |
51+
| 1 | 7.74 | 1.29x | 90% |
52+
| 2 | 9.21 | 1.54x | 82% |
53+
| **3** | **12.11** | **2.02x** | 78% |
54+
| 4 | 7.53 | 1.26x | 70% |
55+
56+
**Bench** (n-max=3): vanilla **5.99 -> 12.01 tok/s = 2.0x**; end-to-end latency
57+
**36.2 s -> 19.3 s (1.87x lower)**; draft acceptance 76%; output similarity **99.1%**
58+
(1 floating-point-tie flip, see notes). Since cost is inversely proportional to
59+
throughput, 2.0x tok/s = **~50% lower $/1M tokens** on any priced Arm instance.
60+
61+
### Apple M4 Pro (Arm64 laptop, dev) - Q4_K_M
62+
63+
For reference, a fast M-series core (less memory-bound) shows a smaller but real win:
64+
n-max=3 -> **1.54x** decode (vanilla 18.6 -> 28.6 tok/s, 81% accept), latency 1.23x lower,
65+
~23% lower $/token. **Self-draft helps *more* on the weaker, more memory-bound Arm cloud
66+
cores** - exactly where it matters for cost.
67+
68+
**Agent loop** (`sd.py agent`, ReAct + calculator tool, correct answer both): end-to-end
69+
win on agentic workloads (short per-step generations are TTFT-bound; the decode win
6170
dominates on longer outputs).
6271

63-
Key takeaways: **~1.5x decode / ~23% lower $/token, zero extra download**, n-max tuning
64-
is decisive (too long *loses* - the autotuner picks the sweet spot per instance).
72+
Key takeaways: **up to 2.0x decode / ~50% lower $/token on Arm64 cloud, zero extra
73+
download.** n-max tuning is decisive (too long *loses*) - the autotuner picks the sweet
74+
spot per instance.
6575

6676
## Install / build
6777

results/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Arm64-cloud benchmark results
2+
3+
Produced by [`.github/workflows/arm-bench.yml`](../.github/workflows/arm-bench.yml) on a
4+
free GitHub-hosted `ubuntu-24.04-arm` runner (4 vCPU aarch64, 15 GiB RAM, Azure westus2),
5+
llama.cpp built with `-DGGML_CPU_KLEIDIAI=ON`, `gemma-4-12b-it-Q4_0` + `mtp-gemma-4-12b-it.gguf`.
6+
7+
- `arm64-ci-autotune.json` - draft-length sweep (best n-max=3, **2.02x**).
8+
- `arm64-ci-bench.json` - n-max=3: vanilla 5.99 -> 12.01 tok/s (**2.0x**), latency
9+
36.2s -> 19.3s (1.87x lower), draft acceptance 76%, output similarity 99.1%.
10+
11+
Reproduce: Actions tab -> "arm64-cloud-benchmark" -> Run workflow (free, no credit card).

results/arm64-ci-autotune.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"vanilla_tok_s": 5.989136380383826,
3+
"grid": [
4+
{
5+
"n_max": 1,
6+
"tok_s": 7.74287874134086,
7+
"speedup": 1.2928205753839657,
8+
"accept_pct": 90.36144578313252
9+
},
10+
{
11+
"n_max": 2,
12+
"tok_s": 9.205315471339194,
13+
"speedup": 1.537002146334369,
14+
"accept_pct": 81.66666666666667
15+
},
16+
{
17+
"n_max": 3,
18+
"tok_s": 12.11183829242459,
19+
"speedup": 2.0223013007508737,
20+
"accept_pct": 77.62237762237763
21+
},
22+
{
23+
"n_max": 4,
24+
"tok_s": 7.533820024385093,
25+
"speedup": 1.257914254392429,
26+
"accept_pct": 70.3030303030303
27+
}
28+
],
29+
"best_n_max": 3
30+
}

results/arm64-ci-bench.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"vanilla": {
3+
"tok_s": 5.986175585963531,
4+
"n": 200,
5+
"ttft_ms": 2777.588,
6+
"latency_ms": 36187.901000000005
7+
},
8+
"self_draft": {
9+
"tok_s": 12.00947523577152,
10+
"n": 200,
11+
"ttft_ms": 2685.847,
12+
"latency_ms": 19339.364,
13+
"accept_pct": 76.24309392265194,
14+
"draft_n": 181
15+
},
16+
"speedup": 2.0062016329643764,
17+
"equivalence": {
18+
"identical": false,
19+
"sha_a": "b3abf8a0132a",
20+
"sha_b": "3e19db8470ba",
21+
"common_prefix_chars": 286,
22+
"len_a": 612,
23+
"len_b": 613,
24+
"similarity": 0.991
25+
},
26+
"price_per_hr": 0.0,
27+
"cost_per_mtok": {
28+
"vanilla": null,
29+
"self_draft": null
30+
}
31+
}

0 commit comments

Comments
 (0)