node stringclasses 3
values | chip stringclasses 3
values | unified_memory_gb int64 64 256 | model stringclasses 3
values | model_repo stringclasses 3
values | mtp_config stringclasses 2
values | ctx_limit_tok int64 65.5k 262k | target stringclasses 7
values | round stringclasses 2
values | decode_tps float64 9.5 129 | completion_tokens int64 143 1.02k | metric stringclasses 1
value |
|---|---|---|---|---|---|---|---|---|---|---|---|
m3 | Apple M3 Ultra | 256 | Qwen3.8-Flash-Next-oQ6e-mtp | local quant (not published) | num_draft 6 adaptive depth 6 | 262,144 | 2k | r1_cold | 39.1 | 587 | decode tok/s TTFT-excluded |
m3 | Apple M3 Ultra | 256 | Qwen3.8-Flash-Next-oQ6e-mtp | local quant (not published) | num_draft 6 adaptive depth 6 | 262,144 | 2k | r2_warm | 79.2 | 587 | decode tok/s TTFT-excluded |
m3 | Apple M3 Ultra | 256 | Qwen3.8-Flash-Next-oQ6e-mtp | local quant (not published) | num_draft 6 adaptive depth 6 | 262,144 | 4k | r1_cold | 32 | 496 | decode tok/s TTFT-excluded |
m3 | Apple M3 Ultra | 256 | Qwen3.8-Flash-Next-oQ6e-mtp | local quant (not published) | num_draft 6 adaptive depth 6 | 262,144 | 4k | r2_warm | 79.9 | 496 | decode tok/s TTFT-excluded |
m3 | Apple M3 Ultra | 256 | Qwen3.8-Flash-Next-oQ6e-mtp | local quant (not published) | num_draft 6 adaptive depth 6 | 262,144 | 8k | r1_cold | 20.4 | 654 | decode tok/s TTFT-excluded |
m3 | Apple M3 Ultra | 256 | Qwen3.8-Flash-Next-oQ6e-mtp | local quant (not published) | num_draft 6 adaptive depth 6 | 262,144 | 8k | r2_warm | 74.9 | 654 | decode tok/s TTFT-excluded |
m3 | Apple M3 Ultra | 256 | Qwen3.8-Flash-Next-oQ6e-mtp | local quant (not published) | num_draft 6 adaptive depth 6 | 262,144 | peak_code | r2_warm | 102.9 | 150 | decode tok/s TTFT-excluded |
m3 | Apple M3 Ultra | 256 | Qwen3.8-Flash-Next-oQ6e-mtp | local quant (not published) | num_draft 6 adaptive depth 6 | 262,144 | peak_step_arith | r2_warm | 113.5 | 547 | decode tok/s TTFT-excluded |
m3 | Apple M3 Ultra | 256 | Qwen3.8-Flash-Next-oQ6e-mtp | local quant (not published) | num_draft 6 adaptive depth 6 | 262,144 | peak_repeat_seq | r2_warm | 128.9 | 1,016 | decode tok/s TTFT-excluded |
m4 | Apple M4 Pro | 64 | Jundot--Qwen3.6-35B-A3B-oQ4e-mtp | https://huggingface.co/Jundot/Qwen3.6-35B-A3B-oQ4e-mtp | num_draft 3 | 131,072 | 2k | r1_cold | 42.7 | 526 | decode tok/s TTFT-excluded |
m4 | Apple M4 Pro | 64 | Jundot--Qwen3.6-35B-A3B-oQ4e-mtp | https://huggingface.co/Jundot/Qwen3.6-35B-A3B-oQ4e-mtp | num_draft 3 | 131,072 | 2k | r2_warm | 94.3 | 527 | decode tok/s TTFT-excluded |
m4 | Apple M4 Pro | 64 | Jundot--Qwen3.6-35B-A3B-oQ4e-mtp | https://huggingface.co/Jundot/Qwen3.6-35B-A3B-oQ4e-mtp | num_draft 3 | 131,072 | 4k | r1_cold | 30.7 | 531 | decode tok/s TTFT-excluded |
m4 | Apple M4 Pro | 64 | Jundot--Qwen3.6-35B-A3B-oQ4e-mtp | https://huggingface.co/Jundot/Qwen3.6-35B-A3B-oQ4e-mtp | num_draft 3 | 131,072 | 4k | r2_warm | 85.5 | 522 | decode tok/s TTFT-excluded |
m4 | Apple M4 Pro | 64 | Jundot--Qwen3.6-35B-A3B-oQ4e-mtp | https://huggingface.co/Jundot/Qwen3.6-35B-A3B-oQ4e-mtp | num_draft 3 | 131,072 | 8k | r1_cold | 11.2 | 527 | decode tok/s TTFT-excluded |
m4 | Apple M4 Pro | 64 | Jundot--Qwen3.6-35B-A3B-oQ4e-mtp | https://huggingface.co/Jundot/Qwen3.6-35B-A3B-oQ4e-mtp | num_draft 3 | 131,072 | 8k | r2_warm | 71.3 | 462 | decode tok/s TTFT-excluded |
m5 | Apple M5 Max | 64 | Qwen3.8-27B-MLX-oQ4e-mtp | https://huggingface.co/fcmeyer/Qwen3.8-27B-MLX-oQ4e-mtp | num_draft 3 | 65,536 | 2k | r1_cold | 28.1 | 456 | decode tok/s TTFT-excluded |
m5 | Apple M5 Max | 64 | Qwen3.8-27B-MLX-oQ4e-mtp | https://huggingface.co/fcmeyer/Qwen3.8-27B-MLX-oQ4e-mtp | num_draft 3 | 65,536 | 2k | r2_warm | 57.2 | 454 | decode tok/s TTFT-excluded |
m5 | Apple M5 Max | 64 | Qwen3.8-27B-MLX-oQ4e-mtp | https://huggingface.co/fcmeyer/Qwen3.8-27B-MLX-oQ4e-mtp | num_draft 3 | 65,536 | 4k | r1_cold | 24.3 | 452 | decode tok/s TTFT-excluded |
m5 | Apple M5 Max | 64 | Qwen3.8-27B-MLX-oQ4e-mtp | https://huggingface.co/fcmeyer/Qwen3.8-27B-MLX-oQ4e-mtp | num_draft 3 | 65,536 | 4k | r2_warm | 50.4 | 451 | decode tok/s TTFT-excluded |
m5 | Apple M5 Max | 64 | Qwen3.8-27B-MLX-oQ4e-mtp | https://huggingface.co/fcmeyer/Qwen3.8-27B-MLX-oQ4e-mtp | num_draft 3 | 65,536 | 8k | r1_cold | 9.5 | 451 | decode tok/s TTFT-excluded |
m5 | Apple M5 Max | 64 | Qwen3.8-27B-MLX-oQ4e-mtp | https://huggingface.co/fcmeyer/Qwen3.8-27B-MLX-oQ4e-mtp | num_draft 3 | 65,536 | 8k | r2_warm | 43.9 | 452 | decode tok/s TTFT-excluded |
m5 | Apple M5 Max | 64 | Qwen3.8-27B-MLX-oQ4e-mtp | https://huggingface.co/fcmeyer/Qwen3.8-27B-MLX-oQ4e-mtp | num_draft 3 | 65,536 | peak_code | r2_warm | 69.1 | 143 | decode tok/s TTFT-excluded |
m5 | Apple M5 Max | 64 | Qwen3.8-27B-MLX-oQ4e-mtp | https://huggingface.co/fcmeyer/Qwen3.8-27B-MLX-oQ4e-mtp | num_draft 3 | 65,536 | peak_repeat_seq | r2_warm | 84.8 | 524 | decode tok/s TTFT-excluded |
m5 | Apple M5 Max | 64 | Qwen3.8-27B-MLX-oQ4e-mtp | https://huggingface.co/fcmeyer/Qwen3.8-27B-MLX-oQ4e-mtp | num_draft 3 | 65,536 | prose_500w | r2_warm | 51.1 | 841 | decode tok/s TTFT-excluded |
oMLX MTP decode benchmarks — Apple Silicon homelab (M3 Ultra / M4 Pro / M5 Max)
Single-stream decode benchmarks of Qwen MTP-enabled MLX quants served with oMLX 0.7.1rc1 on three Apple Silicon machines, measured 2026-10-17. Prompts are long technical Spanish text (2k / 4k / 8k words). To our knowledge there are no published numbers for these quants on this hardware class (the quant cards declare no throughput numbers), so this dataset fills that gap.
Hardware
| Node | Chip | Unified memory | OS | Server | Context limit |
|---|---|---|---|---|---|
| m3 | Apple M3 Ultra | 256 GB | macOS | oMLX 0.7.1rc1 (launchd) | 262,144 tok |
| m4 | Apple M4 Pro | 64 GB | macOS | oMLX 0.7.1rc1 (launchd) | 131,072 tok |
| m5 | Apple M5 Max | 64 GB | macOS | oMLX 0.7.1rc1 (launchd, RunAtLoad+KeepAlive) | 65,536 tok |
Reference node in the same lab (no run in this dataset): GMKtec EVO-X2 (AMD Ryzen AI Max+ 395 / Radeon 8060S, 124 GB UMA, Ubuntu + XanMod) serving Qwen3.6-35B-A3B Q4_K_M with llama.cpp/Vulkan at 262,144 ctx.
Models benchmarked
| Node | Model | Base | Size | Quant | MTP |
|---|---|---|---|---|---|
| m3 | Qwen3.8-Flash-Next-oQ6e-mtp (local quant, not published) |
Qwen3.8-Flash-Next 27B dense | ~24 GB weights | oQ6e (~6.5 bpw) + MTP head | enabled, num_draft 6, adaptive depth 6 |
| m4 | Jundot/Qwen3.6-35B-A3B-oQ4e-mtp | Qwen3.6-35B-A3B (35B MoE, 3B active, VLM) | 20.128 GiB, 4.809 bpw (imatrix + WLS refit) | oQ4e Improved (oMLX #4385) | enabled, num_draft 3 |
| m5 | fcmeyer/Qwen3.8-27B-MLX-oQ4e-mtp | Qwen3.8-27B dense | ~16.5 GB, 4.9 bpw | oQ4e | enabled, num_draft 3 |
Methodology
- Single stream,
temperature=0, thinking disabled (chat_template_kwargs: {enable_thinking: false}). - OpenAI-compatible streaming (
stream=true,stream_options.include_usage). - Decode metric:
(completion_tokens − 1) / (t_end − t_first_token)— TTFT excluded. - Two rounds per point:
r1= cold-ish (fresh server/process),r2= warm (KV/page-cache hot). - Prompt: one 1,360-word Spanish technical paragraph (solar installation in Mérida, Yucatán) repeated
×3 (≈4,080 words ≈ 5.7k tokens) for 2k, ×6 (≈8,160 words ≈ 11.4k tokens) for 4k,
×16 (≈21,760 words ≈ 30k tokens) for 8k, each ending with
"Resume el texto anterior en 300 palabras."— full prompt text inprompts.md. - Guard rails: no concurrent traffic during measurement (concurrent requests on this stack depress decode by 50–60%, so all runs were verified single-request).
Results (decode tokens/s)
2k / 4k / 8k-word prompts (this dataset's main table)
| Node / model | 2k r1 (cold) | 2k r2 (warm) | 4k r1 | 4k r2 | 8k r1 | 8k r2 |
|---|---|---|---|---|---|---|
| m3 · Flash-Next 27B oQ6e+MTP d6 | 39.1 | 79.2 | 32.0 | 79.9 | 20.4 | 74.9 |
| m4 · Jundot 35B-A3B oQ4e+MTP d3 | 42.7 | 94.3 | 30.7 | 85.5 | 11.2 | 71.3 |
| m5 · fcmeyer 27B oQ4e+MTP d3 | 28.1 | 57.2 | 24.3 | 50.4 | 9.5 | 43.9 |
Additional points (same day, same method, different prompt mix)
| Node | Point | decode t/s |
|---|---|---|
| m3 | 50–800-token short prompts (bench harness) | 87–91 |
| m3 | peak, code-only prompt | 102.9 |
| m3 | peak, step-by-step arithmetic | 113.5 |
| m3 | peak, repetitive sequence (draft ~99% accept) | 128.9 |
| m4 | 800-token prompts (warm) | 91–93 |
| m4 | 2k tokens warm (bench harness) | 88.6–88.8 |
| m4 | 4k tokens warm (bench harness) | 84.8–85.7 |
| m5 | short prompts warm (bench harness) | 49.3 |
| m5 | 800-token warm | 57–58 |
| m5 | peak, repetitive sequence | 84.8 |
| m5 | peak, code-only prompt | 69.1 |
Context vs published numbers (informal)
fcmeyer/Qwen3.8-27B-MLX-oQ4e-mtpcard reports ~54 t/s with MTP depth 3 on an M5 Max 128 GB; we measure 50.4–57.2 t/s warm on M5 Max 64 GB — parity with half the memory.- No throughput numbers are published on the Jundot or Flash-Next quant cards, and we found no public M3 Ultra / M4 Pro / M5 Max numbers for these models.
- MTP acceptance on m3 prose runs: 65–71%, 1.8–2.5 tokens/cycle (server log); highly predictable text reaches ~99% acceptance and 3.77 tokens/cycle (128.9 t/s).
Caveats
- Warm rounds benefit from hot weights in unified memory and hot KV page-cache; cold rounds include first-touch effects. Treat r2 as steady-state single-stream.
- Prompts are synthetic and repetitive-ish by construction (deliberately, to also expose MTP draft behavior); prose-quality prompts land 10–20% below the arithmetic/repetitive peaks.
- macOS consumer hardware, no active cooling control on the GMKtec reference node.
- Numbers are single-stream; concurrent throughput is a different metric entirely.
Files
results.csv— one row per measured point (machine-readable).prompts.md— exact prompt construction per target.
- Downloads last month
- 57