mlx-bun 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -32
- package/docs/README.md +58 -42
- package/docs/archive/investigations/benchmark-ledger-through-v0.4.0.md +3617 -0
- package/docs/archive/investigations/openjarvis-fit.md +198 -0
- package/docs/archive/investigations/qwen38-27b-campaign-log.md +1092 -0
- package/docs/archive/planning/release-notes-v0.4.0.md +45 -0
- package/docs/archive/planning/release-notes-v0.5.0.md +37 -0
- package/docs/design/batching.md +1535 -50
- package/docs/design/decode-speed-program.md +394 -1171
- package/docs/design/generic-model-support.md +195 -3
- package/docs/design/kv-cache.md +538 -225
- package/docs/design/speculative-decoding.md +552 -50
- package/docs/design/turboquant.md +140 -17
- package/docs/design/unified-engine-frontier-plan.md +259 -150
- package/docs/planning/PRODUCT_ROADMAP.md +21 -6
- package/docs/planning/public-readiness-handoff.md +244 -0
- package/docs/planning/public-readiness.md +149 -0
- package/docs/reference/benchmarks.md +3537 -1112
- package/docs/reference/cli.md +102 -2
- package/docs/reference/distribution.md +45 -13
- package/docs/reference/environment.md +159 -13
- package/docs/reference/library-api.md +18 -4
- package/docs/reference/memory.md +1 -1
- package/docs/reference/models.md +28 -7
- package/docs/reference/server-api.md +257 -33
- package/docs/reference/server-config.md +372 -151
- package/docs/reference/troubleshooting.md +13 -21
- package/package.json +2 -2
- package/src/audio/audiotoolbox.ts +112 -0
- package/src/audio/conformer.ts +8 -0
- package/src/audio/mic-capture.ts +98 -0
- package/src/audio/silero-vad.ts +379 -0
- package/src/audio/whisper-decode.ts +774 -0
- package/src/audio/whisper-fast.ts +732 -0
- package/src/audio/whisper-format.ts +73 -0
- package/src/audio/whisper-mel.ts +185 -0
- package/src/audio/whisper-timing.ts +274 -0
- package/src/audio/whisper-tokenizer.ts +239 -0
- package/src/audio/whisper-transcribe.ts +410 -0
- package/src/backends/mlx/assistant-target.ts +46 -0
- package/src/backends/mlx/autoregressive-draft-rows.ts +120 -0
- package/src/backends/mlx/autoregressive.ts +22 -1
- package/src/backends/mlx/batch-group.ts +464 -236
- package/src/backends/mlx/cache-attachment.ts +67 -0
- package/src/backends/mlx/cache-layout.ts +31 -0
- package/src/backends/mlx/checkpoint-state.ts +53 -0
- package/src/backends/mlx/continuation-persistence.ts +107 -0
- package/src/backends/mlx/continuation-request.ts +43 -0
- package/src/backends/mlx/continuation.ts +77 -0
- package/src/backends/mlx/draft-target.ts +7 -22
- package/src/backends/mlx/encoder-cache.ts +25 -0
- package/src/backends/mlx/fill-append.ts +21 -8
- package/src/backends/mlx/fill-group.ts +497 -0
- package/src/backends/mlx/full-kv-row-append.ts +32 -0
- package/src/backends/mlx/full-kv-row-donor.ts +54 -0
- package/src/backends/mlx/full-transitioning-kv-rows.ts +65 -0
- package/src/backends/mlx/gateway-binding.ts +122 -19
- package/src/backends/mlx/kv-codec.ts +9 -0
- package/src/backends/mlx/kv-maintenance.ts +161 -0
- package/src/backends/mlx/kv-tensor-rows.ts +212 -0
- package/src/backends/mlx/mixed-iteration.ts +62 -0
- package/src/backends/mlx/model-prompt.ts +46 -32
- package/src/backends/mlx/model-serving.ts +5 -4
- package/src/backends/mlx/paged-cache-codec.ts +27 -0
- package/src/backends/mlx/prefill-cohort.ts +100 -0
- package/src/backends/mlx/prefill-policy.ts +26 -0
- package/src/backends/mlx/prefill-rows.ts +244 -0
- package/src/backends/mlx/prefill.ts +1 -1
- package/src/backends/mlx/projected-context-rows.ts +72 -0
- package/src/backends/mlx/prompt-input.ts +29 -0
- package/src/backends/mlx/qwen-prompt-input.ts +40 -0
- package/src/backends/mlx/request-state-policy.ts +54 -0
- package/src/backends/mlx/rollback.ts +45 -4
- package/src/backends/mlx/row-sampling.ts +49 -0
- package/src/backends/mlx/serial-executor.ts +51 -73
- package/src/backends/mlx/speculative-group.ts +438 -0
- package/src/backends/mlx/speculative-round.ts +161 -0
- package/src/backends/mlx/speculative.ts +24 -7
- package/src/backends/mlx/state-rows.ts +104 -0
- package/src/backends/mlx/state-views.ts +21 -1
- package/src/backends/mlx/target-layout-capability.ts +35 -0
- package/src/backends/mlx/transitioning-kv-rows.ts +173 -0
- package/src/cli.ts +333 -36
- package/src/contracts/execution.ts +21 -0
- package/src/contracts/object-cache.ts +8 -0
- package/src/contracts/pi-provider.ts +1 -1
- package/src/contracts/pi.ts +3 -1
- package/src/contracts/prefix-cache.ts +33 -0
- package/src/contracts/resources.ts +7 -0
- package/src/contracts/sampling.ts +23 -0
- package/src/contracts/scheduling.ts +27 -0
- package/src/engine/execution-plan.ts +38 -25
- package/src/engine/execution-tasks.ts +44 -0
- package/src/engine/namespaced-cache.ts +13 -0
- package/src/engine/resources.ts +12 -1
- package/src/engine/scheduler.ts +32 -7
- package/src/fill/fill-session.ts +14 -3
- package/src/fit.ts +29 -15
- package/src/generate.ts +105 -195
- package/src/grammar.ts +13 -0
- package/src/inference/draft-acceptance.ts +41 -0
- package/src/inference/draft-output.ts +49 -0
- package/src/inference/prefill.ts +6 -0
- package/src/inference/rollback.ts +2 -2
- package/src/kv-scheme.ts +92 -12
- package/src/kv-store.ts +183 -93
- package/src/lab/README.md +5 -1
- package/src/lab/paged-kv/paged-attention.ts +117 -0
- package/src/lab/paged-kv/paged-kv-rows.ts +111 -0
- package/src/lab/paged-kv/paged-kv.ts +126 -46
- package/src/md-modules.d.ts +5 -0
- package/src/mlx/array.ts +39 -1
- package/src/mlx/ffi.ts +19 -0
- package/src/mlx/normalized-argmax.ts +116 -0
- package/src/mlx/ops.ts +97 -10
- package/src/model/artifact-identity.ts +73 -0
- package/src/model/batched-kv.ts +235 -0
- package/src/model/batched-mask.ts +12 -4
- package/src/model/batched-quant.ts +8 -2
- package/src/model/batched-quantized-kv.ts +144 -0
- package/src/model/batched-rotating-quant.ts +76 -15
- package/src/model/batched-rotating-state.ts +76 -0
- package/src/model/batched-rotating.ts +64 -22
- package/src/model/batched-row-storage.ts +52 -0
- package/src/model/batched-ssm.ts +52 -0
- package/src/model/batched-turboquant-kv.ts +94 -0
- package/src/model/compiled-decode.ts +7 -1
- package/src/model/decoded-kv-donor.ts +12 -0
- package/src/model/delayed-quantized-kv.ts +72 -0
- package/src/model/delayed-rotating-quantized-kv.ts +93 -0
- package/src/model/delayed-turboquant-kv.ts +57 -0
- package/src/model/factory.ts +26 -0
- package/src/model/fingerprint.ts +12 -0
- package/src/model/full-prefill-padding.ts +56 -0
- package/src/model/full-prefill-row.ts +105 -0
- package/src/model/gemma4-base.ts +183 -82
- package/src/model/gemma4.ts +116 -28
- package/src/model/generated/gemma4-12b.ts +4 -1
- package/src/model/generated/gemma4-26b.ts +4 -1
- package/src/model/generated/gemma4-e4b.ts +4 -1
- package/src/model/glm52-cache.ts +80 -4
- package/src/model/glm52-mla.ts +12 -6
- package/src/model/glm52.ts +19 -40
- package/src/model/kv-attention-view.ts +70 -0
- package/src/model/minicpm5.ts +11 -7
- package/src/model/profile.ts +29 -4
- package/src/model/quantized-append-attention.ts +31 -0
- package/src/model/qwen3-delta-state.ts +74 -0
- package/src/model/qwen3-delta.ts +59 -36
- package/src/model/qwen3-mrope.ts +7 -9
- package/src/model/qwen3_5.ts +177 -75
- package/src/model/rotating-kv-donor.ts +35 -0
- package/src/model/rotating-kv-layout.ts +262 -0
- package/src/model/rotating-row-transaction.ts +35 -0
- package/src/model/speculative-rotating-kv.ts +101 -0
- package/src/model/ssm-prefill-padding.ts +39 -0
- package/src/model/support.ts +8 -0
- package/src/model/token-groups.ts +66 -0
- package/src/model/trellis-linear.ts +4 -4
- package/src/model/turboquant-codec.ts +89 -0
- package/src/model/universal/dense.ts +14 -13
- package/src/model/whisper.ts +435 -0
- package/src/native/mic_capture.swift +92 -0
- package/src/native-pack.ts +6 -5
- package/src/pi-web.ts +9 -1
- package/src/preflight.ts +31 -15
- package/src/prompt-cache.ts +306 -86
- package/src/runtime-config.ts +1 -5
- package/src/safetensors.ts +9 -2
- package/src/sampler.ts +37 -25
- package/src/serve/audio-routes.ts +323 -0
- package/src/serve/chat-request.ts +2 -0
- package/src/serve/chat-stage.ts +19 -14
- package/src/serve/completion-executor.ts +9 -1
- package/src/serve/discovery-routes.ts +17 -1
- package/src/serve/generated-token-history.ts +57 -0
- package/src/serve/generation-gateway.ts +88 -38
- package/src/serve/model-binding.ts +7 -1
- package/src/serve/model-host.ts +3 -4
- package/src/serve/preparation.ts +3 -3
- package/src/serve/prompt-response-trace.ts +14 -0
- package/src/serve/request-plan.ts +6 -3
- package/src/serve/request-prep.ts +40 -25
- package/src/serve/text-completion-stage.ts +2 -2
- package/src/serve/transcription-server.ts +64 -0
- package/src/serve/transcription-service.ts +502 -0
- package/src/server.ts +185 -261
- package/src/spec/assistant-rows.ts +93 -0
- package/src/spec/assistant-source.ts +28 -18
- package/src/spec/cache-identity.ts +22 -0
- package/src/spec/deepspec-rows.ts +29 -0
- package/src/spec/deepspec-source.ts +12 -10
- package/src/spec/dflash-source.ts +28 -4
- package/src/spec/drafter.ts +153 -142
- package/src/spec/dspark/deepspec-module.ts +95 -120
- package/src/spec/dspark/module-dflash.ts +126 -170
- package/src/spec/glm52-mtp-graph.ts +29 -0
- package/src/spec/glm52-mtp-rows.ts +132 -0
- package/src/spec/glm52-mtp-source.ts +54 -136
- package/src/spec/glm52-mtp-state.ts +33 -0
- package/src/spec/ngram-source.ts +115 -21
- package/src/spec/projected-draft-rows.ts +73 -0
- package/src/spec/qwen-mtp-module.ts +171 -0
- package/src/spec/qwen-mtp-rows.ts +230 -0
- package/src/spec/qwen-mtp-source.ts +84 -226
- package/src/spec/qwen-mtp-state.ts +30 -0
- package/src/spec/serve-loop.ts +73 -69
- package/src/spec/source.ts +93 -15
- package/src/spec/two-model-rows.ts +62 -0
- package/src/spec/two-model.ts +45 -103
- package/src/ssd-cache.ts +107 -36
- package/src/ssd-durability.ts +29 -27
- package/src/storage/host-buffer.ts +24 -0
- package/src/storage/kv-writer.ts +83 -0
- package/src/storage/kv-writer.worker.js +264 -0
- package/src/storage/retention-policy.ts +37 -0
- package/src/tiered-prompt-cache.ts +45 -0
- package/src/vision/embedder.ts +8 -0
- package/src/vision/prompt.ts +101 -65
- package/src/vision/qwen3vl-prompt.ts +101 -64
- package/src/vision/qwen3vl-tower.ts +11 -0
- package/src/vision/siglip.ts +8 -0
- package/src/web/app.html +12 -0
- package/src/web/app.js +217 -57
- package/src/web/src/chat.ts +4 -1
- package/src/web/src/composer.ts +3 -0
- package/src/web/src/voice.ts +141 -0
- package/src/web/sw.js +1 -1
- package/src/backends/mlx/memory-guard.ts +0 -40
- package/src/spec/prefix-state.ts +0 -45
- /package/docs/{planning → archive/planning}/release-notes-v0.3.0.md +0 -0
|
@@ -0,0 +1,3617 @@
|
|
|
1
|
+
# Benchmark ledger through v0.4.0
|
|
2
|
+
|
|
3
|
+
Frozen campaign record moved from `docs/reference/benchmarks.md`. Entries describe
|
|
4
|
+
the source and machine conditions at measurement time; references to unreleased
|
|
5
|
+
work and internal procedures are historical. Current results and reproduction
|
|
6
|
+
instructions live in [benchmarks.md](../../reference/benchmarks.md).
|
|
7
|
+
|
|
8
|
+
The durable, hand-maintained benchmark record. Raw per-run files
|
|
9
|
+
(`benchmarks-h2h-<date>-<machine>.md/.html`) are gitignored ephemera; the
|
|
10
|
+
structured backing record is the user-local eval DB
|
|
11
|
+
(`~/.cache/mlx-bun/evals.sqlite`). Promote a run into this file
|
|
12
|
+
deliberately when it becomes the new reference.
|
|
13
|
+
|
|
14
|
+
New raw request records also retain the server's final `usage` object,
|
|
15
|
+
including execution lane and speculative counters when supplied. The reader
|
|
16
|
+
captures these already-parsed fields after timing finishes; older reports may
|
|
17
|
+
lack them. This lets settings comparisons verify which method actually ran.
|
|
18
|
+
|
|
19
|
+
The optional `mlx-bun-isolated` arm runs the same CLI/model/request cells through
|
|
20
|
+
`--isolate`; select it alongside `mlx-bun` to compare transport cost. Its RSS
|
|
21
|
+
column sums the parent and descendant processes. This is aggregate process RSS,
|
|
22
|
+
not deduplicated physical memory; shared runtime pages may appear in both.
|
|
23
|
+
|
|
24
|
+
The current closeout candidate follows Josh's advisory-memory policy: requests
|
|
25
|
+
are attempted without fit-based refusal or completion clamping by default.
|
|
26
|
+
Earlier reservation variants remain diagnostics, including successful trials;
|
|
27
|
+
they are not the product policy. Explicit budgets/context caps still apply.
|
|
28
|
+
No speed default has been promoted by these memory experiments.
|
|
29
|
+
|
|
30
|
+
The advisory candidate's M4 Pro replay (`m4-advisory-short.md.json`) retains
|
|
31
|
+
all 23 comparable successful request outputs and usage/cache counts from
|
|
32
|
+
the earlier R0 run. Five-sample decode medians are 14.812 tok/s serial and
|
|
33
|
+
14.677 tok/s continuous; this is one diagnostic run, not a paired speed win.
|
|
34
|
+
Both lanes complete decode and cold/warm 1K prefill. The aggregate retained
|
|
35
|
+
history hits actual Metal insufficient-memory errors: serial recovers on the
|
|
36
|
+
harness retry; continuous fails both attempts. These are runtime failures,
|
|
37
|
+
not predictive refusals. Local regression tests deliberately give the live
|
|
38
|
+
model an impossible accounting estimate and verify both lanes still execute.
|
|
39
|
+
Review: `reports/qwen38-closeout/m4-advisory-short-review.json`.
|
|
40
|
+
|
|
41
|
+
## Rotating target speculation through shared execution
|
|
42
|
+
|
|
43
|
+
M4 Pro 24 GB, Bun 1.4.2, MLX 0.32.2. Gemma 4 12B OptiQ, prompt lookup
|
|
44
|
+
at its default depth ten, bf16 KV, 2 GiB RAM cache plus temporary SSD,
|
|
45
|
+
192 decode tokens, four concurrent requests and default capacity eight.
|
|
46
|
+
Production `bench-serve.ts all`, context sweep skipped, seed `rotating-spec-0`,
|
|
47
|
+
diagnostic mode under Josh's machine policy. Final comparison order is
|
|
48
|
+
control-1, candidate-2, control-2, candidate-3; an earlier candidate-1 predates
|
|
49
|
+
the final singleton boundary correction and is excluded from these means.
|
|
50
|
+
|
|
51
|
+
| Metric (mean of two arms) | Previous serial placement | Shared rotating placement | Change |
|
|
52
|
+
|---|---:|---:|---:|
|
|
53
|
+
| Single-request decode | 16.928 tok/s | 16.894 tok/s | −0.2% |
|
|
54
|
+
| Four-request throughput | 17.269 tok/s | 22.130 tok/s | +28.1% |
|
|
55
|
+
| Four-request wall time | 29,648.128 ms | 23,139.278 ms | −22.0% |
|
|
56
|
+
| Repeated-prompt TTFT | 2,505.201 ms | 199.600 ms | −92.0% |
|
|
57
|
+
| Cold prefill TTFT | 2,515.753 ms | 2,524.302 ms | +0.3% |
|
|
58
|
+
| Launch to first output | 1,571.428 ms | 1,631.817 ms | +3.8% |
|
|
59
|
+
|
|
60
|
+
All 60 recorded requests complete with matching bodies and token budgets.
|
|
61
|
+
Single-request text and raw completion/chat probes match. All four concurrent
|
|
62
|
+
responses differ across implementations, while each implementation's repeats
|
|
63
|
+
are exact. This measures fixed output budgets with different concurrent
|
|
64
|
+
trajectories. The shared cache reuses 671 tokens versus zero in the control.
|
|
65
|
+
Startup spans roughly 1.1–2.2 seconds in both arms; its mean does not establish
|
|
66
|
+
strict dominance. This closes the bf16 rotating transaction implementation,
|
|
67
|
+
not all speculative compositions or strict serial-removal acceptance.
|
|
68
|
+
|
|
69
|
+
Control source: `20c21f2f62383b9878966f8ea1bf74c98d58942d33351430042ff7801cb929c4`.
|
|
70
|
+
Final candidate: `c8213540beb87f438fbafad7115b49f494e92526c28acca930f134883d5cfdcf`.
|
|
71
|
+
The change is integrated in the unreleased tree. Evidence:
|
|
72
|
+
`reports/qwen38-closeout/composition-baseline/rotating-speculation/`, including
|
|
73
|
+
`benchmark-comparison.json` and all raw M4 reports.
|
|
74
|
+
|
|
75
|
+
## Full-attention speculation through shared execution
|
|
76
|
+
|
|
77
|
+
M4 Pro 24 GB, Bun 1.4.2, MLX 0.32.2. Llama 3.2 3B target and 1B
|
|
78
|
+
standalone drafter (4-bit weights), draft depth two, bf16 KV, 2 GiB RAM
|
|
79
|
+
plus temporary SSD. Production `bench-serve.ts all`, 192 decode tokens,
|
|
80
|
+
four concurrent requests, default capacity eight, seed `full-kv-spec-0`,
|
|
81
|
+
context sweep skipped, diagnostic mode under Josh's machine policy.
|
|
82
|
+
The same draft engine runs in both arms; target placement and paired cache
|
|
83
|
+
reuse change. Order: control, candidate, candidate, control.
|
|
84
|
+
|
|
85
|
+
| Metric (mean of two arms) | Previous serial placement | Shared placement | Change |
|
|
86
|
+
|---|---:|---:|---:|
|
|
87
|
+
| Single-request decode | 120.890 tok/s | 129.319 tok/s | +7.0% |
|
|
88
|
+
| Four-request throughput | 108.167 tok/s | 162.331 tok/s | +50.1% |
|
|
89
|
+
| Four-request wall time | 4,733.455 ms | 3,154.056 ms | −33.4% |
|
|
90
|
+
| Repeated-prompt TTFT | 891.394 ms | 44.685 ms | −95.0% |
|
|
91
|
+
| Cold prefill TTFT | 893.065 ms | 919.492 ms | +3.0% |
|
|
92
|
+
| Launch to first output | 1,070.260 ms | 978.795 ms | −8.5% |
|
|
93
|
+
|
|
94
|
+
All 60 requests complete, with identical request bodies and token counts.
|
|
95
|
+
Single-request text and raw completion/chat probes match. One of four
|
|
96
|
+
concurrent responses changes across implementations; each implementation's
|
|
97
|
+
repeats are exact. Usage differs by execution lane, repeated-prefix reuse
|
|
98
|
+
(752 tokens versus zero), and the changed response's speculative counters.
|
|
99
|
+
Thus aggregate timing holds token budgets fixed, with one changed trajectory.
|
|
100
|
+
The control launch times span 970–1,171 ms; this is not strict startup
|
|
101
|
+
acceptance. Cold-prefill latency still regresses. The change is integrated
|
|
102
|
+
in the unreleased tree; defaults remain unchanged.
|
|
103
|
+
|
|
104
|
+
Control source: `3a420497bf8a8c6be5896050b45773d541515a22e737d8775522d742221a8d41`.
|
|
105
|
+
Candidate source: `20c21f2f62383b9878966f8ea1bf74c98d58942d33351430042ff7801cb929c4`.
|
|
106
|
+
Evidence: `reports/qwen38-closeout/composition-baseline/full-kv-speculation/`,
|
|
107
|
+
including four raw M4 reports and `benchmark-comparison.json`.
|
|
108
|
+
|
|
109
|
+
## Standalone drafting: first shared-executor comparison
|
|
110
|
+
|
|
111
|
+
M4 Pro 24 GB, Bun 1.4.2, MLX 0.32.2. Qwen3.8 packed 27B target plus
|
|
112
|
+
Qwen3.5 0.8B OptiQ standalone drafter, depth two, KV4 from token zero,
|
|
113
|
+
4 GiB RAM cache plus temporary SSD, 192 decode tokens and four concurrent
|
|
114
|
+
requests. Production `bench-serve.ts all`, seed `standalone-serving-0`,
|
|
115
|
+
context sweep skipped; advisory diagnostic mode under Josh's machine policy.
|
|
116
|
+
|
|
117
|
+
| First run | Single-request decode | Repeated-prompt TTFT | Reused tokens | Four-request throughput |
|
|
118
|
+
|---|---:|---:|---:|---:|
|
|
119
|
+
| Previous standalone provider | 8.936 tok/s | 5,987.688 ms | 0 | 8.617 tok/s |
|
|
120
|
+
| Shared standalone candidate | 13.945 tok/s | 122.100 ms | 756 | GPU allocation failure |
|
|
121
|
+
|
|
122
|
+
The initial candidate's aggregate phase failed both attempts with native Metal
|
|
123
|
+
insufficient-memory errors. A complete-sequence profile reproduces the failure
|
|
124
|
+
with 4,005 MiB of accounted cache entries and an observed 17,987 MiB peak;
|
|
125
|
+
a fresh aggregate completes. Retained RAM entries consume batch headroom.
|
|
126
|
+
|
|
127
|
+
A second matched comparison uses **2 GiB RAM plus SSD in both arms**, in
|
|
128
|
+
candidate/control/control/candidate order. Other settings are unchanged;
|
|
129
|
+
default capacity is eight, with four concurrent requests. All 60 recorded
|
|
130
|
+
requests complete without failures. Means of the per-arm measurements:
|
|
131
|
+
|
|
132
|
+
| Metric | Previous standalone provider | Shared standalone provider | Change |
|
|
133
|
+
|---|---:|---:|---:|
|
|
134
|
+
| Single-request decode | 8.882 tok/s | 13.970 tok/s | +57.3% |
|
|
135
|
+
| Four-request throughput | 8.614 tok/s | 9.343 tok/s | +8.5% |
|
|
136
|
+
| Four-request wall time | 59.437 s | 54.807 s | −7.8% |
|
|
137
|
+
| Repeated-prompt TTFT | 5,989.823 ms | 122.527 ms | −98.0% |
|
|
138
|
+
| Cold prefill TTFT | 5,993.083 ms | 6,153.492 ms | +2.7% |
|
|
139
|
+
| Launch to first output | 4,332.735 ms | 4,537.720 ms | +4.7% |
|
|
140
|
+
|
|
141
|
+
All request bodies, token counts and single-request text match; raw completion
|
|
142
|
+
and chat probes also match. Candidate repeats preserve single-request text and
|
|
143
|
+
usage. Concurrent text and acceptance counters differ both across implementations
|
|
144
|
+
and between candidate repeats as admission geometry changes; throughput is a
|
|
145
|
+
fixed-token-budget serving measurement, not identical generated content.
|
|
146
|
+
The new provider retains recurrent draft history after rejection; the old
|
|
147
|
+
provider discarded that history. It also retains paired cache state, with
|
|
148
|
+
756 tokens reused on the repeated prompt versus zero in the control.
|
|
149
|
+
|
|
150
|
+
The provider is integrated in the unreleased working tree. The cold/startup
|
|
151
|
+
cost and the 4 GiB failure remain; this does not close strict serial dominance
|
|
152
|
+
or select application defaults. MTP comparisons use a different drafter and
|
|
153
|
+
must remain separate. Control source is
|
|
154
|
+
`0a7e65986e57b493e7ab30a2e328a1eb591b03b029f59e342fd8a01471538613`;
|
|
155
|
+
candidate source
|
|
156
|
+
`3a420497bf8a8c6be5896050b45773d541515a22e737d8775522d742221a8d41`.
|
|
157
|
+
Evidence: `reports/qwen38-closeout/composition-baseline/two-model-batch/`,
|
|
158
|
+
including `ram2/benchmark-comparison.json` and raw request records.
|
|
159
|
+
|
|
160
|
+
## Current serial versus shared execution: staggered Gemma requests
|
|
161
|
+
|
|
162
|
+
M4 Pro 24 GB, Bun 1.4.2, MLX 0.32.2/native pack 0.4.0, unreleased source
|
|
163
|
+
`0a7e65986e57b493e7ab30a2e328a1eb591b03b029f59e342fd8a01471538613`.
|
|
164
|
+
Gemma 4 12B OptiQ, ordinary KV4, 4 GiB RAM prompt cache and temporary SSD.
|
|
165
|
+
`bench-serve.ts all` uses 192 decode tokens, skipped context sweep,
|
|
166
|
+
`--aggregate-context 2048 --aggregate-stagger-ms 25`, seed `prefill-long-0`.
|
|
167
|
+
The serial arm pins `--batch 1`; the shared arm uses the default capacity eight. The four aggregate prompts contain 1,289/1,281/1,287/1,287
|
|
168
|
+
tokens with 13/12/14/12 cached, and each emits 128 tokens. Diagnostic mode
|
|
169
|
+
follows Josh's retained-swap policy; no competing GPU job runs during timing.
|
|
170
|
+
|
|
171
|
+
| run order | median decode tok/s | cached first-token ms | aggregate tok/s | aggregate wall ms | first request TTFT ms | mean TTFT ms |
|
|
172
|
+
|---|---:|---:|---:|---:|---:|---:|
|
|
173
|
+
| serial 0 | 26.3177 | 155.205 | 11.4938 | 44545.58 | 10037.72 | 24644.60 |
|
|
174
|
+
| shared 0 | 26.0648 | 155.797 | 19.7660 | 25903.03 | 9287.39 | 16360.50 |
|
|
175
|
+
| shared 1 | 26.2129 | 154.351 | 20.1601 | 25396.75 | 9031.62 | 15985.86 |
|
|
176
|
+
| serial 1 | 25.9724 | 156.207 | 13.0064 | 39365.23 | 4776.07 | 19477.02 |
|
|
177
|
+
|
|
178
|
+
Mean aggregate throughput increases **62.96%**, total aggregate time falls
|
|
179
|
+
**38.86%**, and mean first-token latency falls **26.69%**. Single-request
|
|
180
|
+
decode is effectively equal, −0.024% in throughput or +0.056% in summed
|
|
181
|
+
request time; cached latency falls 0.406%. First-request latency does not
|
|
182
|
+
dominate: the second serial sample starts in 4.78 s versus shared samples
|
|
183
|
+
near 9.1 s. Startup also has an initial serial outlier, so it is not a settled
|
|
184
|
+
comparison. These limits keep strict serial deletion acceptance open.
|
|
185
|
+
|
|
186
|
+
All 60 requests complete without failure. Request bodies, usage excluding
|
|
187
|
+
the expected lane label, token/cache counts and finish markers match. All
|
|
188
|
+
single-request texts match; all four concurrent texts differ between serial
|
|
189
|
+
and shared. Repeated runs of each arm produce identical text. This measures
|
|
190
|
+
throughput for the same submitted workload and output-token budgets, not
|
|
191
|
+
identical generated content. Same-B model oracle checks remain separate.
|
|
192
|
+
Source hashes stay fixed throughout both blocks. Raw reports and comparison:
|
|
193
|
+
`reports/qwen38-closeout/composition-baseline/current-serial-dominance/`.
|
|
194
|
+
|
|
195
|
+
## Delayed full-attention padding: M4 comparison
|
|
196
|
+
|
|
197
|
+
The unreleased cache implementation now supports padded prefill while full
|
|
198
|
+
attention rows transition independently from BF16 to affine or TurboQuant.
|
|
199
|
+
Shared row positions and codec ownership replace separate padding logic.
|
|
200
|
+
The existing uniform KV4 decode still uses the same packed attention code.
|
|
201
|
+
|
|
202
|
+
M4 Pro 24 GB, Bun 1.4.2, MLX 0.32.2/native pack 0.4.0. Qwen3.8-27B packed
|
|
203
|
+
interleave2 target and folded RTN4 MTP companion, depth 2, KV4 from token zero,
|
|
204
|
+
4 GiB RAM prompt cache, temporary SSD cache, configured batch capacity 8,
|
|
205
|
+
four concurrent requests. Production `bench-serve.ts all`, 192 decode tokens,
|
|
206
|
+
`--skip-context`, workload seed `mtp-serving-block-0`, async expansion off and
|
|
207
|
+
fused TQ decode enabled. Diagnostic mode follows Josh's retained-swap policy;
|
|
208
|
+
free memory starts at 90–93%, retained swap at 1.6–2.8 GiB. No other GPU job
|
|
209
|
+
runs during timing. The audio-daemon allowance is explicit.
|
|
210
|
+
|
|
211
|
+
| arm, in order | median decode tok/s | aggregate tok/s | cached first-token ms | ready ms | cold start ms |
|
|
212
|
+
|---|---:|---:|---:|---:|---:|
|
|
213
|
+
| control 1 | 19.2267 | 16.4810 | 98.186 | 610.78 | 4085.57 |
|
|
214
|
+
| candidate 1 | 19.1023 | 16.4524 | 98.070 | 821.10 | 4167.10 |
|
|
215
|
+
| candidate 2 | 19.1224 | 16.4746 | 99.601 | 614.60 | 4009.12 |
|
|
216
|
+
| control 2 | 19.3181 | 16.5351 | 99.174 | 621.53 | 3982.93 |
|
|
217
|
+
|
|
218
|
+
Candidate/control means change decode throughput by −0.831%, aggregate
|
|
219
|
+
throughput by −0.270%, cached latency by +0.157%, and cold start by +1.335%.
|
|
220
|
+
One candidate readiness sample is about 200 ms higher; the other overlaps
|
|
221
|
+
controls. These measurements establish no speed improvement or strict serial
|
|
222
|
+
performance dominance. The feature is integrated with these limits recorded;
|
|
223
|
+
long-prefill and B1 performance acceptance remain open.
|
|
224
|
+
|
|
225
|
+
All 60 request bodies, responses, usage/speculation counters, token counts,
|
|
226
|
+
finish reasons and completion markers match. No requests fail. Each source
|
|
227
|
+
snapshot stays fixed: control `7f06df944eb062703711f29b086879718868803c00367dd992b3a5bb8d0fac8e`,
|
|
228
|
+
candidate `0a7e65986e57b493e7ab30a2e328a1eb591b03b029f59e342fd8a01471538613`.
|
|
229
|
+
Both-machine cache/model and seeded delayed-conversion gates accompany this
|
|
230
|
+
comparison. Evidence: `reports/qwen38-closeout/composition-baseline/full-delayed-prefill/`,
|
|
231
|
+
including `benchmark-comparison.json`, `manifest.json`, and `m4/` raw reports.
|
|
232
|
+
|
|
233
|
+
## Shared MTP prefill: M4 comparison and scheduling attribution
|
|
234
|
+
|
|
235
|
+
Apple M4 Pro, 24 GB; Bun 1.4.2, MLX 0.32.2. Packed interleave2
|
|
236
|
+
Qwen3.8-27B, affine KV4, folded MTP2, four concurrent requests (configured
|
|
237
|
+
maximum batch 8), 4 GiB prompt cache,
|
|
238
|
+
192 output tokens per decode request, five decode samples, context sweep off.
|
|
239
|
+
`bench-serve.ts all` uses workload seed `mtp-serving-block-0`, fused TQ enabled
|
|
240
|
+
and async Trellis expansion disabled. Four balanced runs use
|
|
241
|
+
control/candidate/candidate/control order. The first control started with zero
|
|
242
|
+
swap; subsequent runs used `--diagnostic` after swap returned. All runs finished
|
|
243
|
+
without request failures and retained stable source hashes within each run.
|
|
244
|
+
|
|
245
|
+
| Preparation policy | Runs | Mean decode median tok/s | Mean concurrent tok/s |
|
|
246
|
+
|---|---:|---:|---:|
|
|
247
|
+
| Control: existing MTP preparation | 2 | 19.331 | 15.194 |
|
|
248
|
+
| Common driver, shared prefill | 2 | 19.069 | 14.076 |
|
|
249
|
+
| Common driver, individual preparation | 2 | 19.158 | 15.508 |
|
|
250
|
+
| Common driver, finish resumed final step first | 1 | 19.3 | 14.099 |
|
|
251
|
+
|
|
252
|
+
Shared prefill loses **1.35%** single-request decode rate and **7.36%** concurrent
|
|
253
|
+
throughput relative to the balanced control means. Mean concurrent wall time
|
|
254
|
+
rises from 33.718 to 36.374 seconds. Cached first-output latency is 98.23 versus
|
|
255
|
+
99.85 ms; cold 1K first-output latency is 5844.61 versus 5997.68 ms.
|
|
256
|
+
|
|
257
|
+
All 60 requests in the balanced comparison preserve request hashes,
|
|
258
|
+
prompt/output/cache counts, finish reasons and completion markers. Single-request
|
|
259
|
+
text and usage are exact. Three of four concurrent responses change between
|
|
260
|
+
control and candidate; each arm reproduces its own text and full usage exactly.
|
|
261
|
+
Thus this is a serving comparison with changed concurrent numerical trajectories,
|
|
262
|
+
not an identical-work kernel timing. Total concurrent speculative rounds fall
|
|
263
|
+
from 234 to 232, so an increase in round count does not explain the slowdown.
|
|
264
|
+
|
|
265
|
+
The individual-preparation control changes only the scheduler admission budget
|
|
266
|
+
from 2048 to zero and retains B4 decode and the same common driver. Both runs
|
|
267
|
+
reproduce every control response and full usage record. The clean repeat
|
|
268
|
+
confirmed that this is the only source difference. Finishing resumed final
|
|
269
|
+
steps first instead leaves concurrent responses/usage identical to shared
|
|
270
|
+
prefill and does not recover its throughput. None of these isolated candidates
|
|
271
|
+
is adopted. The next investigation is preparation-to-decode cache state and
|
|
272
|
+
actual work per round.
|
|
273
|
+
|
|
274
|
+
Two instrumented follow-ups locate the sustained cost in target verification.
|
|
275
|
+
Across 53 B4 rounds per arm, median complete-round time is 540.64 ms with
|
|
276
|
+
shared preparation versus 459.01 ms with individual preparation. The target
|
|
277
|
+
forward interval is 510.50 versus 430.34 ms; draft generation is 12.11 versus
|
|
278
|
+
12.15 ms. These are lazy-execution phase timings, so the target interval includes
|
|
279
|
+
any work it forces; layer-level attribution is still needed. Independent saved
|
|
280
|
+
SSE timestamps reproduce the uninstrumented gap (about 542 versus 459 ms
|
|
281
|
+
between output bursts during seconds 10–25).
|
|
282
|
+
|
|
283
|
+
Further probes run three B4 rounds with layer synchronization. Both arms use
|
|
284
|
+
128 packed gate/up calls and 64 expanded down-projection calls, with identical
|
|
285
|
+
M=12 and bf16 geometry. The down-projection evaluation interval, which also
|
|
286
|
+
forces the preceding lazy packed gate/up work, is 412.68 versus 355.75 ms.
|
|
287
|
+
This narrows the cost to MLP evaluation but does not distinguish its packed
|
|
288
|
+
kernels from weight expansion/native matmul. Phase/layer probes preserve their
|
|
289
|
+
respective control responses and usage. A separate candidate evaluates target
|
|
290
|
+
state and clears the temporary buffer pool after preparation; it completes
|
|
291
|
+
without failures at 14.3 concurrent tok/s, still below individual preparation.
|
|
292
|
+
It is not adopted. Profiles: `mtp-cohort-layer-profile.json` and
|
|
293
|
+
`mtp-cohort-trellis-profile.json`; drain result: `mtp-cohort-drain-manifest.json`.
|
|
294
|
+
|
|
295
|
+
A subsequent split probe evaluates inputs, packed projections, expanded weights
|
|
296
|
+
and matrix products separately. Across three instrumented B4 rounds, median
|
|
297
|
+
expansion time is 157.92 ms after shared preparation versus 85.55 ms after
|
|
298
|
+
individual preparation. Packed gate/up evaluation is 232.03 versus 229.83 ms;
|
|
299
|
+
expanded-weight matrix multiplication is 88.75 versus 84.07 ms. These inserted
|
|
300
|
+
synchronization points change absolute latency and serve only to locate work.
|
|
301
|
+
The separate input-evaluation candidate passes M1 native MTP serving but reaches
|
|
302
|
+
13.8 concurrent tok/s on the M4, so it is not adopted. Evidence:
|
|
303
|
+
`mtp-cohort-split-profile.json`, `split-profile-*.md.json`, `input-eval-1.md.json`.
|
|
304
|
+
|
|
305
|
+
Smaller vector expansion tiles (32, 64 and untiled) reach 14.15–14.22
|
|
306
|
+
concurrent tok/s; variant 12 reaches 13.30; a residency refresh reaches 14.00.
|
|
307
|
+
All preserve their shared-prefill reference responses and usage, and none is
|
|
308
|
+
adopted. Memory instrumentation observes 16.823 GiB active after shared
|
|
309
|
+
preparation versus 16.534 GiB after individual preparation. A native ownership
|
|
310
|
+
probe confirms that a deferred compact row copy retains its larger parent
|
|
311
|
+
allocation until evaluated.
|
|
312
|
+
|
|
313
|
+
Evaluating target snapshots before RAM retention recovers concurrent throughput
|
|
314
|
+
in two M4 runs: **16.268 and 16.299 tok/s**, averaging 16.283, versus 14.076
|
|
315
|
+
for the original shared-preparation pair (**+15.68%**) and 15.508 for the two
|
|
316
|
+
individual-preparation controls (**+5.00%**). Concurrent wall time falls to
|
|
317
|
+
31.473 and 31.414 seconds. Single-request decode medians are 19.277 and 19.108
|
|
318
|
+
tok/s; cached first output is 100.66 and 100.76 ms. All 30 requests preserve
|
|
319
|
+
request hashes, output text and full usage exactly against shared preparation.
|
|
320
|
+
Source is stable in both runs. The M1 native serving test passes 229 assertions.
|
|
321
|
+
The final implementation below moves this behavior from method-local capture
|
|
322
|
+
to the common cache ownership boundary for every producer.
|
|
323
|
+
Evidence: `mtp-cohort-snapshot-eval-review.json`,
|
|
324
|
+
`mtp-cohort-expansion-screen-review.json`, `mtp-cohort-memory-profile.json`.
|
|
325
|
+
|
|
326
|
+
Moving materialization into the shared RAM cache, including companion tensors,
|
|
327
|
+
preserves all 30 responses and usage records in two further M4 runs. Concurrent
|
|
328
|
+
throughput is **16.477 and 16.384 tok/s**; single-request decode is 19.127 and
|
|
329
|
+
19.205 tok/s; cached first output is 97.62 and 98.79 ms. The common implementation
|
|
330
|
+
passes 2,150 M1 tests (14 skipped), all typechecks, and the generated TurboQuant
|
|
331
|
+
RAM/SSD continuation test at MTP3/B4. M1 native lookup passes 228 assertions and the ordinary 4096-token TQ prefix
|
|
332
|
+
ownership test passes 40. A fresh current-tree control reaches 19.245 decode
|
|
333
|
+
and 15.539 concurrent tok/s, with 99.02 ms cached first output. Against that
|
|
334
|
+
control, the common-cache pair averages **5.74% higher concurrent throughput**,
|
|
335
|
+
0.41% lower single-request decode and 0.83% lower cached first-output latency.
|
|
336
|
+
This is a two-candidate/one-control comparison; the older balanced control
|
|
337
|
+
pair remains above. The M4 suite passes 2,154 tests (10 skipped), both-machine typechecks pass, and
|
|
338
|
+
M4 native TQ MTP serving passes 229 assertions. The shared driver and common
|
|
339
|
+
cache fix are adopted in the unreleased working tree; main integration
|
|
340
|
+
suite, typechecks and hygiene pass. Strict serial dominance remains open. Review:
|
|
341
|
+
`mtp-cohort-cache-boundary-review.json`; source/validation:
|
|
342
|
+
`mtp-cohort-cache-boundary-manifest.json`.
|
|
343
|
+
|
|
344
|
+
The final memory profile differs from the original shared-preparation profile
|
|
345
|
+
only in the two cache implementation files. Active GPU allocation falls from
|
|
346
|
+
16.823 to **16.458 GiB**, releasing **373.37 MiB**. Median weight-expansion time
|
|
347
|
+
falls from **147.57 to 86.17 ms** across three instrumented B4 rounds, matching
|
|
348
|
+
the individual-preparation profile's 87.99 ms. Routes, geometry and call counts
|
|
349
|
+
are unchanged; all 15 responses and full usage remain exact. The retained-memory
|
|
350
|
+
regression passes with materialization and fails when it is disabled. Profile
|
|
351
|
+
latencies locate the cost; the uninstrumented runs above measure serving speed.
|
|
352
|
+
Evidence: `mtp-cohort-memory-profile.json` and
|
|
353
|
+
`memory-profile-cache-boundary.md.json`.
|
|
354
|
+
|
|
355
|
+
Evidence: `reports/qwen38-closeout/composition-baseline/prefill-cohort/`:
|
|
356
|
+
`mtp-cohort-benchmark-comparison.json`, `mtp-cohort-admission-comparison.json`,
|
|
357
|
+
source manifests/patches, seven comparison runs and instrumented follow-ups in
|
|
358
|
+
`mtp-cohort-m4/*.md.json`; phase timing is in `mtp-cohort-phase-profile.json`.
|
|
359
|
+
|
|
360
|
+
## Delayed affine row composition: fixed-settings M4 regression
|
|
361
|
+
|
|
362
|
+
Apple M4 Pro, 24 GB, macOS 27.0.0, Bun 1.4.2, MLX 0.32.2/native pack
|
|
363
|
+
0.4.0. The existing `bench-serve.ts all` suite ran control/candidate/candidate/control
|
|
364
|
+
on the packed interleave2 Qwen3.8-27B artifact with KV4, MTP2, 192 output tokens,
|
|
365
|
+
five decode requests, prompt cache 4 and context sweep disabled. Workload seed
|
|
366
|
+
`mtp-serving-block-0`; fused TQ enabled, async Trellis expansion disabled.
|
|
367
|
+
All preflights passed with Josh's audio-daemon allowance. Source stayed fixed:
|
|
368
|
+
control `88da0dca100cdb012cbd4330638cc43b727dbb853a5b1ef6aded60bc6fe1eb0d`,
|
|
369
|
+
candidate `eacbb8c7d9e1a2f06c4235f71dc7db51f29b8bd27a9940a5e802a056220ff336`.
|
|
370
|
+
Remote checkout HEAD was `0c355f4`; source hashes include the unreleased changes.
|
|
371
|
+
|
|
372
|
+
| Arm | Five decode requests, total ms | Cached TTFT ms | Concurrent aggregate tok/s |
|
|
373
|
+
|---|---:|---:|---:|
|
|
374
|
+
| Control 1 | 55,730.95 | 97.33 | 15.9259 |
|
|
375
|
+
| Candidate 1 | 55,585.20 | 97.57 | 15.8891 |
|
|
376
|
+
| Candidate 2 | 55,678.22 | 99.36 | 15.7890 |
|
|
377
|
+
| Control 2 | 55,682.47 | 99.41 | 15.7812 |
|
|
378
|
+
|
|
379
|
+
All 60 request records retain identical request hashes, response text, complete
|
|
380
|
+
usage, token counts and finish reasons. Combined candidate/control changes are
|
|
381
|
+
−0.135% decode wall time, +0.099% cached latency and −0.091% aggregate throughput.
|
|
382
|
+
Peak RSS is effectively unchanged. Startup was less stable: the initial control
|
|
383
|
+
reached readiness in 608 ms versus about 800 ms in the later arms, and its cold
|
|
384
|
+
start was 3,443 ms versus about 4,200–4,300 ms afterward. The candidate overlaps
|
|
385
|
+
the final control, but this screen does not establish startup equivalence.
|
|
386
|
+
The decode and cached-latency changes overlap the observed
|
|
387
|
+
control variation: the existing default path is effectively flat. This is a
|
|
388
|
+
regression check for integrating delayed-affine support and the shared transition
|
|
389
|
+
lifecycle, not a measurement of delayed conversion speed or serial dominance.
|
|
390
|
+
Both-machine native/serving/SSD correctness gates qualify the new composition.
|
|
391
|
+
Raw records and comparison: `reports/qwen38-closeout/composition-baseline/delayed-affine/`.
|
|
392
|
+
|
|
393
|
+
## Captured attention views: M4 regression
|
|
394
|
+
|
|
395
|
+
Same M4 Pro 24 GB/toolchain, packed Qwen artifact and 192-token KV4/MTP2
|
|
396
|
+
protocol as the delayed-affine comparison above. Order is again
|
|
397
|
+
control/candidate/candidate/control, with unchanged requests and initial cache
|
|
398
|
+
settings. Control source is
|
|
399
|
+
`eacbb8c7d9e1a2f06c4235f71dc7db51f29b8bd27a9940a5e802a056220ff336`;
|
|
400
|
+
candidate source is
|
|
401
|
+
`f94a8212be222056a0d1cdc70c45c3d7f2e50a937eb89560a719ee4bf21c61f7`.
|
|
402
|
+
Both sources remain fixed throughout their runs.
|
|
403
|
+
|
|
404
|
+
| Arm | Five decode requests, total ms | Cached TTFT ms | Concurrent aggregate tok/s |
|
|
405
|
+
|---|---:|---:|---:|
|
|
406
|
+
| Control 1 | 55,784.51 | 97.57 | 15.8553 |
|
|
407
|
+
| Candidate 1 | 55,656.05 | 97.18 | 15.9355 |
|
|
408
|
+
| Candidate 2 | 55,687.98 | 97.26 | 15.9648 |
|
|
409
|
+
| Control 2 | 55,680.16 | 97.45 | 15.9668 |
|
|
410
|
+
|
|
411
|
+
All 60 request records match in input hash, output text, complete usage, token
|
|
412
|
+
counts and finish reason. Combined decode wall time changes −0.108%, cached
|
|
413
|
+
latency −0.298%, and aggregate throughput +0.246%; peak RSS is unchanged.
|
|
414
|
+
These are effectively flat regression results, not a general speedup or serial
|
|
415
|
+
dominance result. Initial-control startup was faster than every subsequent
|
|
416
|
+
arm: readiness 607 ms versus 817–818 ms; cold start 3,487 ms versus 4,210–4,254 ms.
|
|
417
|
+
Startup equivalence remains unproven.
|
|
418
|
+
|
|
419
|
+
All start checks pass with the audio-daemon allowance. The final control's raw
|
|
420
|
+
end check flags `/usr/libexec/mobileassetd` at 84% CPU and 23 MB RSS, while free
|
|
421
|
+
memory remains 92%. That flag remains in the raw result. Under Josh's policy
|
|
422
|
+
allowing isolated background CPU activity, the stable paired decode/cached
|
|
423
|
+
measurements support feature integration; this is not an entirely unflagged
|
|
424
|
+
four-arm run. The initial wrapper's separate oracle-path error occurred before
|
|
425
|
+
inference and is retained as a failed launch, not a timing sample.
|
|
426
|
+
|
|
427
|
+
The changed attention-view operations are qualified by both-machine full-model
|
|
428
|
+
Gemma/MiniCPM state/logit checks, Qwen rollback/MTP/lookup checks and exact SSD
|
|
429
|
+
continuations. This default-settings screen does not measure delayed conversion
|
|
430
|
+
speed. Evidence: `reports/qwen38-closeout/composition-baseline/kv-attention-view/`.
|
|
431
|
+
|
|
432
|
+
## Delayed rotating affine composition: M4 regression
|
|
433
|
+
|
|
434
|
+
Same M4 Pro 24 GB, Bun 1.4.2, MLX 0.32.2/native pack 0.4.0 and packed
|
|
435
|
+
Qwen KV4/MTP2 protocol as the preceding comparisons: 192 output tokens,
|
|
436
|
+
five decode requests, prompt cache 4, workload seed `mtp-serving-block-0`,
|
|
437
|
+
context sweep disabled, fused TQ enabled and async expansion disabled.
|
|
438
|
+
The four arms ran control/candidate/candidate/control with stable sources:
|
|
439
|
+
control `1b1ededa649088e8338a2930b4ae152e66edf7e4048e2dc8d0b7a3859691800c`,
|
|
440
|
+
candidate `c7d58f7ec867015eff7bbc9a7f02d13baea28173dd312bd504e9b880659278eb`.
|
|
441
|
+
Every start/end preflight passed with the recorded audio-daemon allowance;
|
|
442
|
+
there were no request or phase failures.
|
|
443
|
+
|
|
444
|
+
| Arm | Five decode requests, total ms | Cached TTFT ms | Concurrent aggregate tok/s |
|
|
445
|
+
|---|---:|---:|---:|
|
|
446
|
+
| Control 1 | 55,775.68 | 97.24 | 15.9569 |
|
|
447
|
+
| Candidate 1 | 55,608.34 | 97.49 | 16.0176 |
|
|
448
|
+
| Candidate 2 | 55,692.19 | 97.55 | 15.8421 |
|
|
449
|
+
| Control 2 | 55,661.04 | 99.17 | 15.8041 |
|
|
450
|
+
|
|
451
|
+
All 60 records match in request hash, response text, complete usage including
|
|
452
|
+
speculation counters, token counts and finish reason. These HTTP records do
|
|
453
|
+
not contain emitted token IDs; native tests provide the numerical evidence.
|
|
454
|
+
Candidate versus control means change decode wall time by −0.122%, cached
|
|
455
|
+
latency by −0.696% and aggregate throughput by +0.311%. Peak RSS spans
|
|
456
|
+
12,208–12,224 MB. These are effectively flat regression results. The first
|
|
457
|
+
control reaches readiness in 609 ms and cold start in 3,610 ms; the remaining
|
|
458
|
+
arms take 817–818 ms and 4,235–4,288 ms. Startup equivalence remains unproven.
|
|
459
|
+
|
|
460
|
+
This checks the shared lifecycle on the existing default Qwen path. It does
|
|
461
|
+
not measure positive-threshold Gemma conversion speed or establish serial
|
|
462
|
+
dominance. Both-machine Gemma KV4/KV8 and per-layer native state/logit,
|
|
463
|
+
RAM/SSD continuation and seeded serving tests cover the new composition;
|
|
464
|
+
fresh-process Gemma and long-pressure acceptance remain open.
|
|
465
|
+
Evidence: `reports/qwen38-closeout/composition-baseline/delayed-rotating/`.
|
|
466
|
+
|
|
467
|
+
## Singleton admission attribution on M4 Pro
|
|
468
|
+
|
|
469
|
+
A synthetic Qwen-shaped MLX 0.32.2 probe compares singleton `copyOf` with
|
|
470
|
+
`contiguous`, using evaluated donors: 48 recurrent states, 16 KV4 layers at
|
|
471
|
+
757 logical tokens with 768-token capacity, and their combination. Each arm
|
|
472
|
+
has four warmups and twenty samples; order is control/candidate/candidate/control.
|
|
473
|
+
The combined logical storage is 168,099,840 bytes. Both implementations add
|
|
474
|
+
**zero live GPU allocation** during admission. Combined median admission times
|
|
475
|
+
are 0.1463/0.1435/0.1470/0.1464 ms in execution order. There is no demonstrated
|
|
476
|
+
physical-copy saving; `copyOf` already shares storage in this runtime.
|
|
477
|
+
These synthetic measurements do not establish complete-request speed. The
|
|
478
|
+
initial probe launch omitted the required stream argument to `synchronize`;
|
|
479
|
+
its failure is retained separately and supplied no timing sample.
|
|
480
|
+
|
|
481
|
+
The completed four-arm `bench-serve.ts all` comparison uses the same M4
|
|
482
|
+
Qwen KV4/MTP2, 192-token protocol as above. Control source is
|
|
483
|
+
`c7d58f7ec867015eff7bbc9a7f02d13baea28173dd312bd504e9b880659278eb`;
|
|
484
|
+
candidate is `b7361d962c70f0efbb5c55c32f06996103015477095833c98d83928cc23ddd52`.
|
|
485
|
+
All source snapshots and start/end preflights pass. All 60 request hashes,
|
|
486
|
+
response texts, complete usage/speculation counters, token counts and finish
|
|
487
|
+
reasons match, with no request or phase failures.
|
|
488
|
+
|
|
489
|
+
| Arm | Five decode requests, total ms | Cached TTFT ms | Concurrent aggregate tok/s |
|
|
490
|
+
|---|---:|---:|---:|
|
|
491
|
+
| Control 1 | 56,033.78 | 99.64 | 15.8719 |
|
|
492
|
+
| Candidate 1 | 55,590.06 | 97.28 | 15.9511 |
|
|
493
|
+
| Candidate 2 | 55,682.16 | 97.35 | 15.9217 |
|
|
494
|
+
| Control 2 | 55,725.68 | 99.44 | 15.9324 |
|
|
495
|
+
|
|
496
|
+
Candidate/control means change decode wall time −0.436%, cached latency
|
|
497
|
+
−2.230% and aggregate throughput +0.216%. Both candidate cached samples are
|
|
498
|
+
lower than both controls, although the physical-copy hypothesis is disproven
|
|
499
|
+
and MTP group admission follows its first published token. The latency result
|
|
500
|
+
needs attribution/repetition before treating this replacement as an accepted
|
|
501
|
+
optimization. Controls report readiness at 608 ms and candidates at 816 ms;
|
|
502
|
+
the readiness probe polls every 200 ms, so these observations have coarse
|
|
503
|
+
resolution. Cold starts are 3,414/4,114/4,224/4,017 ms in execution order.
|
|
504
|
+
Startup equivalence and direct serial dominance remain unproven. Both-machine
|
|
505
|
+
native, serving, full-suite and typecheck checks pass; the candidate is isolated.
|
|
506
|
+
Evidence: `reports/qwen38-closeout/composition-baseline/singleton-state/`.
|
|
507
|
+
|
|
508
|
+
## Recurrent row retention diagnostic on M1 Max
|
|
509
|
+
|
|
510
|
+
Apple M1 Max 32 GB, Bun 1.4.2, MLX 0.32.2/native pack 0.4.0. A synthetic
|
|
511
|
+
Qwen-shaped recurrent layer contains 3,207,168 logical bytes per row. After
|
|
512
|
+
extracting one row and disposing its source, the existing implementation keeps
|
|
513
|
+
3,211,264 / 6,422,528 / 12,828,672 / 25,657,344 live allocator bytes for source
|
|
514
|
+
B=1/2/4/8. A proper-subset compact copy retains 3,211,264 bytes in every case,
|
|
515
|
+
including allocator rounding. B1 continues to share its whole allocation.
|
|
516
|
+
This measures one layer, not full-model RSS or request time. The allocation
|
|
517
|
+
regression fails against unchanged source and passes with exact values on the
|
|
518
|
+
isolated fix. Both-machine MTP and bf16/KV4/TQ generated RAM/SSD continuation,
|
|
519
|
+
complete-suite and typecheck checks pass. The allocation regression also passes
|
|
520
|
+
on M4. The reviewed extraction fix is adopted in the unreleased working tree.
|
|
521
|
+
|
|
522
|
+
The M4 Pro 24 GB `bench-serve.ts all` check uses the same packed Qwen KV4/MTP2,
|
|
523
|
+
192-token protocol above, in control/candidate/candidate/control order. Sources
|
|
524
|
+
remain fixed: control
|
|
525
|
+
`c7d58f7ec867015eff7bbc9a7f02d13baea28173dd312bd504e9b880659278eb`, candidate
|
|
526
|
+
`bdc1241596526f42d68ba0988fc63cd90dce73ce8d048b45d9bfa1cc0c5872c7`.
|
|
527
|
+
All start/end preflights pass; all 60 request hashes, response texts, full usage
|
|
528
|
+
and speculation counters, token counts and finish reasons match. No failures.
|
|
529
|
+
|
|
530
|
+
| Arm | Five decode requests, total ms | Cached TTFT ms | Concurrent aggregate tok/s |
|
|
531
|
+
|---|---:|---:|---:|
|
|
532
|
+
| Control 1 | 56,548.78 | 99.48 | 15.7814 |
|
|
533
|
+
| Candidate 1 | 55,608.23 | 99.02 | 15.9869 |
|
|
534
|
+
| Candidate 2 | 55,785.82 | 97.41 | 15.8657 |
|
|
535
|
+
| Control 2 | 55,636.97 | 99.47 | 15.9106 |
|
|
536
|
+
|
|
537
|
+
Candidate/control means change decode wall time −0.706%, cached latency
|
|
538
|
+
−1.264% and aggregate throughput +0.507%. The initial control is slower than
|
|
539
|
+
the remaining arms; candidate throughput overlaps the control range, and the
|
|
540
|
+
second candidate decode total is slightly above the second control. Treat
|
|
541
|
+
these as a regression check for the storage fix, not a broad speedup or serial
|
|
542
|
+
dominance result. Peak RSS spans 12,208–12,240 MB. Startup remains unresolved:
|
|
543
|
+
readiness is 608/816/816/817 ms and cold start 3,704/4,177/4,240/4,181 ms.
|
|
544
|
+
The short workload does not establish long-context pressure acceptance.
|
|
545
|
+
Evidence: `reports/qwen38-closeout/composition-baseline/ssm-extraction/`.
|
|
546
|
+
|
|
547
|
+
## Batched prefill cohorts: M4 regression before projection correction
|
|
548
|
+
|
|
549
|
+
Unreleased isolated candidate against the previously validated delayed-padding
|
|
550
|
+
checkout. Apple M4 Pro, 24 GB; Bun 1.4.2, MLX 0.32.2/native pack 0.4.0.
|
|
551
|
+
Gemma 4 12B OptiQ, ordinary generation, KV4, RAM prompt cache 4 GB, default
|
|
552
|
+
batch capacity 4. Both checkouts have HEAD `0c355f4` plus frozen source changes.
|
|
553
|
+
Control source SHA-256 `89d209400c1f683143ee9afea30e8a440ee00159fe96ba8e1c3bbe5893c744ac`;
|
|
554
|
+
candidate `2431d0395ad7e752991bc47817cf8c6f54a6d74fb6e0f6fc08598e314ce6d937`.
|
|
555
|
+
|
|
556
|
+
Protocol: `bun scripts/bench-serve.ts all --model-path <Gemma-12B-OptiQ>
|
|
557
|
+
--arms mlx-bun --tokens 192 --skip-context --kv-quant 4 --prompt-cache 4
|
|
558
|
+
--workload-seed delayed-padding-0 --allow-cpu-process /usr/libexec/audiomxd`.
|
|
559
|
+
Run order is control, candidate, candidate, control. All preflights and saved
|
|
560
|
+
machine checks pass, with 217 MB swap and the explicitly allowed audio daemon.
|
|
561
|
+
Source hashes remain fixed throughout all four arms; no request failures.
|
|
562
|
+
|
|
563
|
+
| arm | five decode requests, total ms ↓ | cached first-token ms ↓ | B4 aggregate tok/s ↑ | ready ms | cold-start ms | peak RSS MiB |
|
|
564
|
+
|---|---:|---:|---:|---:|---:|---:|
|
|
565
|
+
| control 1 | 38,010.26 | 154.517 | 72.966 | 609.34 | 2,150.35 | 8,985.45 |
|
|
566
|
+
| candidate 1 | 38,063.00 | 154.884 | 72.965 | 608.25 | 1,026.27 | 8,990.06 |
|
|
567
|
+
| candidate 2 | 37,950.08 | 154.601 | 73.024 | 608.52 | 1,024.44 | 8,985.66 |
|
|
568
|
+
| control 2 | 37,906.38 | 154.930 | 73.032 | 609.03 | 1,029.51 | 8,967.28 |
|
|
569
|
+
|
|
570
|
+
Candidate means: decode wall **+0.127%**, cached latency **+0.012%**, aggregate
|
|
571
|
+
throughput **−0.006%**. These results establish no speed win or strict serial
|
|
572
|
+
dominance. The first control's cold-start outlier does not establish a startup
|
|
573
|
+
improvement. This short-prompt workload does not measure long-prefill scaling.
|
|
574
|
+
|
|
575
|
+
All request bodies, token counts, usage, finish reasons and completion markers
|
|
576
|
+
match. Both candidates change the text of concurrent rows 1–3; candidate repeats
|
|
577
|
+
are identical to each other, as are control repeats. Other responses and parity
|
|
578
|
+
probes match. This is not an all-responses-identical regression result. Same-B
|
|
579
|
+
model checks pass on Qwen 27B and Gemma 12B on both Macs, and an admission-only diagnostic restores all
|
|
580
|
+
baseline responses, tying the text changes to shared prefill. An added M4 token-zero check subsequently
|
|
581
|
+
found a sampler-logit mismatch when finished rows project separately. A follow-up
|
|
582
|
+
candidate projects the batch before selecting sampler rows; these timing numbers
|
|
583
|
+
do not measure that fix. The corrected projection passes the M4 model/sampler
|
|
584
|
+
checks. Its fresh comparison is recorded below; the earlier measured candidate is not adopted.
|
|
585
|
+
|
|
586
|
+
Raw evidence: `reports/qwen38-closeout/composition-baseline/prefill-cohort/`,
|
|
587
|
+
including source manifest/patch, native checks and the four complete reports.
|
|
588
|
+
|
|
589
|
+
## Batched prefill cohorts: corrected M4 comparison
|
|
590
|
+
|
|
591
|
+
The benchmark now also accepts `--aggregate-context <approximate tokens>` and
|
|
592
|
+
`--aggregate-stagger-ms <milliseconds>` for long, staggered HTTP requests.
|
|
593
|
+
Zero preserves the original short-prompt/simultaneous workload. Reports record
|
|
594
|
+
these settings, actual submission offsets, prompt/cache counts, first-token
|
|
595
|
+
latencies and total aggregate wall time. These workload changes must match
|
|
596
|
+
between comparison arms; the historical short-prompt numbers below use zeros.
|
|
597
|
+
|
|
598
|
+
The corrected candidate projects the forward batch before selecting each
|
|
599
|
+
sampler's logits. It is adopted in the unreleased working tree. Same machine,
|
|
600
|
+
model, protocol, settings and control as the preceding comparison, with fresh
|
|
601
|
+
control/candidate/candidate/control runs. Candidate source SHA-256
|
|
602
|
+
`84abd86ac44155298ec14cc59eeb0b51a0f1862d45e199b3597ef8a22d24a31f`.
|
|
603
|
+
All source hashes remain fixed, all preflight/save checks pass, and every arm
|
|
604
|
+
reports zero failures. Retained swap is 215 MB; the audio daemon allowance is
|
|
605
|
+
explicit, as in the preceding run.
|
|
606
|
+
|
|
607
|
+
| arm | five decode requests, total ms ↓ | cached first-token ms ↓ | B4 aggregate tok/s ↑ | ready ms | cold-start ms | peak RSS MiB |
|
|
608
|
+
|---|---:|---:|---:|---:|---:|---:|
|
|
609
|
+
| control 1 | 37,975.15 | 155.060 | 73.009 | 608.52 | 1,033.49 | 8,977.16 |
|
|
610
|
+
| candidate 1 | 37,989.93 | 154.810 | 73.042 | 608.63 | 1,029.35 | 8,980.83 |
|
|
611
|
+
| candidate 2 | 37,971.84 | 154.802 | 73.071 | 608.51 | 1,030.21 | 8,974.33 |
|
|
612
|
+
| control 2 | 37,974.80 | 154.991 | 73.003 | 609.87 | 1,027.01 | 8,954.62 |
|
|
613
|
+
|
|
614
|
+
Candidate means: decode wall **+0.016%**, cached latency **−0.142%**, aggregate
|
|
615
|
+
throughput **+0.069%**. Ready time changes by −0.102%, cold-start time by
|
|
616
|
+
−0.045%, and peak RSS by +0.130%. This is effectively flat performance for the
|
|
617
|
+
short-prompt workload, with no established speed win or strict serial dominance.
|
|
618
|
+
Long-prefill scaling remains unmeasured by this workload.
|
|
619
|
+
|
|
620
|
+
All 60 requests complete. Request bodies, token counts, usage, finish reasons
|
|
621
|
+
and completion markers match the baseline. The two candidate repeats produce
|
|
622
|
+
identical responses; the two controls do too. Three concurrent responses differ
|
|
623
|
+
between candidate and control, as in the earlier admission-only attribution.
|
|
624
|
+
Other responses match. These cross-shape text differences do not establish
|
|
625
|
+
an engine-only coding-task speedup or an all-responses-identical result.
|
|
626
|
+
The corrected same-B Qwen 27B and Gemma 12B checks include full logits,
|
|
627
|
+
token-zero sampler logits and restored continuation on both Macs.
|
|
628
|
+
|
|
629
|
+
Raw evidence: `reports/qwen38-closeout/composition-baseline/prefill-cohort/`,
|
|
630
|
+
particularly `projection-m4/`, `projection-benchmark-comparison.json`, and
|
|
631
|
+
`projection-manifest.json`. Main integration results are recorded in the manifest.
|
|
632
|
+
|
|
633
|
+
## Staggered long prefill: M4 regression
|
|
634
|
+
|
|
635
|
+
Gemma 4 12B OptiQ, M4 Pro 24 GB, Bun 1.4.2, MLX 0.32.2/native pack 0.4.0.
|
|
636
|
+
Same ordinary KV4/cache settings as the preceding corrected comparison.
|
|
637
|
+
The benchmark adds `--aggregate-context 2048 --aggregate-stagger-ms 25` and
|
|
638
|
+
uses `--workload-seed prefill-long-0`. Actual aggregate prompt counts are
|
|
639
|
+
1,289/1,281/1,287/1,287, with matching cache hits of 13/12/14/12 across all arms.
|
|
640
|
+
The target length is a character-based estimate, not a measured token count.
|
|
641
|
+
Client submission offsets are approximately 0/26/51/76 ms. Each request
|
|
642
|
+
produces 128 completion tokens. The existing prefill chunk default is 2,048.
|
|
643
|
+
|
|
644
|
+
Control source SHA-256
|
|
645
|
+
`4ab50112e6464d0d778f80398d8f61e3740c9a6dd5c3c9725f34b255c26b7711`;
|
|
646
|
+
candidate `003827c79e0bcefd65c33fe7366faa28ca60d7fd428063f6c3a159efd7a60991`.
|
|
647
|
+
Both include the same benchmark extension; inference code matches the preceding
|
|
648
|
+
control/corrected candidate respectively. All source hashes stay fixed, all
|
|
649
|
+
preflight/save checks pass, and all requests complete without failure. The
|
|
650
|
+
explicit audio allowance applies; retained swap remains 215 MB.
|
|
651
|
+
|
|
652
|
+
| arm | aggregate wall ms ↓ | aggregate tok/s ↑ | first request TTFT ms ↓ | mean request TTFT ms ↓ | peak RSS MiB |
|
|
653
|
+
|---|---:|---:|---:|---:|---:|
|
|
654
|
+
| control 1 | 25,278.61 | 20.254 | 9,007.88 | 15,911.29 | 8,947.95 |
|
|
655
|
+
| candidate 1 | 26,328.98 | 19.446 | 18,696.52 | 19,042.67 | 8,997.20 |
|
|
656
|
+
| candidate 2 | 26,543.42 | 19.289 | 18,849.50 | 19,193.88 | 9,013.50 |
|
|
657
|
+
| control 2 | 26,388.15 | 19.403 | 9,493.52 | 16,771.75 | 8,949.66 |
|
|
658
|
+
|
|
659
|
+
Candidate means show **2.333% longer aggregate wall time**, **2.324% lower
|
|
660
|
+
throughput**, **102.936% higher first-request TTFT**, and **16.992% higher mean
|
|
661
|
+
TTFT**. The controls' aggregate wall times differ by 4.4%, so the exact small
|
|
662
|
+
throughput penalty is not stable enough to generalize. The large first-request
|
|
663
|
+
latency penalty repeats clearly. Short decode request wall time changes by
|
|
664
|
+
−0.066%, and cached TTFT by −0.036%. Shared prefill has not passed long-request
|
|
665
|
+
performance acceptance. No serial deletion or default promotion follows.
|
|
666
|
+
|
|
667
|
+
Requests, usage, counts, finish reasons and completion markers match. Concurrent
|
|
668
|
+
rows 1–3 change text; other responses match, and each pair of repeated arms is
|
|
669
|
+
internally identical. This remains a comparison of identical submitted work,
|
|
670
|
+
not an all-responses-identical result or a coding-task quality assessment.
|
|
671
|
+
|
|
672
|
+
An M1 diagnostic with `MLX_BUN_P2R_TRACE=1` records the first request's internal
|
|
673
|
+
token-zero completion at about 6.25 s, but its first response write at 25.94 s.
|
|
674
|
+
The following B3 prefill chunk spans 18.25 s. This points to long preparation
|
|
675
|
+
work delaying active output, rather than admission waiting alone. It is
|
|
676
|
+
instrumented M1 attribution, not an M4 performance claim. A bounded M4 screen
|
|
677
|
+
with prefill chunks of 256 completes at 26,526.13 ms aggregate wall time and
|
|
678
|
+
19.302 tok/s, with first-request TTFT 13,235.29 ms. It improves first output
|
|
679
|
+
relative to the candidate's 2,048-token chunks but still trails the earlier
|
|
680
|
+
control. The matching 256-token control completes at 26,011.10 ms and
|
|
681
|
+
19.684 tok/s, with first-request TTFT 7,232.19 ms. The candidate therefore
|
|
682
|
+
still has 1.980% longer wall time and 83.005% higher first-request TTFT at
|
|
683
|
+
matching chunk size. Source/preflight/save checks pass with no failures.
|
|
684
|
+
Requests, usage/counts and completion markers match, but all four concurrent
|
|
685
|
+
texts differ. This one-pair screen does not qualify a default. Smaller chunks
|
|
686
|
+
change KV conversion boundaries and do not resolve the admission/work-unit
|
|
687
|
+
performance problem. Raw comparison: `long-chunk256-comparison.json` in the
|
|
688
|
+
evidence directory below.
|
|
689
|
+
|
|
690
|
+
Evidence: `reports/qwen38-closeout/composition-baseline/prefill-cohort/`,
|
|
691
|
+
including `long-m4/`, `long-benchmark-comparison.json`, and
|
|
692
|
+
`long-m1-prefill-traces.json`.
|
|
693
|
+
|
|
694
|
+
## Prefill admission work budget: M4 comparison
|
|
695
|
+
|
|
696
|
+
The isolated scheduler candidate limits admission to an existing prefill cohort
|
|
697
|
+
using initial uncached token work. Its internal budget is 2,048 tokens; a larger
|
|
698
|
+
request still enters alone and runs through the same preparation method. An
|
|
699
|
+
earlier shrinking-weight screen restored first TTFT to 9,538.63 ms but completed
|
|
700
|
+
the group in 26,797.77 ms, versus 9,012.73/25,295.58 ms in the first control,
|
|
701
|
+
and still changed three responses. The fixed-weight candidate below avoids
|
|
702
|
+
attaching another long prompt to a nearly completed request.
|
|
703
|
+
|
|
704
|
+
M4 Pro 24 GB, Gemma 4 12B OptiQ, Bun 1.4.2, MLX 0.32.2/native pack 0.4.0.
|
|
705
|
+
Same protocol and exact inputs as the preceding staggered-long comparison,
|
|
706
|
+
including KV4, prompt cache 4 GB, chunk default 2,048, 25 ms arrival spacing,
|
|
707
|
+
and `prefill-long-0`. Actual prompt/cache/output counts match. Control source
|
|
708
|
+
SHA-256 `4ab50112e6464d0d778f80398d8f61e3740c9a6dd5c3c9725f34b255c26b7711`;
|
|
709
|
+
fixed candidate `2dcee8a99708c66facd8aa296fe8b990de92eca5031453888947e9f9f35dfd72`.
|
|
710
|
+
Run order was control 1, the earlier shrinking-weight screen, fixed candidate 1,
|
|
711
|
+
fixed candidate 2, control 2. All source hashes remain fixed within their runs;
|
|
712
|
+
all preflight/save checks pass under the explicit audio-daemon allowance, with
|
|
713
|
+
215 MB retained swap and no failed requests.
|
|
714
|
+
|
|
715
|
+
| arm | aggregate wall ms ↓ | aggregate tok/s ↑ | first request TTFT ms ↓ | mean TTFT ms ↓ | five decode requests, total ms ↓ | cached TTFT ms ↓ |
|
|
716
|
+
|---|---:|---:|---:|---:|---:|---:|
|
|
717
|
+
| control 1 | 25,295.58 | 20.241 | 9,012.73 | 15,955.67 | 37,922.95 | 154.872 |
|
|
718
|
+
| candidate 1 | 25,550.88 | 20.038 | 9,031.34 | 16,089.03 | 37,960.58 | 154.755 |
|
|
719
|
+
| candidate 2 | 26,390.25 | 19.401 | 9,526.85 | 16,783.75 | 38,091.45 | 155.456 |
|
|
720
|
+
| control 2 | 26,122.33 | 19.600 | 9,289.83 | 16,519.82 | 37,973.20 | 155.051 |
|
|
721
|
+
|
|
722
|
+
All 60 responses in the four fixed-candidate/control arms match exactly, including
|
|
723
|
+
request bodies, usage/counts, finish reasons and completion markers. Candidate
|
|
724
|
+
means are +1.018% aggregate wall time, −1.007% throughput, +1.397% first-request
|
|
725
|
+
TTFT, +1.223% mean TTFT, +0.205% short decode wall and +0.093% cached TTFT.
|
|
726
|
+
This restores the large latency regression from unrestricted cohorts, but does
|
|
727
|
+
not establish strict performance dominance. Aggregate timings vary by about
|
|
728
|
+
3.3% within both candidate and control pairs. No default-speed win is claimed.
|
|
729
|
+
|
|
730
|
+
The policy is adopted in the unreleased working tree. Complete suites/types
|
|
731
|
+
and long-prefix Qwen/TurboQuant and Gemma/KV4 ownership checks pass on both
|
|
732
|
+
Macs. Main integration suite/typecheck pass.
|
|
733
|
+
A separate lifetime review found that the new loop retains unused hidden output
|
|
734
|
+
through cache maintenance, unlike the existing shared prefill primitive. Its
|
|
735
|
+
release-order screen is complete and is not adopted, as recorded below.
|
|
736
|
+
|
|
737
|
+
Evidence: `reports/qwen38-closeout/composition-baseline/prefill-cohort/`,
|
|
738
|
+
including `budget-m4/`, `budget-fixed-benchmark-comparison.json`, the earlier
|
|
739
|
+
`budget-remaining.patch`, and `budget-fixed-manifest.json`.
|
|
740
|
+
|
|
741
|
+
## Prefill early-release lifetime screen: no measured win
|
|
742
|
+
|
|
743
|
+
The candidate disposes input IDs immediately after prefill forward and unused
|
|
744
|
+
hidden output before cache maintenance. Its control is the adopted fixed-work
|
|
745
|
+
admission policy above. Same M4 Pro 24 GB, Gemma 4 12B OptiQ snapshot, Bun 1.4.2,
|
|
746
|
+
MLX 0.32.2/native pack 0.4.0 and production `bench-serve.ts all` protocol:
|
|
747
|
+
KV4, prompt cache 4 GB, 192 decode tokens, skipped context sweep,
|
|
748
|
+
`prefill-long-0`, aggregate context target 2,048 and stagger 25 ms.
|
|
749
|
+
Actual aggregate prompts/cache hits remain 1,289/13, 1,281/12, 1,287/14,
|
|
750
|
+
1,287/12, with 128 output tokens each. Control source SHA-256
|
|
751
|
+
`2dcee8a99708c66facd8aa296fe8b990de92eca5031453888947e9f9f35dfd72`;
|
|
752
|
+
candidate `46b351c3a4f4ed1442c946de388638b01611419fcc5a060c407f7a9da9584a80`.
|
|
753
|
+
|
|
754
|
+
| arm, in run order | aggregate wall ms ↓ | aggregate tok/s ↑ | first request TTFT ms ↓ | five decode requests, total ms ↓ | cached TTFT ms ↓ |
|
|
755
|
+
|---|---:|---:|---:|---:|---:|
|
|
756
|
+
| control 1 | 25,394.38 | 20.162 | 9,020.58 | 38,018.88 | 154.911 |
|
|
757
|
+
| candidate 1 | 25,537.82 | 20.049 | 9,033.96 | 37,966.96 | 154.710 |
|
|
758
|
+
| candidate 2 | 26,290.25 | 19.475 | 9,402.95 | 38,027.90 | 154.732 |
|
|
759
|
+
| control 2 | 25,888.99 | 19.777 | 9,164.43 | 38,000.93 | 154.781 |
|
|
760
|
+
|
|
761
|
+
All 60 responses, request bodies, usage/counts, finish reasons and completion
|
|
762
|
+
markers match exactly. All source/preflight/save checks pass; retained swap
|
|
763
|
+
stays at 208.25 MB under the explicit audio-daemon CPU allowance. No requests
|
|
764
|
+
fail. Candidate means are +1.062% aggregate wall time, −1.039% throughput,
|
|
765
|
+
+1.385% first TTFT, +1.366% mean TTFT, −0.033% short decode wall and
|
|
766
|
+
−0.081% cached TTFT. Aggregate run spread is 1.95% in controls and 2.95% in
|
|
767
|
+
candidates, so these small differences do not establish a causal slowdown.
|
|
768
|
+
Mean peak RSS differs by only −1.95 MB, or −0.022%, with no pressure test.
|
|
769
|
+
Cold start has a 2,132 ms first-control outlier versus roughly 1,095–1,100 ms
|
|
770
|
+
in the other three arms; its mean ratio is not evidence of a startup gain.
|
|
771
|
+
|
|
772
|
+
No speed or material measured-memory benefit is established. The candidate
|
|
773
|
+
remains isolated and is not adopted. M1 full suite/typecheck and Qwen 27B
|
|
774
|
+
same-B model/sampler/continuation checks on both Macs pass; M4 full suite and
|
|
775
|
+
typecheck were not run for this unadopted screen.
|
|
776
|
+
Evidence: `reports/qwen38-closeout/composition-baseline/prefill-cohort/`,
|
|
777
|
+
including `drain-m4/`, `drain-benchmark-comparison.json` and `drain-manifest.json`.
|
|
778
|
+
|
|
779
|
+
## MTP preparation port and compiled activation: M4 comparison
|
|
780
|
+
|
|
781
|
+
This seven-file change adds provider-owned draft prefill using the existing
|
|
782
|
+
Qwen row state and replaces the companion's unfused MLP activation with the
|
|
783
|
+
compiled SwiGLU already used by the target. The new prefill port is not yet
|
|
784
|
+
connected to shared target preparation. This HTTP comparison therefore covers
|
|
785
|
+
the activation and row-lifecycle changes, not batched MTP prefill performance.
|
|
786
|
+
The same-B pinned companion check found 11 differing bf16 output values out of
|
|
787
|
+
10,240 in one decoder continuation with the old activation, maximum absolute
|
|
788
|
+
difference 0.0078125; KV already matched. The shared compiled activation passes
|
|
789
|
+
all tested KV/full-decoder continuations at B1/B2/B3/B4 on both Macs, including
|
|
790
|
+
a 2,051-token prefix and cold/restored joins.
|
|
791
|
+
|
|
792
|
+
M4 Pro 24 GB, packed Qwen 27B Trellis interleave2 artifact and folded RTN4/g64
|
|
793
|
+
MTP companion, Bun 1.4.2, MLX 0.32.2/native pack 0.4.0. Production
|
|
794
|
+
`bench-serve.ts all`, explicit `mlx-bun` arm, MTP2, KV4, prompt cache 4 GB,
|
|
795
|
+
192 decode tokens, five decode requests, context sweep disabled, original
|
|
796
|
+
short aggregate prompts at concurrency four, seed `mtp-serving-block-0`.
|
|
797
|
+
`MLX_BUN_TURBOQUANT_FUSED_DECODE=1` and
|
|
798
|
+
`MLX_BUN_TRELLIS_ASYNC_EXPAND=0` match the preceding MTP controls.
|
|
799
|
+
Control source SHA-256
|
|
800
|
+
`2dcee8a99708c66facd8aa296fe8b990de92eca5031453888947e9f9f35dfd72`;
|
|
801
|
+
candidate `69f3f37388ca0fdda2dd836786a20cb588c947fdc476b6206d617d7312d366fa`.
|
|
802
|
+
|
|
803
|
+
| arm, in run order | five decode requests, total ms ↓ | concurrent aggregate tok/s ↑ | cached TTFT ms ↓ |
|
|
804
|
+
|---|---:|---:|---:|
|
|
805
|
+
| control 1 | 55,546.48 | 15.7645 | 99.415 |
|
|
806
|
+
| candidate 1 | 55,705.24 | 15.6455 | 99.348 |
|
|
807
|
+
| candidate 2 | 55,931.24 | 15.7543 | 96.942 |
|
|
808
|
+
| control 2 | 55,905.67 | 15.7074 | 97.644 |
|
|
809
|
+
|
|
810
|
+
All 60 request bodies, response texts, prompt/output/cache token counts,
|
|
811
|
+
finish reasons and completion markers match. Five records per candidate arm
|
|
812
|
+
have different speculation statistics; candidate repeats agree exactly, as do
|
|
813
|
+
the controls. Four of the five decode requests have changed acceptance traces,
|
|
814
|
+
and one concurrent response has changed draft/acceptance counts. This follows
|
|
815
|
+
the corrected draft arithmetic and is not identical internal work. The targets
|
|
816
|
+
still return the same text and token counts.
|
|
817
|
+
|
|
818
|
+
Descriptive candidate/control means change decode wall by +0.165%, aggregate
|
|
819
|
+
throughput by −0.229%, aggregate wall by +0.230% and cached TTFT by −0.390%.
|
|
820
|
+
Readiness and cold-start means change by +0.059% and +0.051%. Mean peak RSS is
|
|
821
|
+
14.82 MB lower, without a pressure test. All source/preflight/save checks pass
|
|
822
|
+
under the audio-daemon allowance, with no request or phase failures. Retained
|
|
823
|
+
swap grows across the runs, from 200.25 MB before the first control to 297.88 MB
|
|
824
|
+
after the final control; the environment is not a fixed zero-swap control.
|
|
825
|
+
|
|
826
|
+
No speed win, identical-work ratio or serial dominance is established. The
|
|
827
|
+
provider port and numerical correction are adopted in the unreleased working
|
|
828
|
+
tree after both-machine companion-oracle, native MTP, full-suite and typecheck
|
|
829
|
+
checks. Main integration suite/typecheck pass. Shared target/MTP prefill integration,
|
|
830
|
+
its serving/caching gates and a combined performance comparison remain open.
|
|
831
|
+
Evidence: `reports/qwen38-closeout/composition-baseline/prefill-cohort/`, including
|
|
832
|
+
`mtp-prefill-m4/`, `mtp-prefill-benchmark-comparison.json`,
|
|
833
|
+
`mtp-prefill-manifest.json`, and `mtp-prefill.patch`.
|
|
834
|
+
|
|
835
|
+
## Delayed rotating prefill: M4 regression
|
|
836
|
+
|
|
837
|
+
Gemma 4 12B OptiQ 4-bit, snapshot
|
|
838
|
+
`5b1101065d2094c8f12aa87fee80e0afa5b292b7`, on the **M4 Pro / 24 GB**.
|
|
839
|
+
Bun 1.4.2, MLX 0.32.2, native pack 0.4.0. The control is
|
|
840
|
+
`padded-partial-validation`; the candidate is `delayed-padding-validation`.
|
|
841
|
+
Both use remote HEAD `0c355f4` plus their recorded working-tree changes.
|
|
842
|
+
The production snapshots are respectively
|
|
843
|
+
`27b65281f031a4ffc4f7db057a264f32aa8bbfab70bf4c2acb357176148f38b2` and
|
|
844
|
+
`89d209400c1f683143ee9afea30e8a440ee00159fe96ba8e1c3bbe5893c744ac`.
|
|
845
|
+
|
|
846
|
+
Four alternating runs use `bun scripts/bench-serve.ts all`, the exact artifact
|
|
847
|
+
above, `--arms mlx-bun --tokens 192 --skip-context --kv-quant 4 --prompt-cache 4
|
|
848
|
+
--workload-seed delayed-padding-0 --allow-cpu-process /usr/libexec/audiomxd`.
|
|
849
|
+
All preflights pass under the authorized audio-daemon CPU allowance, with fixed
|
|
850
|
+
source in each arm and identical workload/runtime settings. All 60 request
|
|
851
|
+
bodies, response texts, usage records, token counts and finish reasons match;
|
|
852
|
+
the separate parity probes also match. No request or phase failed.
|
|
853
|
+
|
|
854
|
+
| Arm | Five decode requests, total wall ms | Cached TTFT ms | B4 aggregate tok/s | Ready ms | Cold start ms | Peak RSS MiB |
|
|
855
|
+
|---|---:|---:|---:|---:|---:|---:|
|
|
856
|
+
| Control 1 | 37,952.57 | 154.73 | 72.98 | 608.63 | 1,022.52 | 8,992.91 |
|
|
857
|
+
| Candidate 1 | 37,969.02 | 155.03 | 72.85 | 607.89 | 1,024.32 | 8,971.34 |
|
|
858
|
+
| Candidate 2 | 38,284.21 | 155.46 | 72.54 | 608.21 | 1,021.92 | 8,982.78 |
|
|
859
|
+
| Control 2 | 38,207.34 | 155.07 | 72.90 | 608.12 | 1,023.51 | 8,990.95 |
|
|
860
|
+
|
|
861
|
+
Candidate means are **0.123% higher decode wall time**, **0.222% higher cached
|
|
862
|
+
TTFT** and **0.339% lower aggregate throughput**. Both candidate aggregate
|
|
863
|
+
observations are below both controls. These are small unfavorable differences,
|
|
864
|
+
not evidence of a speed win. Readiness is in the same 200 ms polling interval;
|
|
865
|
+
this Gemma block does not resolve the separate Qwen startup/cached-latency debt.
|
|
866
|
+
|
|
867
|
+
The change adds delayed rotating-cache preparation and is retained as feature
|
|
868
|
+
work. This benchmark exercises current serving, which still prefills requests
|
|
869
|
+
separately; it does not measure the future batched-prefill path or establish
|
|
870
|
+
serial dominance. Native preparation tests cover mixed-format attention and
|
|
871
|
+
encoded state through B8, with the numerical scope documented in batching.md.
|
|
872
|
+
Raw records and comparison: `reports/qwen38-closeout/composition-baseline/delayed-padding/`.
|
|
873
|
+
|
|
874
|
+
## Recurrent padded prefill: M4 regression
|
|
875
|
+
|
|
876
|
+
Joshs-MBP-2025.local, Apple M4 Pro 24 GB, Bun 1.4.2, MLX 0.32.2/native
|
|
877
|
+
pack 0.4.0. Four alternating `bench-serve.ts all` arms use the same packed
|
|
878
|
+
Qwen KV4/MTP2, 192-token protocol above. The control includes the adopted
|
|
879
|
+
full/rotating KV padding interfaces. Sources remain fixed: control
|
|
880
|
+
`5431fdd0f20225e0493b12fb251db0b773f93d6ca92a2a5d09d64882a1161d04`,
|
|
881
|
+
candidate `98f5fb5038e3b63f3d1e28a3084f5d1da0a475aa28307761defd26f681e4eb82`.
|
|
882
|
+
Every start/end preflight passes with the audio-daemon allowance. All 60
|
|
883
|
+
requests match in request hash/body, text, complete usage/speculation counters,
|
|
884
|
+
token counts and finish reason. The separate parity probes also match. There
|
|
885
|
+
are no request or phase failures.
|
|
886
|
+
|
|
887
|
+
| Arm | Five decode requests, total ms | Cached TTFT ms | Concurrent aggregate tok/s |
|
|
888
|
+
|---|---:|---:|---:|
|
|
889
|
+
| Control 1 | 55,951.11 | 97.49 | 15.7960 |
|
|
890
|
+
| Candidate 1 | 55,713.07 | 97.38 | 15.8332 |
|
|
891
|
+
| Candidate 2 | 55,628.97 | 97.20 | 15.9066 |
|
|
892
|
+
| Control 2 | 55,639.46 | 98.99 | 15.9824 |
|
|
893
|
+
|
|
894
|
+
Candidate/control means change decode wall time by −0.223%, cached latency
|
|
895
|
+
by −0.964% and aggregate throughput by −0.122%. Candidate aggregate throughput
|
|
896
|
+
falls within the control range; cached latency is lower in both candidate arms.
|
|
897
|
+
This supports integration as a feature addition with
|
|
898
|
+
roughly flat decode/request performance, not a speedup or serial-dominance
|
|
899
|
+
claim. Peak RSS ranges from 12,161 to 12,227 MB. Readiness is
|
|
900
|
+
608/817/813/612 ms; both candidate observations fall one 200-ms polling
|
|
901
|
+
interval later. Cold start is 3,726/4,207/4,200/4,006 ms. Startup equivalence
|
|
902
|
+
remains unproven and is not covered by the flat decode conclusion.
|
|
903
|
+
|
|
904
|
+
This checks existing unpadded serving behavior. Actual padded behavior passes
|
|
905
|
+
same-B 27B logit and convolution/recurrent-state oracles on both machines,
|
|
906
|
+
including B1 and uniform/unequal B3. MTP, TurboQuant, generated RAM/SSD reuse,
|
|
907
|
+
complete suites and typechecks also pass on both Macs. True batched serving
|
|
908
|
+
prefill, delayed-codec preparation and long-pressure acceptance remain open.
|
|
909
|
+
The recurrent-padding change is adopted in the unreleased working tree.
|
|
910
|
+
Evidence: `reports/qwen38-closeout/composition-baseline/padded-ssm/`.
|
|
911
|
+
|
|
912
|
+
## Packed Qwen serial closeout on M4 Pro
|
|
913
|
+
|
|
914
|
+
Six balanced v6/v13 pairs on **Joshs-MBP-2025.local, Apple M4 Pro 24 GB**
|
|
915
|
+
complete with **114 matching paired requests and no failures**. This uses
|
|
916
|
+
Bun 1.4.0, MLX 0.32.2 and the advisory-memory candidate on `0c355f4` plus
|
|
917
|
+
its recorded patch. Source snapshot
|
|
918
|
+
`e0ebcb3fd1be6024623ffb4db08cdb5b7322a823d43df7ef1e803d11b37131b7`
|
|
919
|
+
is unchanged across all twelve runs. The packed interleaved artifact's
|
|
920
|
+
20-file manifest hashes to
|
|
921
|
+
`24c56033e1ae4c816747f763b76a7420b6327236a3736c2a89462a22e4e512ce`.
|
|
922
|
+
Preflight passes under Josh's explicit `/usr/libexec/audiomxd` CPU allowance;
|
|
923
|
+
all blocks retain their memory, swap and thermal observations.
|
|
924
|
+
|
|
925
|
+
| Metric | v6 → v13 or paired factor | 95% block interval |
|
|
926
|
+
|---|---|---|
|
|
927
|
+
| Decode request wall time | 20.507 → 17.826 seconds pooled median; **1.1504×**, or **13.08% less time** | 1.1493–1.1514× |
|
|
928
|
+
| Decode SSE-window rate | 10.026 → 11.593 tok/s pooled median; 1.1562× | 1.1557–1.1568× |
|
|
929
|
+
| Cold 1K TTFT | 1.0145× | 0.9997–1.0292×; inconclusive |
|
|
930
|
+
| Warm 1K TTFT | 1.0889× | 1.0710–1.1083× |
|
|
931
|
+
| Long-prompt TTFT | 1.0039× | 0.9995–1.0083×; inconclusive |
|
|
932
|
+
| Four queued requests, aggregate rate | 1.1464× | 1.1457–1.1470× |
|
|
933
|
+
| Peak process RSS, inverse ratio | 0.9948× | 0.9755–1.0107×; no demonstrated reduction |
|
|
934
|
+
|
|
935
|
+
Factors above one favor v13. Intervals resample the six block log-ratios of
|
|
936
|
+
within-run summaries, not the individual requests. These describe this
|
|
937
|
+
controlled session, not variation across days or p99 latency. Each run has
|
|
938
|
+
five 192-token decode requests, cold/warm prefix requests, restart restoration
|
|
939
|
+
and the four-request aggregate leg. Actual long prompts contain
|
|
940
|
+
10,397–10,399 tokens despite the synthetic `--context 16384` target. Both arms
|
|
941
|
+
use serial serving and bf16 KV; output hashes, prompt/output/reused-token
|
|
942
|
+
counts and finish reasons match throughout. The aggregate leg is queued
|
|
943
|
+
serial throughput, not evidence of simultaneous batch execution.
|
|
944
|
+
|
|
945
|
+
Final-source native checks also preserve full logits, cache state and
|
|
946
|
+
continuation at eight input lengths. Paired MTP-prefix restoration passes with
|
|
947
|
+
both bf16 and KV4 storage. Continuous and combined paired results follow below;
|
|
948
|
+
broader composed/pressure acceptance remains open; **no default is promoted by this serial result alone**.
|
|
949
|
+
Raw bundle: `reports/qwen38-closeout/m4-v6-v13-b{0..5}-v{6,13}.md.json`;
|
|
950
|
+
review and offline HTML: `m4-v6-v13-review.json`,
|
|
951
|
+
`m4-v6-v13-comparison.html`. Native evidence: `m4-final-native-runner.json`
|
|
952
|
+
and `m4-final-v13-*.log` in the same directory.
|
|
953
|
+
|
|
954
|
+
Six balanced longer-context continuous-serving pairs now pass on the same
|
|
955
|
+
M4 Pro, artifact, Bun/MLX versions and CPU allowance above. All 114 paired
|
|
956
|
+
requests match with no failures. Each run uses 256-token decode requests and
|
|
957
|
+
actual long prompts of about 20,717 tokens. The frozen source snapshot is
|
|
958
|
+
`363f74acc1e432677bfe333eec001c9111a1fb2c10128603409568f86dad58bb`.
|
|
959
|
+
The paired decode request-time factor is 1.15235×, or 13.22% less time,
|
|
960
|
+
with a 95% block interval of 1.15164–1.15316×. Four-request aggregate
|
|
961
|
+
throughput improves 2.37742×, with a 95% block interval of 2.37615–2.37856×.
|
|
962
|
+
These are same-session intervals, not across-day or sustained-load results.
|
|
963
|
+
Raw reports and review are
|
|
964
|
+
`reports/qwen38-closeout/m4-final-continuous-b{0..5}-v{6,13}.md.json`
|
|
965
|
+
and `m4-final-continuous-review.json`.
|
|
966
|
+
|
|
967
|
+
All six serial KV4 plus two-token MTP pairs with paired RAM prefixes now
|
|
968
|
+
pass, with all 114 paired requests matching and no failures. Source, host,
|
|
969
|
+
artifact and qualification match the longer-context continuous series above.
|
|
970
|
+
The paired decode request-time factor is 2.15832×, or 53.67% less time,
|
|
971
|
+
with a 95% block interval of 2.15467–2.16129×. Aggregate queued throughput
|
|
972
|
+
improves 2.07990×, with a 95% block interval of 2.07838–2.08162×. At long
|
|
973
|
+
context, decode SSE-window throughput improves 2.03668× and first-token time
|
|
974
|
+
improves 1.03885×. These compare kernel variant 13 with variant 6 while keeping
|
|
975
|
+
KV4 and MTP enabled in both arms; they do not isolate the benefit of MTP or
|
|
976
|
+
compare KV formats. All twelve restart requests reuse zero tokens: paired MTP
|
|
977
|
+
prefixes are RAM-only, so this is fresh-prefill restart measurement, not SSD
|
|
978
|
+
restoration. Raw reports and review are
|
|
979
|
+
`reports/qwen38-closeout/m4-final-kv4-mtp-b{0..5}-v{6,13}.md.json`
|
|
980
|
+
and `m4-final-kv4-mtp-review.json`. These measured settings are now selected in
|
|
981
|
+
the unreleased candidate source as documented in server-config.md; changing
|
|
982
|
+
default selection does not complete output-cache or execution consolidation.
|
|
983
|
+
|
|
984
|
+
The saved Kanban first-turn audit finds 50,479 reasoning tokens shared with
|
|
985
|
+
the next request beyond the original 2,550-token prompt. The following prompt
|
|
986
|
+
has 53,175 tokens. This is an offline tokenizer/template comparison, not a
|
|
987
|
+
performance measurement: no generated-state checkpoint has yet been accepted
|
|
988
|
+
for this saved long turn, and no saved time is claimed for it. Evidence:
|
|
989
|
+
`reports/qwen38-closeout/r17-first-tool-prefix-opportunity.json`.
|
|
990
|
+
|
|
991
|
+
## Running the benchmark
|
|
992
|
+
|
|
993
|
+
`bun scripts/bench-serve.ts all` is THE benchmark — one pass, real servers,
|
|
994
|
+
real paths, every number that matters. Per model × arm (mlx-bun@defaults ·
|
|
995
|
+
mlx-bun `--batch 1` [the control arm — `--no-serial` skips] · mlx-lm ·
|
|
996
|
+
mlx-bun-mixed · optiq-mixed) it measures decode tok/s (five fixed samples,
|
|
997
|
+
all retained; unstable runs flagged), TTFT cold (~1k, nonce-busted) and warm/cached (each stack's own
|
|
998
|
+
prompt cache), prefill tok/s, long-context prefill/TTFT/decode (ONE measured
|
|
999
|
+
prefill; decode sampled on 64 tok + 2 cached repeats), aggregate tok/s at 4
|
|
1000
|
+
concurrent streams, peak RSS (sampled; undercounts GPU), and load→ready time.
|
|
1001
|
+
The same cells compare decoded text from greedy probes of up to 64 tokens
|
|
1002
|
+
between stacks of the same scheme, including the serial control vs mlx-lm.
|
|
1003
|
+
Prompt-count inequality rejects a comparison as template/tokenizer drift;
|
|
1004
|
+
matching counts and text are a smoke check, not proof of identical token IDs
|
|
1005
|
+
or logits. Missing usage cannot produce a passing verdict. The engine's
|
|
1006
|
+
pinned logit oracle remains the correctness gate.
|
|
1007
|
+
|
|
1008
|
+
```sh
|
|
1009
|
+
bun scripts/bench-serve.ts all # cpm5 + e4b + 12B + Qwen3.8-27B, all arms
|
|
1010
|
+
bun scripts/bench-serve.ts all --no-serial # skip the --batch 1 control arm
|
|
1011
|
+
bun scripts/bench-serve.ts all --models cpm5,qwen27b # subset
|
|
1012
|
+
bun scripts/bench-serve.ts all --skip-context # drop the long-context leg
|
|
1013
|
+
bun scripts/bench-serve.ts all --context 8192 # shorter context leg
|
|
1014
|
+
```
|
|
1015
|
+
|
|
1016
|
+
For an exact local quant use `--model-path <dir>` and optionally `--label`.
|
|
1017
|
+
It replaces the registry selection and cannot be combined with `--models`.
|
|
1018
|
+
`--dry-run` prints artifact metadata and server commands, with no preflight,
|
|
1019
|
+
model load, database write or server process. Packed trellis skips stock
|
|
1020
|
+
mlx-lm/optiq arms; explicitly requesting those arms fails before starting a
|
|
1021
|
+
server. A fake-quant/8-bit carrier is a separate artifact and cannot establish
|
|
1022
|
+
same-artifact packed performance or decode parity.
|
|
1023
|
+
|
|
1024
|
+
```sh
|
|
1025
|
+
bun scripts/bench-serve.ts all --model-path /path/to/quant --label qwen38-quant --dry-run
|
|
1026
|
+
bun scripts/bench-serve.ts all --model-path /path/to/affine --arms mlx-bun-serial,mlx-lm --context 4096 --out reports/affine-h2h.md
|
|
1027
|
+
bun scripts/bench-serve.ts all --model-path /path/to/packed --arms mlx-bun-serial --context 4096 --out reports/packed-baseline.md
|
|
1028
|
+
bun scripts/bench/model-inventory.ts /path/to/affine /path/to/packed > reports/model-inventory.json
|
|
1029
|
+
```
|
|
1030
|
+
|
|
1031
|
+
`--workload-seed <block-id>` generates identical nonce-prefixed prompts for
|
|
1032
|
+
every engine and artifact in that block, with distinct nonces for retries.
|
|
1033
|
+
`--logprobs` and `--top-logprobs N` apply capture settings to every timed
|
|
1034
|
+
request, including concurrent requests, and record them in the workload and
|
|
1035
|
+
request hashes. SSE timing measures capture cost; wire-level logprob values
|
|
1036
|
+
are checked separately by the native/HTTP composition tests.
|
|
1037
|
+
Thinking is pinned on for all chat measurements. Long-context filler uses a
|
|
1038
|
+
fixed character estimate so token-count drift cannot silently change the
|
|
1039
|
+
input on one engine. Record actual token counts and compare raw request hashes.
|
|
1040
|
+
Use phase/attempt/index to distinguish a cold request from its identical warm
|
|
1041
|
+
repeat; request hashes alone do not identify cache state.
|
|
1042
|
+
For paired trials, alternate `--arms mlx-bun-serial,mlx-lm` and the reversed
|
|
1043
|
+
order across blocks; give every block its own seed and `--out` path.
|
|
1044
|
+
|
|
1045
|
+
Configured engine experiments accept `--draft-model`, `--draft-kind`,
|
|
1046
|
+
`--num-draft-tokens`, `--kv-quant`, `--prompt-cache` and `--adapter`. These options
|
|
1047
|
+
require explicit `--arms mlx-bun-serial,mlx-bun` (or either engine arm); run
|
|
1048
|
+
oracle controls separately. Both selected engine arms receive identical overrides.
|
|
1049
|
+
The dry-run, raw JSON and Markdown report retain the settings and relevant
|
|
1050
|
+
runtime overrides. No script under `reports/` is required to launch them.
|
|
1051
|
+
For the current packed Qwen artifact on the M4 Pro, run this after closing
|
|
1052
|
+
other workloads. It exercises the opt-in KV4/MTP/paired-prefix configuration
|
|
1053
|
+
through the current checkout and writes a new dated report under `reports/`.
|
|
1054
|
+
|
|
1055
|
+
```sh
|
|
1056
|
+
MLX_BUN_TRELLIS_VARIANT=13 MLX_BUN_QWEN_SPEC_KV4=1 MLX_BUN_MTP_PROMPT_CACHE=1 MLX_BUN_RD_PREFILL_CHUNK=256 \
|
|
1057
|
+
bun scripts/bench-serve.ts all \
|
|
1058
|
+
--model-path "$HOME/models/Qwen3.8-27B-q3-trellis-ldlq-k300-packed-interleave2-rd" \
|
|
1059
|
+
--arms mlx-bun-serial \
|
|
1060
|
+
--draft-model "$HOME/models/Qwen3.8-27B-MTP-folded-rtn4-g64-rd" \
|
|
1061
|
+
--draft-kind mtp --num-draft-tokens 2 --kv-quant 4 --prompt-cache 4 \
|
|
1062
|
+
--context 4096 --tokens 192 --workload-seed pr47-block-0
|
|
1063
|
+
```
|
|
1064
|
+
|
|
1065
|
+
Append `--dry-run` to inspect the command first. This serving suite is separate
|
|
1066
|
+
from the Luke Kanban task and does not establish its task-time speedup. This
|
|
1067
|
+
entry point writes Markdown plus the `<report>.md.json` companion; the offline
|
|
1068
|
+
HTML comparison report renders from saved companions:
|
|
1069
|
+
|
|
1070
|
+
```sh
|
|
1071
|
+
bun scripts/bench/report.ts reports/a.md.json reports/b.md.json --out reports/compare.html
|
|
1072
|
+
bun scripts/bench/report.ts reports/a.md.json reports/native-bun.json --out reports/compare.html --baseline mlx-bun-serial
|
|
1073
|
+
```
|
|
1074
|
+
|
|
1075
|
+
Use `--baseline mlx-bun-serial --baseline-env MLX_BUN_TRELLIS_VARIANT=6`
|
|
1076
|
+
to compare environment-selected variants of that same arm. The selected
|
|
1077
|
+
setting stays visible in both serving tables; the usual identity and workload
|
|
1078
|
+
requirements still apply.
|
|
1079
|
+
|
|
1080
|
+
Inputs are auto-detected: bench-serve schema-4 `<report>.md.json` files and
|
|
1081
|
+
`scripts/bench/native.ts` `native-inference-diagnostic` JSON. Rendering reads
|
|
1082
|
+
the saved JSON only — no weights, server, GPU, Python or network. The single
|
|
1083
|
+
self-contained file shows a provenance panel per input (file sha256, machine
|
|
1084
|
+
string, commit, Bun, runtime overrides, source snapshot hashes, server
|
|
1085
|
+
commands, workload seed, thinking mode), a per-machine serving matrix with a
|
|
1086
|
+
status on every cell (measured, recovered on retry, failed with the phase
|
|
1087
|
+
error, not-measured, or unsupported with the reason), correctness flags beside
|
|
1088
|
+
the timings (finish-reason mix, actual vs requested output counts, early EOS,
|
|
1089
|
+
warm/restart cached-token counts, durability, request errors, retries, parity
|
|
1090
|
+
verdicts), ratios only against a baseline arm on the same machine key,
|
|
1091
|
+
artifact and workload (`--baseline mlx-lm|mlx-bun-serial|mlx-bun`; default
|
|
1092
|
+
mlx-lm when present), per-machine comparison columns, decode-sample strips,
|
|
1093
|
+
an RSS-versus-decode plot, a native token-identity table, and the retained
|
|
1094
|
+
failures, stderr tails and raw request table. "decode" stays the SSE-window
|
|
1095
|
+
rate and "actual output / wall" the completion-token rate; RSS is process
|
|
1096
|
+
RSS from `ps`. The paired uncertainty table groups fixed-source trials across
|
|
1097
|
+
workload seeds and gives a 95% percentile-bootstrap interval for the geometric
|
|
1098
|
+
mean of block ratios. It resamples block log-ratios, requires at least five
|
|
1099
|
+
distinct seeds and ignores duplicate seeds. Its baseline is fixed when the
|
|
1100
|
+
report is generated. Quality-versus-size renders "not measured" until a quality
|
|
1101
|
+
input exists.
|
|
1102
|
+
|
|
1103
|
+
Request-derived speed ratios require matching request hashes, attempts, full
|
|
1104
|
+
output hashes, prompt/output and reused-token counts, and finish reasons. A mismatch keeps the
|
|
1105
|
+
absolute timings visible and suppresses the ratio. Full output hashes survive
|
|
1106
|
+
fixture trimming. Retry summaries use the final attempt; earlier samples and
|
|
1107
|
+
failures remain in the raw table. Diagnostic, nonquiet and changing-source
|
|
1108
|
+
runs cannot earn speed ratios. Cross-file comparisons require a recorded
|
|
1109
|
+
hostname, matching artifact path/config and the complete workload definition;
|
|
1110
|
+
matching config files alone do not establish matching weights. New serving
|
|
1111
|
+
companions record hostname and OS. Old files with no hostname compare only
|
|
1112
|
+
within their own file. Displayed ratios are ratios of medians, not paired
|
|
1113
|
+
confidence intervals or default-promotion evidence.
|
|
1114
|
+
|
|
1115
|
+
The bounded M1 Max smoke of this path uses MiniCPM, 16 requested decode
|
|
1116
|
+
tokens, `--skip-context`, and the unsplit reference. Both real-server arms
|
|
1117
|
+
complete without failed phases on fixed source. Warmup, the parity chat,
|
|
1118
|
+
five decode requests and the cold/warm 1K requests match full output hashes
|
|
1119
|
+
and reused-token counts. Concurrent four-request outputs still differ.
|
|
1120
|
+
Short decode timings are unstable; the run is explicitly diagnostic and
|
|
1121
|
+
cannot supply speed ratios or M4 acceptance. Raw data and review:
|
|
1122
|
+
`reports/qwen38-closeout/serve-smoke.md.json` and `serve-smoke-review.json`.
|
|
1123
|
+
The offline `comparison.html` includes this run beside both machines' saved
|
|
1124
|
+
evidence. Automated rendering/escaping checks pass; browser URL policy
|
|
1125
|
+
blocked visual inspection of the local HTML file.
|
|
1126
|
+
|
|
1127
|
+
`--reference-prefill server` keeps stock MLX-LM system/thinking segmentation
|
|
1128
|
+
and is the default. `--reference-prefill unsplit` selects an explicit Python
|
|
1129
|
+
reference control that passes one whole-prompt segment to BatchGenerator,
|
|
1130
|
+
which still reserves the final token. Tokenization, model operations,
|
|
1131
|
+
sampling and HTTP handling remain in the pinned reference. This changes
|
|
1132
|
+
prefill and cache policy and is recorded in commands, workload identity and
|
|
1133
|
+
the Markdown report. It applies to the `mlx-lm` arm, including models that
|
|
1134
|
+
need OptiQ registration. Use it only where it matches the Bun request's
|
|
1135
|
+
boundaries; it does not promise matching arbitrary multi-turn snapshots.
|
|
1136
|
+
|
|
1137
|
+
```sh
|
|
1138
|
+
bun scripts/bench-serve.ts all --models cpm5,qwen27b --arms mlx-bun,mlx-bun-serial,mlx-lm --reference-prefill unsplit --out reports/matched-prefill.md
|
|
1139
|
+
```
|
|
1140
|
+
|
|
1141
|
+
For an exclusively allocated GPU, `--allow-cpu-process /absolute/command`
|
|
1142
|
+
permits one explicitly reviewed background command to exceed the CPU
|
|
1143
|
+
threshold. The exact command and observed activity remain in the raw
|
|
1144
|
+
preflight snapshots and the report names the allowance. RSS, swap, thermal
|
|
1145
|
+
and overall-load checks still apply. This is not proof of an idle GPU or
|
|
1146
|
+
stable timing: verify GPU ownership and compare alternating repeated runs.
|
|
1147
|
+
Josh authorized this policy for `/usr/libexec/audiomxd` on the M4 Pro;
|
|
1148
|
+
CPU activity alone no longer blocks this campaign. Earlier diagnostic
|
|
1149
|
+
runs keep their original classification.
|
|
1150
|
+
|
|
1151
|
+
`--diagnostic` explicitly permits a loaded-machine serving run. It records
|
|
1152
|
+
the preflight snapshot and writes `*-serve-diagnostic` DB rows, which cannot
|
|
1153
|
+
serve as canonical results. Server children use the invoking Bun executable,
|
|
1154
|
+
so an isolated runtime comparison actually changes the server runtime too.
|
|
1155
|
+
|
|
1156
|
+
The Markdown report has a `<report>.md.json` companion containing all chat
|
|
1157
|
+
requests, results, failures and retries, plus config/source-diff hashes and
|
|
1158
|
+
server commands. Schema 4 also hashes a sorted manifest of tracked and
|
|
1159
|
+
untracked source files at startup and save time, so new local kernels cannot
|
|
1160
|
+
escape source identity. External native libraries and weights need their own
|
|
1161
|
+
manifests. Failed attempts include the child's stderr tail and process
|
|
1162
|
+
status; a successful retry keeps the recovered failure visible. It is saved
|
|
1163
|
+
after each completed or failed cell. The report
|
|
1164
|
+
separately records total request wall time and actual-output throughput.
|
|
1165
|
+
The decode columns use the first-to-last visible SSE interval: bursty chunks
|
|
1166
|
+
can distort that interval, so it is not a GPU timing. Token throughput requires
|
|
1167
|
+
valid server usage; chunk counting is no longer a fallback. Raw results also
|
|
1168
|
+
record response-header, first-byte and first-SSE-event latency, then every
|
|
1169
|
+
content/reasoning/tool-output event arrival. Event gaps measure stream
|
|
1170
|
+
delivery, not individual token latency. Tool-only streams have an output TTFT.
|
|
1171
|
+
Malformed/error SSE and responses without a finish reason or `[DONE]` fail
|
|
1172
|
+
the measurement. Match output counts, finish reasons and text before
|
|
1173
|
+
interpreting a speed difference. The exported `measureCompletionRequest`
|
|
1174
|
+
helper applies the same timing and stream-validation contract to raw
|
|
1175
|
+
`/v1/completions` requests, without chat-template preparation.
|
|
1176
|
+
|
|
1177
|
+
The inventory reads shard headers and config only, reconstructs matrix
|
|
1178
|
+
shapes including trellis axis-0 storage, and counts actual tensors rather
|
|
1179
|
+
than duplicate config aliases. Its matrix effective-bpw figure includes
|
|
1180
|
+
scales/biases but excludes norms, convolutions and sidecars; it is explicitly
|
|
1181
|
+
not whole-model bpw or peak memory. Config/index/layout hashes do not hash
|
|
1182
|
+
weight payloads. Use existing shard hashes or hash weights outside timed runs
|
|
1183
|
+
when certifying artifact identity. The complete Qwen campaign is in
|
|
1184
|
+
[the performance program](../../design/decode-speed-program.md#7-qwen38-27b-research-program).
|
|
1185
|
+
|
|
1186
|
+
For native engine isolation, `scripts/bench/native.ts` runs dense Qwen3.5/3.8
|
|
1187
|
+
with bf16 attention KV, f32 recurrent state and greedy decoding. Supply a
|
|
1188
|
+
frozen JSON array of prompt token IDs and the exact local artifact to both
|
|
1189
|
+
stacks. Each request starts with a fresh cache; warmups and every measured
|
|
1190
|
+
sample are retained. Reports include actual output IDs, EOS policy, TTFT,
|
|
1191
|
+
wall time through cache cleanup/GPU synchronization, memory and source pins.
|
|
1192
|
+
They record the effective wiring policy and active/cached memory around each
|
|
1193
|
+
request. The oracle worker enters mlx-lm's normal scoped wired limit; compare
|
|
1194
|
+
that policy with Bun's model-sized scope before interpreting a ratio.
|
|
1195
|
+
`--clear-before-request` is a separate allocator-cache experiment on both
|
|
1196
|
+
stacks, with cleanup included in wall time. Keep it fixed within a pair;
|
|
1197
|
+
it does not clear model weights or substitute for a fresh inference cache.
|
|
1198
|
+
Stock mlx-lm rejects packed trellis. This worker uses the pinned oracle
|
|
1199
|
+
environment and never starts a server or downloads a model.
|
|
1200
|
+
|
|
1201
|
+
```sh
|
|
1202
|
+
bun scripts/bench/native.ts --model-path /path/to/affine --prompt-ids reports/prompt-ids.json --stack mlx-bun --json reports/native-bun.json --dry-run
|
|
1203
|
+
bun scripts/bench/native.ts --model-path /path/to/affine --prompt-ids reports/prompt-ids.json --stack mlx-lm --json reports/native-oracle.json
|
|
1204
|
+
```
|
|
1205
|
+
|
|
1206
|
+
Alternate stack order across predeclared process pairs. Check token IDs,
|
|
1207
|
+
output counts and finish reasons before comparing request wall times.
|
|
1208
|
+
`--diagnostic` permits a failed quiet-machine preflight and records that
|
|
1209
|
+
failure. Native results remain diagnostic, including on a quiet machine;
|
|
1210
|
+
they do not establish HTTP throughput, task quality or full logit parity.
|
|
1211
|
+
The repaired legacy `bench-h2h.ts direct` command delegates to this worker,
|
|
1212
|
+
requires `--models` and bf16 KV, and writes only `*-native-diagnostic` DB
|
|
1213
|
+
rows with raw report paths. Its rates use actual emitted tokens and all
|
|
1214
|
+
fixed samples. Use the worker directly to avoid registry ambiguity.
|
|
1215
|
+
|
|
1216
|
+
`all` runs the clean-machine preflight first (refuses headline numbers from
|
|
1217
|
+
a loaded or swapped box) and holds `caffeinate` for the pass. Quotable
|
|
1218
|
+
numbers and ratios need a quiet machine; loaded runs are diagnostic only.
|
|
1219
|
+
Results land in the eval DB (`~/.cache/mlx-bun/evals.sqlite`) plus dated
|
|
1220
|
+
Markdown and JSON reports under `reports/` by default. Developer lever A/Bs are NOT benchmarks — run
|
|
1221
|
+
`scripts/bench-levers.ts <faithful-matrix|fused-prefill|compiled-decode>` or
|
|
1222
|
+
`scripts/bench-matrix.ts <modes|features>` directly when touching those paths.
|
|
1223
|
+
|
|
1224
|
+
There are **three categorically different kinds of measurement** — kept in
|
|
1225
|
+
separate sections because they answer different questions:
|
|
1226
|
+
|
|
1227
|
+
1. **Parity** — are we *bit-exact* with the upstream oracle? (pass/fail)
|
|
1228
|
+
2. **Performance** — *numbers* under like-for-like config (tok/s, memory…).
|
|
1229
|
+
3. **Quality** — for non-bit-exact optimizations, what does the speed cost
|
|
1230
|
+
in output quality? (6-test mean + KL)
|
|
1231
|
+
|
|
1232
|
+
**Default machine for older rows:** Apple M4 Pro, 24 GB unified
|
|
1233
|
+
(`Joshs-MBP-2025`), ~273 GB/s. Newer subsections name their machine explicitly.
|
|
1234
|
+
**Oracle toolchain:** Bun 1.3.14; Python 3.13.5 with mlx 0.31.2,
|
|
1235
|
+
mlx-lm 0.31.3, mlx-optiq 0.2.1. Numbers below are the 2026-06-14
|
|
1236
|
+
cleared-machine run (commits `97457e4` / `d1e0296`), preflight-gated,
|
|
1237
|
+
median-of-N with warmups discarded.
|
|
1238
|
+
|
|
1239
|
+
**Model legend** (registry hash → repo):
|
|
1240
|
+
|
|
1241
|
+
| hash | model |
|
|
1242
|
+
|---|---|
|
|
1243
|
+
| `664aabaed233` | `MiniCPM5-1B-OptiQ-4bit` (sub-GB starter) |
|
|
1244
|
+
| `fcdb12d740cd` | `gemma-4-e4b-it-OptiQ-4bit` |
|
|
1245
|
+
| `5b1101065d20` | `gemma-4-12B-it-OptiQ-4bit` |
|
|
1246
|
+
| `dbfd2a779b03` | `gemma-4-26B-A4B-it-OptiQ-4bit` (MoE) |
|
|
1247
|
+
|
|
1248
|
+
> **Legend corrected 2026-06-15.** An earlier revision had the gemma
|
|
1249
|
+
> hashes cycled (`5b…`→e4b, `dbfd…`→12B, `fcdb…`→26B). The mapping above is
|
|
1250
|
+
> the authoritative one from `tests/support/paths.ts` (`SNAPSHOT`=`5b…`=12B,
|
|
1251
|
+
> `SNAPSHOT_26B`=`dbfd…`=26B) and the e4b snapshot hash used across
|
|
1252
|
+
> `tests/*.test.ts` (`fcdb…`=e4b), corroborated by on-disk weight size
|
|
1253
|
+
> (e4b 7.0G · 12B 8.4G · 26B 18G). The **Performance** rows below were
|
|
1254
|
+
> labeled by the old legend; each gemma row has been relabeled to its true
|
|
1255
|
+
> model, re-identified by its gen-peak / steady-RSS fingerprint —
|
|
1256
|
+
> e4b≈6.6 GB, 12B≈9.0 GB, 26B≈17.7 GB — which is stable across runs. The
|
|
1257
|
+
> row *data* was correct; only the model labels moved.
|
|
1258
|
+
|
|
1259
|
+
---
|
|
1260
|
+
|
|
1261
|
+
## 1. Parity (porting correctness) — bit-exact vs the oracle
|
|
1262
|
+
|
|
1263
|
+
Parity results moved to the [current benchmark reference](../../reference/benchmarks.md).
|
|
1264
|
+
|
|
1265
|
+
### GLM-5.2 direct-Colibri oracle closure — M1 Max 32 GB
|
|
1266
|
+
|
|
1267
|
+
The direct-container port uses pinned Colibri, rather than mlx-lm, as its
|
|
1268
|
+
implementation oracle. The public artifact is
|
|
1269
|
+
`mateogrgic/GLM-5.2-colibri-int4-with-int8-mtp@3cc8db9`; direct component and
|
|
1270
|
+
G0 controls use Colibri `44e489b`, while the later official DSA replay is
|
|
1271
|
+
pinned to `ecade075` with indexers sourced from
|
|
1272
|
+
`zai-org/GLM-5.2-FP8@ba978f7d`.
|
|
1273
|
+
|
|
1274
|
+
| gate | result | durable proof |
|
|
1275
|
+
|---|---|---|
|
|
1276
|
+
| tiny converted Q4 trajectory | 32/32 greedy tokens exact with `IDOT=0`; all 8,192 logits max abs `1.3113e-6`, RMSE `2.7423e-7` | `fixtures/colibri-glm52/tiny-teacher-forcing.json` |
|
|
1277
|
+
| production Q4/router cells | layer-0 SwiGLU max abs `5.2387e-9`; layers 3/77 exact ordered top-8 | `fixtures/colibri-glm52/production-probe.json` |
|
|
1278
|
+
| real-model oracle | 140 GLM/MLA/router/MTP/KV records reproduced byte-for-byte twice; both heads predict teacher token 16 | `fixtures/colibri-glm52/real-model-oracle.json` |
|
|
1279
|
+
| full target trajectory | all 128 cold/warm, MTP-on/off target token IDs identical; first 64 also match direct Colibri | machine-local `runs/colibri-g5/summary.json` |
|
|
1280
|
+
| first-sparse DSA | all 21 official score rows replay to exact ordered positions and float32 thresholds at context 2,049; both engines emit `[264,264]` | `~/.cache/mlx-bun/evidence/glm52-dsa-stage0-2026-08-17/` |
|
|
1281
|
+
|
|
1282
|
+
These are quality-preserving gates: checkpoint precision, true top-8 routing,
|
|
1283
|
+
and the 21-full/57-shared DSA schedule remain unchanged. Consequently there is
|
|
1284
|
+
no KL/eval tradeoff row in section 3 for this path.
|
|
1285
|
+
|
|
1286
|
+
**Served-surface parity (2026-07-07, prefill tail-split fix):** the two
|
|
1287
|
+
serve-bench parity residuals (cpm5 + 12B `/v1/completions` probe ✗ on the
|
|
1288
|
+
07-07 run) are closed — with the oracle's step-0 prefill convention
|
|
1289
|
+
adopted (drain to len−1, step 0 from an L=1 forward of the last prompt
|
|
1290
|
+
token; `MLX_BUN_PREFILL_TAIL_SPLIT`), live HTTP probes are
|
|
1291
|
+
**byte-identical** to `mlx_lm.server`/optiq serve for MiniCPM5-1B,
|
|
1292
|
+
gemma-4-e4b, AND gemma-4-12B, on completion + chat probes, in both the
|
|
1293
|
+
unified (`--batch 8` default) and `--batch 1` lanes; script-level A/B
|
|
1294
|
+
shows 64/64 token ids + top-2 logprob values identical per step
|
|
1295
|
+
(`serve-parity-probe.ts (deleted; git history)`,
|
|
1296
|
+
`step0-top2-dump.ts (deleted; git history)`).
|
|
1297
|
+
|
|
1298
|
+
---
|
|
1299
|
+
|
|
1300
|
+
## Methodology change (2026-07-05)
|
|
1301
|
+
|
|
1302
|
+
The primary benchmark is now **`bun scripts/bench-serve.ts all` → `scripts/bench-serve.ts`**:
|
|
1303
|
+
real servers on real paths — the mlx-bun arms spawn the ACTUAL CLI at its
|
|
1304
|
+
actual defaults (the old harness used a bench-local wrapper, since deleted),
|
|
1305
|
+
and every metric arrives over HTTP as a user would see it. One server per
|
|
1306
|
+
cell yields: decode tok/s, cold TTFT (~1k, nonce-busted), warm/cached TTFT
|
|
1307
|
+
(each stack's own prompt cache), prefill tok/s, long-context
|
|
1308
|
+
prefill/TTFT/decode (ONE measured prefill; decode sampled on 64 tokens),
|
|
1309
|
+
aggregate tok/s at 4 concurrent streams, and load→ready time. Context
|
|
1310
|
+
lengths are recorded from usage.prompt_tokens (measured, not requested).
|
|
1311
|
+
Engine-level questions (in-process kernel parity, gen-peak memory,
|
|
1312
|
+
kill-switch A/Bs) live behind `bun scripts/bench-serve.ts all --engine`. Numbers below this
|
|
1313
|
+
note predate the redesign; the next quiet-machine pass supersedes them.
|
|
1314
|
+
|
|
1315
|
+
## 2. Performance — like-for-like numbers
|
|
1316
|
+
|
|
1317
|
+
Two comparison axes: **vs the oracles**, and **our optimized path vs our
|
|
1318
|
+
own bit-exact compat path** (does an optimization beat the baseline it
|
|
1319
|
+
diverges from). Within mlx-bun, `bf16` is the L1-compatible path and
|
|
1320
|
+
`mixed` is the L2-compatible path; both are bit-exact, so the bf16↔mixed
|
|
1321
|
+
delta is the first "our-vs-our" axis. Lab experiment rows (no external
|
|
1322
|
+
oracle; KL/eval-gated) land here once one beats the L1 baseline in a
|
|
1323
|
+
paired A/B — none recorded yet (the 2026-07-05 candidates were deleted).
|
|
1324
|
+
|
|
1325
|
+
### Default batched h2h without serial controls — M4 Pro (2026-09-11)
|
|
1326
|
+
|
|
1327
|
+
Default batched h2h moved to the [current benchmark reference](../../reference/benchmarks.md).
|
|
1328
|
+
|
|
1329
|
+
### Released v0.4.0 packed Qwen with KV4/TQ and MTP2 — M4 Pro (2026-09-11)
|
|
1330
|
+
|
|
1331
|
+
Packed Qwen cache comparison moved to the [current benchmark reference](../../reference/benchmarks.md).
|
|
1332
|
+
|
|
1333
|
+
### Released v0.4.0 standard registry comparison — M4 Pro 24 GB (2026-09-11)
|
|
1334
|
+
|
|
1335
|
+
Released standard registry comparison moved to the [current benchmark reference](../../reference/benchmarks.md).
|
|
1336
|
+
|
|
1337
|
+
### Standard serve matrix — M4 Pro 24 GB (2026-09-08, incomplete acceptance)
|
|
1338
|
+
|
|
1339
|
+
Josh ran `bun scripts/bench-serve.ts all` at clean commit `86738ac` on
|
|
1340
|
+
`Joshs-MBP-2025.local`, Apple M4 Pro, 24 GB, Bun 1.4.0, with the matching
|
|
1341
|
+
MLX 0.32.2 reference. Quiet preflight passed. There were no runtime overrides;
|
|
1342
|
+
the workload used `bench-serve-v2`, thinking enabled, five 192-token decode
|
|
1343
|
+
requests and a requested context target of 16,384. The actual context probes
|
|
1344
|
+
contained 9,062 MiniCPM tokens and 9,589 Gemma tokens. This is one ordered
|
|
1345
|
+
suite, not an alternating before/after optimization comparison.
|
|
1346
|
+
|
|
1347
|
+
| Model | Default mlx-bun decode tok/s | mlx-lm decode tok/s | Default mlx-bun request time | mlx-lm request time | Request-time reduction |
|
|
1348
|
+
|---|---:|---:|---:|---:|---:|
|
|
1349
|
+
| MiniCPM5-1B | 278.65 | 223.55 | 0.710 s | 0.936 s | 24.2% — output mismatch |
|
|
1350
|
+
| Gemma4-e4b | 57.86 | 53.63 | 3.402 s | 3.810 s | 10.7% |
|
|
1351
|
+
| Gemma4-12B | 26.14 | 25.40 | 7.576 s | 7.969 s | 4.9% |
|
|
1352
|
+
| Qwen3.8-27B 4/8-bit winner | 14.75 | 14.19 | 13.814 s | 14.523 s | 4.9% — output mismatch |
|
|
1353
|
+
|
|
1354
|
+
The table uses medians of the same five requests, all with exactly 192 output
|
|
1355
|
+
tokens. Request hashes, input/output counts and cached-token counts match
|
|
1356
|
+
between these arms. Both Gemma models also match all five timed output texts
|
|
1357
|
+
and both short parity probes. MiniCPM and Qwen differ on all five timed
|
|
1358
|
+
outputs despite matching counts; Qwen's separate 64-token probes match, while
|
|
1359
|
+
MiniCPM's chat probe diverges. Their timing rows remain observations pending
|
|
1360
|
+
the exact-token/logit investigation. The Gemma12B reference command invokes
|
|
1361
|
+
OptiQ's model registration before its mlx-lm serving path.
|
|
1362
|
+
|
|
1363
|
+
For Gemma e4b, cold/cached TTFT is 559/72 ms versus 707/212 ms in the
|
|
1364
|
+
reference, and the approximately 1K prefill estimate is 1,199 versus 947
|
|
1365
|
+
tok/s. For Gemma 12B those values are 2,531/157 ms versus 2,677/333 ms and
|
|
1366
|
+
265 versus 250 tok/s. The serial controls finish the same short requests in
|
|
1367
|
+
3.360 s and 7.514 s, respectively. Cached TTFT is one warm sample per cell.
|
|
1368
|
+
|
|
1369
|
+
Acceptance is incomplete. Qwen hits Metal out-of-memory errors in both the
|
|
1370
|
+
approximately 1K and context phases, in default and serial serving. Its
|
|
1371
|
+
reference recovers an initial 1K timeout, then fails the context phase and
|
|
1372
|
+
skips concurrency. MiniCPM and Gemma12B each report missing SSD snapshots on
|
|
1373
|
+
the first restart-flush attempt in default and mixed serving; retries succeed.
|
|
1374
|
+
Mixed-KV rows are not compared for L1 identity against bf16 KV. The complete
|
|
1375
|
+
report retains eleven phase-failure records, including recovered failures.
|
|
1376
|
+
|
|
1377
|
+
The Qwen artifact is the registry's 4/8-bit winner, not the required 12.14 GiB
|
|
1378
|
+
packed Trellis target. No MTP draft was configured. These numbers neither
|
|
1379
|
+
replace the Trellis/KV4/MTP measurements nor establish a Kanban task-time gain.
|
|
1380
|
+
Raw evidence: `reports/benchmarks-serve-2026-09-08-Joshs-MBP-2025.md` and its
|
|
1381
|
+
`.md.json` companion; source hashes are unchanged across the run.
|
|
1382
|
+
|
|
1383
|
+
The SSD follow-up at `f144516` fixes flush ordering: an ancestor removed from
|
|
1384
|
+
RAM can be covered by a longer trimmable snapshot written later in that same
|
|
1385
|
+
flush. After all writes settle, the coordinator checks committed coverage
|
|
1386
|
+
again and keeps uncovered prefixes dirty. The regression fails before the
|
|
1387
|
+
change and all 29 SSD tests pass afterward. The same M4 Pro repeats pass all
|
|
1388
|
+
phases on the first attempt for MiniCPM and Gemma12B in both default and mixed
|
|
1389
|
+
serving, restoring 9,061 and 9,588 tokens after restart. Source hashes stay
|
|
1390
|
+
fixed in both repeats. Default-arm timed request hashes and all ten output
|
|
1391
|
+
texts match the original run. The original failure records remain intact;
|
|
1392
|
+
this follow-up does not resolve their separate cross-oracle output differences.
|
|
1393
|
+
Evidence: `reports/qwen38-rd/pr47-ssd-followup.md.json` and
|
|
1394
|
+
`reports/qwen38-rd/pr47-ssd-followup-mixed.md.json`.
|
|
1395
|
+
|
|
1396
|
+
The subsequent boundary investigation identifies the timed-output difference
|
|
1397
|
+
on MiniCPM and Qwen. For each model's first saved request, Bun and Python match all 192
|
|
1398
|
+
complete native logit vectors. Stock Python HTTP instead splits at the
|
|
1399
|
+
thinking marker: MiniCPM uses prefill lengths 29, 1, 1 instead of 30, 1;
|
|
1400
|
+
Qwen uses 75, 1, 1 instead of 76, 1. Those segmented native Python runs
|
|
1401
|
+
reproduce the original reference responses after HTTP thinking-tag removal.
|
|
1402
|
+
The explicit unsplit reference control then reproduces all ten saved Bun
|
|
1403
|
+
decode responses, with identical output counts and finish reasons. Request
|
|
1404
|
+
hashes match. The first MiniCPM replay reuses zero tokens versus four in the
|
|
1405
|
+
original run; the other nine cache counts match. These are M4 Pro correctness
|
|
1406
|
+
diagnostics, not a replacement timing cohort or a speed claim. Qwen's Metal
|
|
1407
|
+
prefill failures and quiet paired timing acceptance remain open. Evidence:
|
|
1408
|
+
`reports/qwen38-closeout/prefill-segmentation-review.json` and its hashed
|
|
1409
|
+
native/HTTP companions. The initial invalid-model-ID replay is retained on
|
|
1410
|
+
the M4 Pro as `cpm5-replay-invalid-model-id.json`.
|
|
1411
|
+
|
|
1412
|
+
The Qwen memory follow-up on the same M4 Pro distinguishes a fresh-process
|
|
1413
|
+
control from the suite's retained state. The saved “1K” request actually has
|
|
1414
|
+
757 prompt tokens and succeeds after a fresh warmup. Replaying the preceding
|
|
1415
|
+
warmup, completion/chat parity probes and five decode requests with SSD cache
|
|
1416
|
+
enabled reproduces the Metal OOM on the original source. An isolated
|
|
1417
|
+
per-layer prefill-evaluation prototype passes the fresh control; its full
|
|
1418
|
+
history replay completes warmup and the raw completion probe, then times
|
|
1419
|
+
out before the parity chat finishes. SSH subsequently became unavailable
|
|
1420
|
+
and recovered without a reboot. The timeout has no resolved cause, and the
|
|
1421
|
+
prototype is not integrated. Raising the fit estimate alone does not resolve
|
|
1422
|
+
the observed OOM. Local fresh controls and recovered history trials are
|
|
1423
|
+
`reports/qwen38-closeout/qwen27b-memory-{server,barrier}-{fresh,history}.json`;
|
|
1424
|
+
the M4 keeps the history trials under the unsuffixed names. Preflight still
|
|
1425
|
+
rejects retained swap. No speed or memory improvement is accepted from
|
|
1426
|
+
these trials.
|
|
1427
|
+
|
|
1428
|
+
After the M4 reboot and unlock, the frozen candidate still fails the 1K
|
|
1429
|
+
prefill phase on both attempts. Layer evaluation gets all four cold/warm 1K
|
|
1430
|
+
requests through with the seven preceding outputs and usage unchanged, but
|
|
1431
|
+
four-request serving then fails with a Metal OOM. Reserving successor state
|
|
1432
|
+
for all batch rows gets all 15 requests through. Both changes are now in the
|
|
1433
|
+
working candidate. Twelve same-version oracle cases (prefix lengths 0/64,
|
|
1434
|
+
forward lengths 1/4/8/16/128/757) preserve complete logits, recurrent state
|
|
1435
|
+
and continuation exactly. A longer replay completes 38 requests across
|
|
1436
|
+
continuous and serial serving, including a 2,679-token context and SSD
|
|
1437
|
+
restart restoring 2,678 tokens. All 15 individually issued requests match
|
|
1438
|
+
across lanes in output and usage; the four concurrent responses differ and
|
|
1439
|
+
are excluded from cross-lane speed comparisons.
|
|
1440
|
+
|
|
1441
|
+
These remain correctness diagnostics under their original run policy.
|
|
1442
|
+
A subsequent control removes per-token memory polling from continuous
|
|
1443
|
+
decode and reserves at batch joins. It completes 19 requests with a
|
|
1444
|
+
5,239-token context and restores 5,238 tokens from SSD. The integrated
|
|
1445
|
+
reservation also accounts for cache growth to the requested output caps;
|
|
1446
|
+
its repeat preserves all 19 request identities, outputs and usage counts.
|
|
1447
|
+
Josh then clarified that the isolated audio CPU load is acceptable with
|
|
1448
|
+
memory and GPU availability; new acceptance runs record the explicit
|
|
1449
|
+
allowance described above. Earlier diagnostics are not relabeled.
|
|
1450
|
+
Evidence under `reports/qwen38-closeout/`:
|
|
1451
|
+
`m4-{candidate,layer-eval,layer-batch}-memory.md.json`,
|
|
1452
|
+
`m4-memory-review.json`, `m4-layer-state-{bun,reference,review}.json`,
|
|
1453
|
+
`m4-memory-context{.md,-review}.json`,
|
|
1454
|
+
`m4-{join-only,reserved-growth}-memory.md.json` and
|
|
1455
|
+
`m4-join-reservation-review.json`; artifact hashes are in
|
|
1456
|
+
`m4-candidate-preparation.json`. No speed default is promoted.
|
|
1457
|
+
|
|
1458
|
+
The first CPU-allowance R0 block (same M4 Pro, candidate on `0c355f4`,
|
|
1459
|
+
Bun 1.4.0, MLX 0.32.2, stock GPU ceiling, explicit unsplit reference)
|
|
1460
|
+
passes preflight before and after on fixed source. All five decode requests
|
|
1461
|
+
match across continuous Bun, serial Bun and Python in complete output,
|
|
1462
|
+
prompt/generated/reused tokens and finish reason. Within-arm decode spread
|
|
1463
|
+
is 0.49%, 1.05% and 0.78%, respectively; this is one block, not a paired
|
|
1464
|
+
speed verdict. Continuous serving completes all phases. Without the earlier
|
|
1465
|
+
context leg's server restart, serial serving fails the fourth queued request
|
|
1466
|
+
with Metal OOM. Python's 1K timeout and final aggregate failure also contain
|
|
1467
|
+
Metal OOM tracebacks, at prompt-state evaluation and pipelined decode.
|
|
1468
|
+
The earlier longer replay therefore does not close retained-history pressure.
|
|
1469
|
+
A focused allocation trace reproduces the fourth-request failure with
|
|
1470
|
+
18,783,888,604 active bytes, a four-byte allocator pool, 2,485,518,336 bytes
|
|
1471
|
+
of RAM prefixes and a 199,133,984-byte reservation against the
|
|
1472
|
+
19,069,665,280-byte GPU ceiling. The pool is not the missing memory; the
|
|
1473
|
+
remaining 86,642,692 bytes do not establish room for overlapping asynchronous
|
|
1474
|
+
state updates. A two-successor boundary reservation then completes all 30
|
|
1475
|
+
requests across both Bun lanes without failures. The 29 successful requests
|
|
1476
|
+
from R0 match output and usage; the formerly failed serial request matches
|
|
1477
|
+
the earlier context/restart control. Full-output reservation and longer
|
|
1478
|
+
generation are the next gates. Evidence:
|
|
1479
|
+
`m4-serial-allocation-probe.md.json`, `m4-serial-allocation-review.json`,
|
|
1480
|
+
`m4-two-state-memory.md.json` and `m4-two-state-memory-review.json` in
|
|
1481
|
+
`reports/qwen38-closeout/`.
|
|
1482
|
+
Raw: `reports/qwen38-closeout/m4-r0-audio-allowed-01.md.json` and
|
|
1483
|
+
`m4-r0-audio-allowed-01-review.json`.
|
|
1484
|
+
|
|
1485
|
+
### Fresh Kanban candidate generation — M4 Pro (2026-09-09)
|
|
1486
|
+
|
|
1487
|
+
The frozen optimized candidate completed the pinned Luke Kanban prompt on
|
|
1488
|
+
Joshs-MBP-2025.local (M4 Pro 24 GB, Bun 1.4.0, MLX 0.32.2, Pi 0.85.1)
|
|
1489
|
+
in **5,085.387 seconds (1h 24m 45.387s)** from prompt submission to completion.
|
|
1490
|
+
It generated 68,958 output tokens across 15 requests, with zero Pi retries,
|
|
1491
|
+
compactions or tool errors. Pi and the server exited zero; the outcome parser
|
|
1492
|
+
confirmed completion, profile requests were valid, and source hashes stayed fixed.
|
|
1493
|
+
The run used packed interleave2, variant 13, KV4, MTP depth 2 and paired RAM
|
|
1494
|
+
prefixes, with the authorized audio CPU allowance. R17 generated-history
|
|
1495
|
+
checkpointing was not implemented in this candidate.
|
|
1496
|
+
|
|
1497
|
+
The untouched generated app passes all 18 required browser acceptance categories,
|
|
1498
|
+
including native card/column dragging, combined filters, archive/restore,
|
|
1499
|
+
keyboard operation and persistence in both themes. Source hashes are unchanged. The earlier successful task generated a different number of tokens
|
|
1500
|
+
and tool turns, so this duration does not establish an engine-only speedup.
|
|
1501
|
+
The first/new runs used 75/21 tool calls, 7/0 tool errors and 1/0 compactions.
|
|
1502
|
+
Summed pre-first-output time is 3,399.895/814.988 seconds. New task time is
|
|
1503
|
+
60.2% lower and output count 47.2% lower, without an engine-only attribution.
|
|
1504
|
+
The sole initial-request difference is Pi's working-directory suffix:
|
|
1505
|
+
`kanban-final-workspace` versus `kanban-closeout-candidate-r1-workspace`,
|
|
1506
|
+
verified as five additional tokens by the model tokenizer. Both used batch 1
|
|
1507
|
+
and MTP depth 2. Detailed acceptance and comparison:
|
|
1508
|
+
`reports/qwen38-closeout/kanban-run-comparison.md`; raw evidence:
|
|
1509
|
+
`reports/qwen38-closeout/kanban-final-candidate-r1/`.
|
|
1510
|
+
|
|
1511
|
+
### Direct scheduler B=1 versus serial — both machines (2026-09-08)
|
|
1512
|
+
|
|
1513
|
+
Josh's September 8 standard suites include both default scheduling and strict
|
|
1514
|
+
serial controls. M1 Max 32 GB used clean commit `1ac8f61`; M4 Pro 24 GB used
|
|
1515
|
+
clean commit `86738ac`. Both used Bun 1.4.0, no runtime overrides, and passed
|
|
1516
|
+
quiet preflight. Compare arms within each machine; the machines have different
|
|
1517
|
+
source commits. These are single ordered suites, not alternating repeat blocks.
|
|
1518
|
+
|
|
1519
|
+
Median short-decode SSE rates from five 192-token requests per arm:
|
|
1520
|
+
|
|
1521
|
+
| Model | M1 default / serial tok/s | M4 default / serial tok/s |
|
|
1522
|
+
|---|---:|---:|
|
|
1523
|
+
| MiniCPM5-1B | 268.79 / 267.81 | 278.65 / 275.86 |
|
|
1524
|
+
| Gemma4-e4b | 63.85 / 64.01 | 57.86 / 59.03 |
|
|
1525
|
+
| Gemma4-12B | 30.33 / 30.33 | 26.14 / 26.44 |
|
|
1526
|
+
| Qwen3.8-27B 4/8-bit winner | 18.58 / 18.56 | 14.75 / 14.66 |
|
|
1527
|
+
|
|
1528
|
+
All 40 paired timed responses match between default and serial in request hash,
|
|
1529
|
+
output text, prompt/cached/generated token counts, finish reason and DONE status.
|
|
1530
|
+
Completion and chat parity probes also match for all eight model/machine cells.
|
|
1531
|
+
This comparison is between our two executors; it does not erase the separate
|
|
1532
|
+
Python-reference differences recorded in the M4 section above. Default B=1
|
|
1533
|
+
short-decode rates are within 0.4% of serial on M1 and within 2.0% on M4.
|
|
1534
|
+
The M1 suite has no phase failures. The M4 suite retains its recorded SSD retry
|
|
1535
|
+
and Qwen prefill OOM failures; short-decode agreement is not whole-suite acceptance.
|
|
1536
|
+
|
|
1537
|
+
The M1 four-request aggregate rates, default versus serial, are 408.12/243.14
|
|
1538
|
+
(MiniCPM), 101.60/60.91 (e4b), 41.32/27.95 (12B), and 20.08/15.72 (Qwen),
|
|
1539
|
+
in tok/s. These measure aggregate throughput, not single-request latency.
|
|
1540
|
+
The results support sharing a scheduler with a B=1 case; they do not establish
|
|
1541
|
+
feature completeness for replacing the dedicated executor, including MTP.
|
|
1542
|
+
Raw reports: `reports/benchmarks-serve-2026-09-08-Joshs-MacBook-Pro.md.json`
|
|
1543
|
+
and the M4's `reports/benchmarks-serve-2026-09-08-Joshs-MBP-2025.md.json`
|
|
1544
|
+
(local preserved copy: `reports/qwen38-closeout/m4-standard-20260908-original.json`).
|
|
1545
|
+
|
|
1546
|
+
### Batched logprob composition — M4 Pro, acceptance open (2026-09-09)
|
|
1547
|
+
|
|
1548
|
+
Two ordered/reversed `bench-serve.ts all` blocks use the packed interleave2
|
|
1549
|
+
Qwen artifact on Joshs-MBP-2025.local, M4 Pro 24 GB, Bun 1.4.0 and MLX
|
|
1550
|
+
0.32.2. Both pass preflight with the authorized audio CPU allowance. The
|
|
1551
|
+
frozen sampler candidate uses selected logprobs plus top-3 capture, unchanged
|
|
1552
|
+
kernels, five 192-token decode requests and the short-context suite with SSD
|
|
1553
|
+
caching. Its source predates the subsequent explicit-seed placement change;
|
|
1554
|
+
these benchmark requests have no explicit seed. Neither block has a failure.
|
|
1555
|
+
|
|
1556
|
+
| Block/order | Median decode request ms, serial / batch B=1 | Cached TTFT ms, serial / batch B=1 | Cached request ms, serial / batch B=1 |
|
|
1557
|
+
|---|---:|---:|---:|
|
|
1558
|
+
| 0, serial then batch | 17,833.47 / 17,785.57 | 261.16 / 307.45 | 800.68 / 846.69 |
|
|
1559
|
+
| 1, batch then serial | 17,840.70 / 17,771.87 | 272.90 / 319.81 | 812.66 / 858.99 |
|
|
1560
|
+
|
|
1561
|
+
All 22 single-request pairs match request/output hashes, token counts, finish
|
|
1562
|
+
reason and DONE status. Only three of eight concurrent pairs match complete
|
|
1563
|
+
outputs across serial and batch execution, so their timing does not establish
|
|
1564
|
+
an identical-work speedup. The cached response regression keeps performance
|
|
1565
|
+
acceptance open. Existing ordinary-execution M1/M4 baselines above remain valid.
|
|
1566
|
+
|
|
1567
|
+
Raw reports and review: `reports/qwen38-closeout/composition-baseline/`
|
|
1568
|
+
`logprobs-composition-{0,1}.md.json` and `logprobs-performance-review.json`.
|
|
1569
|
+
A third block enables `MLX_BUN_EARLY_FIRST_TOKEN=1` in both arms using
|
|
1570
|
+
block 0's requests. Source hashes remain fixed and no phase fails. Serial /
|
|
1571
|
+
batch B=1 median decode request time is 17,847.38 / 17,782.37 ms, cached
|
|
1572
|
+
TTFT 194.87 / 242.19 ms, and cached request time 809.63 / 860.77 ms. All
|
|
1573
|
+
15 within-block response pairs match, including the four concurrent requests.
|
|
1574
|
+
All 11 single-request outputs also match block 0; two concurrent batch outputs
|
|
1575
|
+
change with the different admission timing. Early output improves delivery in
|
|
1576
|
+
both arms but leaves the cached-request regression open. It is not a default
|
|
1577
|
+
promotion. Raw: `logprobs-early-composition-0.md.json` and
|
|
1578
|
+
`logprobs-early-performance-review.json` in the same directory.
|
|
1579
|
+
|
|
1580
|
+
Bounded P2R diagnostics there separate recurrent-boundary SSD persistence
|
|
1581
|
+
from output-delivery delay. Traced timings are diagnostic only.
|
|
1582
|
+
|
|
1583
|
+
### Shared uniform KV4 composition — M4 Pro, acceptance open (2026-09-09)
|
|
1584
|
+
|
|
1585
|
+
One ordered serial/default block uses the packed interleave2 artifact with
|
|
1586
|
+
uniform KV4, selected logprobs and top-3 capture on M4 Pro 24 GB, Bun 1.4.0,
|
|
1587
|
+
MLX 0.32.2. Both commands receive identical KV options. Preflight passes with
|
|
1588
|
+
the authorized audio allowance, source hashes stay fixed, and no phase fails.
|
|
1589
|
+
Serial / shared B=1 median decode request time is 17,866.95 / 17,814.16 ms;
|
|
1590
|
+
median SSE decode rate is 11.5556 / 11.5569 tok/s. Cached TTFT is 271.67 /
|
|
1591
|
+
292.97 ms and cached request time 813.85 / 834.49 ms. The cached latency gap
|
|
1592
|
+
keeps acceptance open; this single ordered block cannot establish stability.
|
|
1593
|
+
All 11 single-request pairs match complete responses. Only one of four
|
|
1594
|
+
concurrent pairs matches, so the aggregate timings do not establish an
|
|
1595
|
+
identical-work speedup. The frozen candidate includes the shared KV conversion
|
|
1596
|
+
and uniform placement change; later removal of an obsolete startup warning is
|
|
1597
|
+
not part of this source snapshot.
|
|
1598
|
+
|
|
1599
|
+
Raw: `reports/qwen38-closeout/composition-baseline/`
|
|
1600
|
+
`uniform-kv4-composition-0.md.json` and `uniform-kv4-performance-review.json`.
|
|
1601
|
+
|
|
1602
|
+
### Immutable RAM prefix prototype — M4 Pro (2026-09-09)
|
|
1603
|
+
|
|
1604
|
+
The first borrowed-prefix prototype uses the same packed artifact, selected
|
|
1605
|
+
logprobs/top-3, SSD cache and workload as logprob block 0 above. On M4 Pro
|
|
1606
|
+
24 GB, Bun 1.4.0, MLX 0.32.2, preflight passes with the authorized audio CPU
|
|
1607
|
+
allowance. Source hashes remain fixed and no phase fails. Serial / shared
|
|
1608
|
+
B=1 median decode request time is 17,874.77 / 17,758.63 ms, cached TTFT
|
|
1609
|
+
256.93 / 168.77 ms and cached request time 796.78 / 707.51 ms.
|
|
1610
|
+
|
|
1611
|
+
All 11 single-request pairs match. Every output within each arm also matches
|
|
1612
|
+
that arm in original logprob block 0. Two of four concurrent pairs match
|
|
1613
|
+
across arms; aggregate timings do not establish identical-work performance.
|
|
1614
|
+
This prototype still makes serial requests flush durability before generation.
|
|
1615
|
+
The later removal of that flush must be measured in both arms before claiming
|
|
1616
|
+
that shared B=1 dominates the best serial implementation.
|
|
1617
|
+
|
|
1618
|
+
Raw: `reports/qwen38-closeout/composition-baseline/`
|
|
1619
|
+
`borrowed-prefix-composition-0.md.json` and
|
|
1620
|
+
`borrowed-prefix-performance-review.json`.
|
|
1621
|
+
|
|
1622
|
+
### Eventual SSD persistence — M4 Pro, acceptance open (2026-09-09)
|
|
1623
|
+
|
|
1624
|
+
The next frozen candidate retains immutable RAM prefixes and removes the
|
|
1625
|
+
serial request-time durability flush. It uses the same machine, toolchain,
|
|
1626
|
+
artifact, capture settings and block-0 workload as the prototype above.
|
|
1627
|
+
Preflight passes with the audio allowance, source hashes remain fixed and
|
|
1628
|
+
there are no failures. Serial / shared B=1 median decode request time is
|
|
1629
|
+
17,768.44 / 17,787.02 ms, cached TTFT 163.57 / 168.03 ms and cached request
|
|
1630
|
+
time 703.55 / 706.67 ms. All 11 single-request pairs match, and every output
|
|
1631
|
+
within each arm matches original logprob block 0. Two of four concurrent
|
|
1632
|
+
pairs match across arms.
|
|
1633
|
+
|
|
1634
|
+
This removes the large cached-request regression in the earlier logprob
|
|
1635
|
+
comparisons. One ordered block does not establish that the remaining small
|
|
1636
|
+
difference is stable or that shared B=1 dominates serial. A subsequent change
|
|
1637
|
+
makes background writes acquire idle ownership without requesting a batch
|
|
1638
|
+
drain; its balanced serving comparisons are separate acceptance work.
|
|
1639
|
+
|
|
1640
|
+
Raw: `reports/qwen38-closeout/composition-baseline/`
|
|
1641
|
+
`eventual-cache-composition-0.md.json` and
|
|
1642
|
+
`eventual-cache-performance-review.json`.
|
|
1643
|
+
|
|
1644
|
+
### Idle persistence queue on Bun 1.4.2 — M4 Pro (2026-09-09)
|
|
1645
|
+
|
|
1646
|
+
Two ordered/reversed blocks measure immutable RAM reuse, removal of the
|
|
1647
|
+
request-time flush, and background writes that acquire the engine only when
|
|
1648
|
+
idle. Both use the packed Qwen artifact, bf16 KV, selected logprobs/top-3,
|
|
1649
|
+
SSD caching and the same block-0 requests. M4 Pro 24 GB, Bun 1.4.2, MLX
|
|
1650
|
+
0.32.2; preflight passes under the audio allowance. The source hash is identical
|
|
1651
|
+
across both blocks and remains fixed; neither block has a failure.
|
|
1652
|
+
|
|
1653
|
+
| Order | Median decode request ms, serial / shared B=1 | Cached TTFT ms, serial / shared B=1 | Cached request ms, serial / shared B=1 |
|
|
1654
|
+
|---|---:|---:|---:|
|
|
1655
|
+
| Serial then batch | 17,772.00 / 17,750.51 | 163.13 / 167.44 | 703.25 / 706.08 |
|
|
1656
|
+
| Batch then serial | 17,746.81 / 17,757.96 | 162.87 / 167.51 | 701.86 / 706.03 |
|
|
1657
|
+
|
|
1658
|
+
All 22 single-request pairs match complete response identity. Every output
|
|
1659
|
+
within each arm also matches original logprob block 0. Four of eight concurrent
|
|
1660
|
+
pairs match across arms, so aggregate timing does not establish identical-work
|
|
1661
|
+
performance. Decode request time differs by less than 0.13%, while shared B=1
|
|
1662
|
+
retains a consistent 4.3–4.6 ms cached first-output gap. Strict dominance is
|
|
1663
|
+
still unproven. The later correction to the batch's reported first-token
|
|
1664
|
+
clock is not included; these numbers come from client-observed timings.
|
|
1665
|
+
|
|
1666
|
+
Raw: `reports/qwen38-closeout/composition-baseline/`
|
|
1667
|
+
`idle-persistence-bun142-composition-{0,1}.md.json` and
|
|
1668
|
+
`idle-persistence-bun142-performance-review.json`.
|
|
1669
|
+
|
|
1670
|
+
### First-admission device pipeline — M4 Pro (2026-09-09)
|
|
1671
|
+
|
|
1672
|
+
The first ordinary row now enters the existing pending GPU-token register,
|
|
1673
|
+
allowing the next forward to overlap its first readback. This also includes
|
|
1674
|
+
the corrected first-token metric timestamp. The frozen candidate was measured
|
|
1675
|
+
in both arm orders on M4 Pro 24 GB, Bun 1.4.2 and MLX 0.32.2, using the same
|
|
1676
|
+
packed artifact, bf16 KV, logprobs/top-3, SSD and block-0 requests as the
|
|
1677
|
+
idle-persistence comparison. Both preflights pass with the audio allowance,
|
|
1678
|
+
source stays fixed across both blocks and no phase fails.
|
|
1679
|
+
|
|
1680
|
+
| Arm order | Decode request median ms, serial / shared B=1 | Cached TTFT ms, serial / shared B=1 | Cached request ms, serial / shared B=1 |
|
|
1681
|
+
|---|---:|---:|---:|
|
|
1682
|
+
| Serial first | 17,759.74 / 17,745.59 | 163.25 / 163.38 | 703.29 / 701.71 |
|
|
1683
|
+
| Shared first | 17,754.03 / 17,746.97 | 162.61 / 163.53 | 701.91 / 702.64 |
|
|
1684
|
+
|
|
1685
|
+
All 22 single-request pairs match, and every output within each arm matches
|
|
1686
|
+
the idle-persistence baseline. Four of eight concurrent pairs match across
|
|
1687
|
+
arms; these do not support an identical-work aggregate speed claim. The
|
|
1688
|
+
change reduces the prior cached-TTFT gap to 0.12–0.91 ms and is adopted in
|
|
1689
|
+
the working tree. Shared B=1 does not strictly dominate every measured
|
|
1690
|
+
latency, and this composition does not close the full feature matrix.
|
|
1691
|
+
|
|
1692
|
+
Raw: `reports/qwen38-closeout/composition-baseline/`
|
|
1693
|
+
`first-row-pipeline-composition-{0,1}.md.json` and corresponding
|
|
1694
|
+
`first-row-pipeline-composition-{0,1}-review.json`. Both blocks identify source
|
|
1695
|
+
`5cd1cb0668b743303cd6b05ba8779fd9075280d97585b008ac2da9d03f462c7f`.
|
|
1696
|
+
|
|
1697
|
+
### Batched sliding-window correctness — M1 Max and M4 Pro (2026-09-09)
|
|
1698
|
+
|
|
1699
|
+
The shared executor passes the live, pinned same-B MLX-LM oracle on Gemma
|
|
1700
|
+
12B and e4b on both M1 Max 32 GB and M4 Pro 24 GB, with Bun 1.4.2 and
|
|
1701
|
+
MLX 0.32.2. Each cell compares 48 complete float32 logit vectors exactly.
|
|
1702
|
+
Three unequal prompt lengths straddle the configured sliding window: two
|
|
1703
|
+
cross it during decode and one starts beyond it. The two arrival schedules
|
|
1704
|
+
include staggered retirement and a late join. This closes Phase 18's ordinary
|
|
1705
|
+
Gemma ring-wrap gate; it does not qualify quantized layouts or other methods.
|
|
1706
|
+
|
|
1707
|
+
Raw: `reports/qwen38-closeout/composition-baseline/`
|
|
1708
|
+
`m1-gemma12b-batch-ring-wrap.log`,
|
|
1709
|
+
`m4-gemma12b-batch-ring-wrap-complete-inputs.log`,
|
|
1710
|
+
`m1-gemmae4b-batch-ring-wrap.log`, and
|
|
1711
|
+
`m4-gemmae4b-batch-ring-wrap.log`. The first M4 launch failed before model
|
|
1712
|
+
loading because its scratch checkout lacked test support files; the complete
|
|
1713
|
+
input rerun is the accepted result. No performance conclusion uses test time.
|
|
1714
|
+
|
|
1715
|
+
### Compatible adapter groups — M4 Pro (2026-09-09)
|
|
1716
|
+
|
|
1717
|
+
Gemma e4b OptiQ snapshot `98d7dc6`, `fixtures/adapters/upper`, bf16 KV and
|
|
1718
|
+
SSD cache, on M4 Pro 24 GB with Bun 1.4.2 and MLX 0.32.2. The configured
|
|
1719
|
+
adapter and block-0 requests are identical across the serial and shared arms.
|
|
1720
|
+
Both arm orders pass preflight with the recorded audio allowance, retain a
|
|
1721
|
+
fixed source, and finish every phase.
|
|
1722
|
+
|
|
1723
|
+
| Arm order | Decode request median ms, serial / shared B=1 | Cached TTFT ms, serial / shared B=1 | Cached request ms, serial / shared B=1 | Observed four-request throughput tok/s, serial / shared |
|
|
1724
|
+
|---|---:|---:|---:|---:|
|
|
1725
|
+
| Serial first | 3,654.29 / 3,671.12 | 36.88 / 37.66 | 162.18 / 161.73 | 51.76 / 161.42 |
|
|
1726
|
+
| Shared first | 3,678.68 / 3,675.22 | 37.58 / 37.96 | 162.13 / 161.98 | 51.82 / 161.27 |
|
|
1727
|
+
|
|
1728
|
+
All 22 single-request output/usage pairs match. Six of eight concurrent
|
|
1729
|
+
pairs match across arms; every output is stable within its own arm across
|
|
1730
|
+
orders. The concurrent throughput figures therefore are observed workload
|
|
1731
|
+
results, not an identical-output speedup. Single-request decode changes winner
|
|
1732
|
+
with order; cached first output remains slightly slower on the shared path.
|
|
1733
|
+
Strict serial-dominance acceptance remains open.
|
|
1734
|
+
|
|
1735
|
+
Native adapter B=1 control, compatible B=2, mixed queues, callback failure,
|
|
1736
|
+
separate prefix reuse and queued adapter replacement pass on M1/M4. Both
|
|
1737
|
+
machines match 48 full logit vectors against the pinned same-B adapter oracle.
|
|
1738
|
+
KV4 plus logprobs also passes the native composition checks on both machines;
|
|
1739
|
+
this is not an external quantized-batch oracle claim.
|
|
1740
|
+
|
|
1741
|
+
Raw: `reports/qwen38-closeout/composition-baseline/`
|
|
1742
|
+
`adapter-composition-{0,1}.md.json` and
|
|
1743
|
+
`adapter-composition-performance-review.json`. Frozen source:
|
|
1744
|
+
`e92487827cbb4755f5bd0cb4880999b2aa1d1aba64a86b7bfc6042b0b458723c`.
|
|
1745
|
+
Native logs: `m1-batch-adapters-replacement.log`,
|
|
1746
|
+
`m1-batch-adapter-oracle.log`, `m4-batch-adapters-oracle.log`, and
|
|
1747
|
+
`{m1,m4}-batch-adapters-kv4-logprobs.log`.
|
|
1748
|
+
|
|
1749
|
+
|
|
1750
|
+
### State-only recurrent replay experiment — M4 Pro (2026-09-09)
|
|
1751
|
+
|
|
1752
|
+
Packed Qwen 27B with its folded RTN4 MTP companion, depth four and KV4,
|
|
1753
|
+
Bun 1.4.2 and MLX 0.32.2 on the M4 Pro 24 GB. Both versions use the same
|
|
1754
|
+
serial serving control and shared prefill cache. Only recurrent prefix replay
|
|
1755
|
+
changes. The existing serving suite ran reference/candidate, then
|
|
1756
|
+
candidate/reference, with matched requests within each block. Preflight passed
|
|
1757
|
+
under Josh's audio-daemon CPU allowance; raw reports retain `canonical:false`.
|
|
1758
|
+
|
|
1759
|
+
| Block/order | Five decode requests, reference → candidate | Sum of four queued request times, reference → candidate | Cached TTFT, reference → candidate |
|
|
1760
|
+
|---|---:|---:|---:|
|
|
1761
|
+
| 0, reference/candidate | 135,674.99 → 135,614.72 ms | 176,655.25 → 176,192.41 ms | 94.03 → 94.10 ms |
|
|
1762
|
+
| 1, candidate/reference | 130,083.45 → 129,893.97 ms | 189,279.10 → 189,066.15 ms | 93.98 → 93.78 ms |
|
|
1763
|
+
|
|
1764
|
+
All 30 recorded responses match in text, counts, cached coverage and finish
|
|
1765
|
+
reason; both completion/chat probes match and no phase failed. The five-request
|
|
1766
|
+
decode totals improve by only 0.044% and 0.146%. Warmup complete time regresses
|
|
1767
|
+
in both blocks, by 8.41% and 0.32%. This is **inconclusive for default promotion**.
|
|
1768
|
+
The independently required batched recurrence can use its row-length-aware
|
|
1769
|
+
kernel; uniform replay retains its existing kernel pending a demonstrated win.
|
|
1770
|
+
|
|
1771
|
+
Raw files: `reports/qwen38-closeout/composition-baseline/`
|
|
1772
|
+
`state-replay-{reference,candidate}-{0,1}.md.json` and
|
|
1773
|
+
`state-replay-performance-review.json`. Both sources stay fixed across blocks:
|
|
1774
|
+
reference `a01bee0b7e1962c8211f1ffd845d95f7923d6c04bddb18cf06f07483cab9e7e8`,
|
|
1775
|
+
candidate `9ea170f63a70b143a978fd2f8519c265a363760fcc5921ab7fe7c51f6ff2a173`.
|
|
1776
|
+
These reports measure the isolated replay experiment, not the subsequent
|
|
1777
|
+
attention-cache and draft-interface work.
|
|
1778
|
+
|
|
1779
|
+
|
|
1780
|
+
### Shared MTP drafting candidate — M4 Pro (2026-09-09)
|
|
1781
|
+
|
|
1782
|
+
Packed Qwen 27B, folded RTN4 companion, MTP depth two, KV4, Bun 1.4.2 and
|
|
1783
|
+
MLX 0.32.2 on the M4 Pro 24 GB. The candidate replaces the request-local
|
|
1784
|
+
draft/commit loop with the shared row method at B=1. Both use the existing
|
|
1785
|
+
serving control and shared prefill cache. The official serving suite ran in
|
|
1786
|
+
both orders with 192-token decode requests. Preflight passed under Josh's
|
|
1787
|
+
audio-daemon CPU allowance; reports retain `canonical:false`.
|
|
1788
|
+
|
|
1789
|
+
| Block/order | Five decode requests, reference → candidate | Sum of four queued request times, reference → candidate |
|
|
1790
|
+
|---|---:|---:|
|
|
1791
|
+
| 0, reference/candidate | 53,764.24 → 53,884.42 ms | 80,319.89 → 81,191.39 ms |
|
|
1792
|
+
| 1, candidate/reference | 56,025.69 → 56,363.44 ms | 78,935.80 → 81,001.15 ms |
|
|
1793
|
+
|
|
1794
|
+
All 30 recorded request hashes, response hashes, token counts, cached coverage
|
|
1795
|
+
and finish reasons match, with no failures and unchanged source snapshots.
|
|
1796
|
+
Decode complete time regresses by 0.22% and 0.60%; summed queued-request time
|
|
1797
|
+
regresses by 1.09% and 2.62%. The four-request 1k-context phase also regresses,
|
|
1798
|
+
by 2.09% and 3.04%. This candidate has not established equal-or-better serving
|
|
1799
|
+
performance and is not adopted. Native before/after prefix continuations match
|
|
1800
|
+
on both Macs; those correctness results do not close the timing gate.
|
|
1801
|
+
|
|
1802
|
+
Raw: `reports/qwen38-closeout/composition-baseline/`
|
|
1803
|
+
`mtp-row-{reference,candidate}-{0,1}.md.json` and
|
|
1804
|
+
`mtp-shared-draft-performance-review.json`. Frozen source hashes:
|
|
1805
|
+
reference `a0f66ee4bbf357cdd7ace981e31c4f21d8e1705b7f052e5bd6ce0b8bccf68ab5`,
|
|
1806
|
+
candidate `dcaf122ce30b38e60847af6c0fd4df59232ccb2552ec7fb98019d231e1757b75`.
|
|
1807
|
+
Four queued requests here still execute one at a time; this is not B=4 MTP
|
|
1808
|
+
serving acceptance.
|
|
1809
|
+
|
|
1810
|
+
The subsequent candidate replaces the B=1 hidden gather with a slice of the
|
|
1811
|
+
same verification context. On the same machine/toolchain and settings, two
|
|
1812
|
+
new matched blocks preserve all 30 responses, counts, cached coverage and
|
|
1813
|
+
finish reasons, plus both parity probes, with no failures or source changes.
|
|
1814
|
+
|
|
1815
|
+
| Block/order | Five decode requests, reference → slice candidate | Sum of four queued request times, reference → slice candidate | Cached TTFT, reference → slice candidate |
|
|
1816
|
+
|---|---:|---:|---:|
|
|
1817
|
+
| 0, candidate/reference | 56,802.25 → 56,806.30 ms | 83,579.51 → 82,931.12 ms | 93.85 → 93.78 ms |
|
|
1818
|
+
| 1, reference/candidate | 55,672.47 → 56,315.67 ms | 80,785.87 → 82,545.85 ms | 93.54 → 94.80 ms |
|
|
1819
|
+
|
|
1820
|
+
The first block's decode time is essentially flat; the reverse-order block
|
|
1821
|
+
regresses by 1.16%. Queued-request gains also reverse, and the 1k-context phase
|
|
1822
|
+
changes by -0.57% then +2.34%. This does not close the performance gate. The
|
|
1823
|
+
source replacement and slice specialization remain isolated. Do not attribute
|
|
1824
|
+
the full variation to the gather or claim a speedup from the first block.
|
|
1825
|
+
|
|
1826
|
+
Raw: `mtp-slice-{reference,candidate}-{0,1}.md.json` and
|
|
1827
|
+
`mtp-slice-performance-review.json` in the same report directory. Reference
|
|
1828
|
+
hash is unchanged; slice candidate hash is
|
|
1829
|
+
`665acf5432f5cde64207a475edff0f999215f2fb9df014fce8db295e6cc20bd9`.
|
|
1830
|
+
|
|
1831
|
+
### Concurrent MTP serving candidate — M4 Pro (2026-09-09)
|
|
1832
|
+
|
|
1833
|
+
Packed Qwen 27B, folded RTN4 companion, MTP depth two and KV4, Bun 1.4.2
|
|
1834
|
+
and MLX 0.32.2 on the M4 Pro 24 GB. The existing serving suite compares
|
|
1835
|
+
strict serial with shared execution in both arm orders. Each block uses
|
|
1836
|
+
matched requests and a fixed source, with 192-token decode requests and no
|
|
1837
|
+
long-context leg. Preflight passes under the recorded audio CPU allowance.
|
|
1838
|
+
|
|
1839
|
+
| Arm order | Five decode requests, serial / shared | Cached TTFT, serial / shared | Observed four-request throughput, serial / shared |
|
|
1840
|
+
|---|---:|---:|---:|
|
|
1841
|
+
| Serial first | 56,130.19 / 55,549.00 ms | 93.58 / 214.00 ms | 15.88 / 16.18 tok/s |
|
|
1842
|
+
| Shared first | 54,137.25 / 53,914.05 ms | 93.63 / 218.90 ms | 16.08 / 16.41 tok/s |
|
|
1843
|
+
|
|
1844
|
+
All 22 single-request output/usage pairs and both parity probes match, with
|
|
1845
|
+
no phase failures. Single-request decode totals improve by 1.04% and 0.41%,
|
|
1846
|
+
but cached first output regresses in both orders. This does not meet serial
|
|
1847
|
+
dominance and is not adopted. Seven of eight concurrent outputs differ across
|
|
1848
|
+
arms, so aggregate throughput is an observed result, not an identical-output
|
|
1849
|
+
speed ratio. The separate native/HTTP gate confirms real B=4 MTP verification.
|
|
1850
|
+
|
|
1851
|
+
The next revision exposes preparation output through the shared scheduling
|
|
1852
|
+
readiness interface. Scheduling yields after admission completes, before the
|
|
1853
|
+
next graph. The same two arm orders give:
|
|
1854
|
+
|
|
1855
|
+
| Arm order | Five decode requests, serial / shared | Cached TTFT, serial / shared | Observed four-request throughput, serial / shared |
|
|
1856
|
+
|---|---:|---:|---:|
|
|
1857
|
+
| Serial first | 56,583.61 / 55,563.91 ms | 93.64 / 98.28 ms | 15.52 / 16.21 tok/s |
|
|
1858
|
+
| Shared first | 54,175.23 / 53,514.51 ms | 93.48 / 99.70 ms | 16.09 / 16.19 tok/s |
|
|
1859
|
+
|
|
1860
|
+
All 22 single-request pairs match, with no phase failures. Decode totals
|
|
1861
|
+
improve by 1.80% and 1.22%. The remaining cached TTFT gap is 4.64 and 6.22 ms,
|
|
1862
|
+
so strict serial dominance remains open. Seven of eight concurrent outputs
|
|
1863
|
+
again differ, preventing an identical-output aggregate speed claim.
|
|
1864
|
+
Moving publication ahead of the remaining state admission gives these results:
|
|
1865
|
+
|
|
1866
|
+
| Arm order | Five decode requests, serial / shared | Cached TTFT, serial / shared | Observed four-request throughput, serial / shared |
|
|
1867
|
+
|---|---:|---:|---:|
|
|
1868
|
+
| Serial first | 56,139.21 / 55,564.02 ms | 93.64 / 97.75 ms | 15.76 / 16.24 tok/s |
|
|
1869
|
+
| Shared first | 54,122.55 / 54,352.40 ms | 93.60 / 100.76 ms | 16.09 / 15.89 tok/s |
|
|
1870
|
+
|
|
1871
|
+
All 22 single-request pairs still match, with no failures. Decode totals change
|
|
1872
|
+
by -1.02% and +0.42%; the cached first-output gap remains. Seven concurrent
|
|
1873
|
+
outputs differ. This revision also does not establish dominance. The next
|
|
1874
|
+
candidate removes allocator cache clearing from shared output delivery while
|
|
1875
|
+
preserving the methods' own maintenance. It also fixes cleanup after state
|
|
1876
|
+
admission. Its two arm orders produce:
|
|
1877
|
+
|
|
1878
|
+
| Arm order | Five decode requests, serial / shared | Cached TTFT, serial / shared | Observed four-request throughput, serial / shared |
|
|
1879
|
+
|---|---:|---:|---:|
|
|
1880
|
+
| Serial first | 56,857.65 / 55,535.73 ms | 94.48 / 99.33 ms | 15.50 / 16.24 tok/s |
|
|
1881
|
+
| Shared first | 54,107.37 / 53,587.76 ms | 93.70 / 98.99 ms | 16.09 / 16.16 tok/s |
|
|
1882
|
+
|
|
1883
|
+
All 22 single-request pairs and parity probes match, with no failures. Decode
|
|
1884
|
+
totals improve by 2.32% and 0.96%, but cached TTFT trails serial by 4.85 and
|
|
1885
|
+
5.28 ms. Seven concurrent outputs differ. Allocator maintenance separation
|
|
1886
|
+
therefore does not resolve the latency gap or qualify serial removal.
|
|
1887
|
+
|
|
1888
|
+
Raw reports and reviews in
|
|
1889
|
+
`reports/qwen38-closeout/composition-baseline/`:
|
|
1890
|
+
`mtp-serving-serial-shared-0.md.json`, `mtp-serving-shared-serial-1.md.json`,
|
|
1891
|
+
`mtp-serving-performance-review.json`, `mtp-serving-output-yield-0.md.json`,
|
|
1892
|
+
`mtp-serving-output-yield-1.md.json` and
|
|
1893
|
+
`mtp-serving-output-yield-performance-review.json`, `mtp-serving-staged-0.md.json`,
|
|
1894
|
+
`mtp-serving-staged-1.md.json`, `mtp-serving-staged-performance-review.json`,
|
|
1895
|
+
`mtp-serving-method-maintenance-0.md.json`, `mtp-serving-method-maintenance-1.md.json`
|
|
1896
|
+
and `mtp-serving-method-maintenance-performance-review.json`.
|
|
1897
|
+
Initial frozen source:
|
|
1898
|
+
`4799c307be193a2cd53c91d95940c40e7294f41b13a07693ab4a45097be60d25`.
|
|
1899
|
+
First readiness revision:
|
|
1900
|
+
`e7d6955ea0ae8133b6445a5180fd68a784c8913072a13579f08392896cff8904`.
|
|
1901
|
+
Staged admission revision:
|
|
1902
|
+
`309d671bdcdd4830765d6af2341fe3b68a04c2eb9795929f9d6bcfb12f55e04d`.
|
|
1903
|
+
Method-owned maintenance revision:
|
|
1904
|
+
`311043d3a1add4bebffffc820a96f83dc415ad3ac6d6a17133e75540909ff273`.
|
|
1905
|
+
|
|
1906
|
+
The subsequent combined source includes the TurboQuant codec/row components.
|
|
1907
|
+
The first matched block keeps KV4/MTP2, so it measures overhead in the existing
|
|
1908
|
+
workload rather than TurboQuant serving. Compared directly with the previous
|
|
1909
|
+
method-maintenance block on the same M4:
|
|
1910
|
+
|
|
1911
|
+
| Metric | Previous shared | Combined shared |
|
|
1912
|
+
|---|---:|---:|
|
|
1913
|
+
| Five decode requests, complete time | 55,535.73 ms | 55,560.29 ms |
|
|
1914
|
+
| Median decode | 19.211 tok/s | 19.196 tok/s |
|
|
1915
|
+
| Cached TTFT | 99.33 ms | 99.55 ms |
|
|
1916
|
+
| Four concurrent requests | 16.238 tok/s | 16.241 tok/s |
|
|
1917
|
+
|
|
1918
|
+
All 15 shared request/output/usage pairs match, as do all 15 serial-control
|
|
1919
|
+
pairs. Shared decode time changes by +0.044%; this is effectively unchanged,
|
|
1920
|
+
not a demonstrated speed gain. The serial control changes by -0.94%. No phase
|
|
1921
|
+
fails and the combined source stays fixed. This is one arm-order block;
|
|
1922
|
+
the reverse-order repeat remains open. The first settings sweep follows.
|
|
1923
|
+
Raw report: `decode-composition-combined-0.md.json`; review:
|
|
1924
|
+
`decode-composition-previous-run-review.json`, in the same reports directory.
|
|
1925
|
+
Combined source:
|
|
1926
|
+
`2b7b258c983729be4dc723493ad6a14eea853c0166df9f2a36a4a3b27344f51c`.
|
|
1927
|
+
|
|
1928
|
+
The first settings sweep uses that same frozen source, the same block-0
|
|
1929
|
+
requests and the shared server. Each row includes five 192-token decode
|
|
1930
|
+
requests, short cold/cached prompts and four concurrent requests. Long-context
|
|
1931
|
+
and restart benchmark legs are excluded. Every report has zero failed phases
|
|
1932
|
+
and a stable source snapshot; the audio CPU allowance remains recorded.
|
|
1933
|
+
|
|
1934
|
+
| KV / draft depth | Five decode requests | Median decode | Cached TTFT | Four concurrent requests |
|
|
1935
|
+
|---|---:|---:|---:|---:|
|
|
1936
|
+
| Affine 4 / MTP2 | 55.560 s | 19.196 tok/s | 99.55 ms | 16.241 tok/s |
|
|
1937
|
+
| Affine 8 / MTP2 | 55.067 s | 19.442 tok/s | 98.96 ms | 16.329 tok/s |
|
|
1938
|
+
| Affine 4 / MTP4 | 136.714 s | 7.493 tok/s | 97.23 ms | 14.522 tok/s |
|
|
1939
|
+
| Affine 8 / MTP4 | 131.855 s | 7.683 tok/s | 97.48 ms | 15.170 tok/s |
|
|
1940
|
+
|
|
1941
|
+
MTP2 leads this first sweep. Changing precision or draft depth can change the
|
|
1942
|
+
continuation; these are observed configuration rates, not identical-output
|
|
1943
|
+
engine speedup ratios. The small KV8/MTP2 lead needs repetition. The expanded
|
|
1944
|
+
screen below adds async weight expansion, no-MTP controls and TurboQuant
|
|
1945
|
+
serving. No default changes are justified by this single block. Raw settings reports are
|
|
1946
|
+
`decode-settings-{kv8-mtp2,kv4-mtp4,kv8-mtp4}-0.md.json`; the summary is
|
|
1947
|
+
`decode-settings-first-sweep-review.json` in the same reports directory.
|
|
1948
|
+
|
|
1949
|
+
### Integrated settings screen and context repeat — M4 Pro (2026-09-09)
|
|
1950
|
+
|
|
1951
|
+
The isolated shared-serving candidate now includes TurboQuant ordinary/MTP
|
|
1952
|
+
groups. All 20 reports below use stable source
|
|
1953
|
+
`6e293a0efeb2f22e2557bf0e39373774545dc0737496c07e7bbe8cfbf6cd3939`,
|
|
1954
|
+
the same packed Qwen artifact and folded RTN4 companion, Bun 1.4.2,
|
|
1955
|
+
MLX 0.32.2 and the M4 Pro 24 GB. Preflight passes with Josh's audio-CPU
|
|
1956
|
+
allowance. The server's batch capacity is eight; the aggregate leg submits
|
|
1957
|
+
four requests. Separate native serving gates establish actual four-row MTP
|
|
1958
|
+
verification. These reports retain `canonical:false`.
|
|
1959
|
+
|
|
1960
|
+
Short-context block 0 uses matching requests and five 192-token decode
|
|
1961
|
+
samples. Fused TurboQuant decode is enabled; async Trellis expansion is off
|
|
1962
|
+
unless labeled. No report has a failed phase.
|
|
1963
|
+
|
|
1964
|
+
| KV / method | Five requests, complete ms | Median decode tok/s | Cached TTFT ms | Aggregate ×4 tok/s |
|
|
1965
|
+
|---|---:|---:|---:|---:|
|
|
1966
|
+
| bf16 / ordinary | 88,763.10 | 11.593 | 163.76 | 25.776 |
|
|
1967
|
+
| bf16 / MTP2 | 54,064.81 | 19.793 | 96.49 | 16.822 |
|
|
1968
|
+
| bf16 / MTP3 | 53,904.19 | 20.089 | 98.79 | 16.952 |
|
|
1969
|
+
| Affine 4 / ordinary | 89,551.02 | 11.521 | 164.78 | 25.689 |
|
|
1970
|
+
| Affine 4 / MTP1 | 61,737.80 | 17.170 | 96.91 | 15.695 |
|
|
1971
|
+
| Affine 4 / MTP2 | 55,544.22 | 19.200 | 99.49 | 16.247 |
|
|
1972
|
+
| Affine 4 / MTP3 | 61,344.01 | 17.198 | 98.07 | 16.208 |
|
|
1973
|
+
| Affine 4 / MTP2, async | 55,282.33 | 19.167 | 99.02 | 16.243 |
|
|
1974
|
+
| Affine 4 / MTP4, async | 136,386.37 | 7.487 | 97.26 | 14.559 |
|
|
1975
|
+
| Affine 8 / ordinary | 88,955.50 | 11.571 | 167.18 | 25.679 |
|
|
1976
|
+
| Affine 8 / MTP1 | 62,207.00 | 17.003 | 97.45 | 15.510 |
|
|
1977
|
+
| Affine 8 / MTP3 | 56,289.15 | 18.991 | 99.90 | 16.664 |
|
|
1978
|
+
| TQ K8V3 / ordinary | 90,881.00 | 11.403 | 174.53 | 25.308 |
|
|
1979
|
+
| TQ K8V3 / MTP2 | 56,578.08 | 19.242 | 102.53 | 16.429 |
|
|
1980
|
+
| TQ K8V3 / MTP3 | 56,923.87 | 19.065 | 102.78 | 16.046 |
|
|
1981
|
+
| TQ K8V3 / MTP4 | 131,849.48 | 7.593 | 101.34 | 14.481 |
|
|
1982
|
+
|
|
1983
|
+
The affine-4/MTP2 integration control preserves all 15 request/output pairs
|
|
1984
|
+
against the preceding `2b7b…` source; complete decode time changes by -0.029%,
|
|
1985
|
+
effectively unchanged. Its async arm also preserves all 15 outputs, with
|
|
1986
|
+
complete time -0.47% in this one block. Async expansion does not remove the
|
|
1987
|
+
MTP4 decode cliff. MTP3 uses its third proposal: affine-4 accepts 109 of 386
|
|
1988
|
+
third-position drafts, affine-8 accepts 114 of 373. Acceptance alone does not
|
|
1989
|
+
make the extra work profitable.
|
|
1990
|
+
|
|
1991
|
+
The four leading comparison profiles then run full `bench-serve all` with
|
|
1992
|
+
block-1 inputs and `--context 16384`. The rendered prompt actually contains
|
|
1993
|
+
**10,398 tokens**. Each context leg has a cold request and two RAM-cached
|
|
1994
|
+
repeats, followed by an explicit durable flush and SSD restart.
|
|
1995
|
+
|
|
1996
|
+
| KV / method | Five short requests, complete ms | Short decode tok/s | Context decode tok/s | Cold context TTFT ms | SSD restart TTFT ms |
|
|
1997
|
+
|---|---:|---:|---:|---:|---:|
|
|
1998
|
+
| bf16 / MTP3 | 56,107.03 | 19.179 | 23.130 | 80,060.42 | 2,026.44 |
|
|
1999
|
+
| TQ K8V3 / MTP3 | 58,195.34 | 18.350 | 19.580 | 79,777.84 | 1,936.05 |
|
|
2000
|
+
| Affine 4 / MTP2 | 53,548.41 | 20.133 | 22.184 | 79,860.36 | 1,919.74 |
|
|
2001
|
+
| Affine 4 / MTP3 | 56,923.65 | 18.999 | 22.826 | 79,912.94 | 1,930.17 |
|
|
2002
|
+
|
|
2003
|
+
Within each profile the three context responses match exactly. Every restart
|
|
2004
|
+
restores 10,397 cached tokens, with zero pending, dropped or failed spills
|
|
2005
|
+
after flush. Across settings, continuations can differ; these rates do not
|
|
2006
|
+
establish an identical-output engine speedup. MTP2 leads affine-4 short
|
|
2007
|
+
requests, while MTP3 has a small context-decode lead. Ordinary batching has
|
|
2008
|
+
the strongest aggregate throughput in the short screen. The choice of one
|
|
2009
|
+
default for typical single-user multi-turn/tool use remains open pending
|
|
2010
|
+
late-task context measurements and balanced repeats; user overrides remain.
|
|
2011
|
+
|
|
2012
|
+
Raw files in `reports/qwen38-closeout/composition-baseline/`:
|
|
2013
|
+
`decode-integrated-*-0.md.json`, `decode-default-*-context-1.md.json` and
|
|
2014
|
+
`decode-integrated-settings-review.json`. Source archives remain frozen on
|
|
2015
|
+
the M4; no candidate default has been promoted.
|
|
2016
|
+
|
|
2017
|
+
The subsequent late-context control uses the same frozen source and
|
|
2018
|
+
`--context 125000`. KV4/MTP2 fails the context phase, including its retry,
|
|
2019
|
+
with Metal command-buffer out-of-memory at the default 2,048-token prefill
|
|
2020
|
+
chunk. It supplies no context decode or restart result. Preflight passed
|
|
2021
|
+
with 96 MB retained swap and 93% free memory; swap remained 96 MB afterward.
|
|
2022
|
+
Raw: `decode-default-kv4-mtp2-late-context-0.md.json` in the same directory.
|
|
2023
|
+
The next depth-3 attempt was stopped before the context leg to avoid repeating
|
|
2024
|
+
the same oversized configuration. A separate depth-2/3/1 comparison uses
|
|
2025
|
+
`MLX_BUN_RD_PREFILL_CHUNK=256`, matching the published Kanban prefill profile;
|
|
2026
|
+
depth 2 now completes at **78,678 actual prompt tokens**. Cold first-output time
|
|
2027
|
+
is 884.14 seconds, context decode median is 12.828 tok/s, cached repeat
|
|
2028
|
+
first-output time is 237.45 ms and fresh-process SSD restart first-output time
|
|
2029
|
+
is 2,229.68 ms with 78,677 cached tokens. All three context outputs match;
|
|
2030
|
+
the eight-token restart output matches their beginning. Flush is durable with
|
|
2031
|
+
zero pending, dropped or failed writes, and the source hash remains unchanged.
|
|
2032
|
+
Depth 3 also completes on unchanged source. Its cold first-output time is
|
|
2033
|
+
884.68 seconds, context decode median 11.718 tok/s, cached first-output time
|
|
2034
|
+
187.75 ms and SSD restart first-output time 2,235.34 ms with 78,677 tokens
|
|
2035
|
+
restored. Its three context outputs match each other, but differ from depth 2;
|
|
2036
|
+
these are settings comparisons, not identical-output engine comparisons.
|
|
2037
|
+
Durability also passes with no pending, dropped or failed writes. Depth 1
|
|
2038
|
+
completes at 10.582 tok/s context decode, with 884.59 seconds cold first-output
|
|
2039
|
+
time, 189.69 ms cached first-output time and 2,243.35 ms after SSD restart.
|
|
2040
|
+
It restores 78,677 tokens; all three context outputs match depth 2. Source
|
|
2041
|
+
hashes are stable, both preflights pass and there are no phase failures or
|
|
2042
|
+
pending, dropped or failed writes. These single profiles do not select a
|
|
2043
|
+
default. Raw: `decode-default-kv4-mtp{1,2,3}-late-context-chunk256-0.md.json`.
|
|
2044
|
+
Ordinary shared prefill in the frozen benchmark source does not read that
|
|
2045
|
+
control. The adopted policy fix makes ordinary and speculative prefill use the group's
|
|
2046
|
+
captured default and preserves the library request override. Its M1 seeded
|
|
2047
|
+
native and MTP RAM/SSD gates, complete model-free suite and typecheck pass; a matched M4
|
|
2048
|
+
ordinary late-context arm remains open.
|
|
2049
|
+
|
|
2050
|
+
The composed ownership/prefill-policy short control is complete on the M4
|
|
2051
|
+
Pro, with source `04f518534d568d10cd570e3ecd671a69ccbe97513f803d3a29ac250269416a0d`.
|
|
2052
|
+
It uses the same block-0 requests, KV4/MTP2, default prefill chunk and runtime
|
|
2053
|
+
settings as the frozen `6e293a0...` arm. All 14 measured request hashes,
|
|
2054
|
+
response texts, generated counts and cached counts match. Five decode requests
|
|
2055
|
+
take 55,619.41 ms versus 55,544.22 ms, a 0.14% increase; median decode is
|
|
2056
|
+
19.195 versus 19.200 tok/s. Cached first-output time is 97.56 versus 99.49 ms,
|
|
2057
|
+
and four-request aggregate throughput is 16.203 versus 16.247 tok/s. This
|
|
2058
|
+
single comparison is effectively unchanged, with no performance win claimed.
|
|
2059
|
+
There are no phase failures and source hashes remain stable. The arm includes
|
|
2060
|
+
the Gemma ownership fix and captured prefill policy, but not generated-output
|
|
2061
|
+
publication. Raw: `composition-baseline/decode-prefill-policy-kv4-mtp2-short-0.md.json`
|
|
2062
|
+
under `reports/qwen38-closeout/`.
|
|
2063
|
+
|
|
2064
|
+
The same composed source also completes the 78,678-token KV4/MTP2 context
|
|
2065
|
+
control with 256-token chunks. All 19 request hashes, response texts,
|
|
2066
|
+
generated counts and cached counts match the frozen arm. Cold first-output
|
|
2067
|
+
time is 884.12 versus 884.14 seconds; context decode median is 12.918 versus
|
|
2068
|
+
12.828 tok/s. Cached first-output time is 188.35 versus 237.45 ms and restart
|
|
2069
|
+
time is 2,230.56 versus 2,229.68 ms, with 78,677 tokens restored. Durability
|
|
2070
|
+
has no pending, dropped or failed writes; source hashes and both preflights
|
|
2071
|
+
pass. This single comparison does not establish a latency or throughput win.
|
|
2072
|
+
Raw: `composition-baseline/decode-prefill-policy-kv4-mtp2-late-context-chunk256-0.md.json`.
|
|
2073
|
+
The wrapper failed before launching the ordinary arm because macOS Bash 3
|
|
2074
|
+
rejects its empty-array expansion under `set -u`. That arm was resumed alone;
|
|
2075
|
+
the completed MTP report was preserved.
|
|
2076
|
+
|
|
2077
|
+
|
|
2078
|
+
The subsequent ordinary KV4 late-context arm on the same M4 Pro source did
|
|
2079
|
+
**not** pass clean acceptance. Its first 78,678-token cold request completed
|
|
2080
|
+
with 881,941 ms to first output, but the cached repeat failed with Metal
|
|
2081
|
+
`kIOGPUCommandBufferCallbackErrorOutOfMemory`. The benchmark's built-in retry
|
|
2082
|
+
restarted the phase with a different request hash and 78,677 prompt tokens.
|
|
2083
|
+
That retry completed at 7.319 tok/s median context decode, 292.54 ms cached
|
|
2084
|
+
first output and 2,262.76 ms after SSD restart, reusing 78,676 tokens. These
|
|
2085
|
+
are recovery diagnostics, not a matched successful ordinary/MTP comparison.
|
|
2086
|
+
Both machine checks passed and source stayed fixed; final swap was 294.69 MB.
|
|
2087
|
+
The final flush retained 17 entries with no pending, dropped or failed spills.
|
|
2088
|
+
The initial failure and both attempts remain in
|
|
2089
|
+
`reports/qwen38-closeout/composition-baseline/decode-prefill-policy-kv4-plain-late-context-chunk256-0.md.json`.
|
|
2090
|
+
The cached-repeat allocation failure needs investigation before repeating
|
|
2091
|
+
ordinary late-context acceptance. Independent output-cache/prefill correctness
|
|
2092
|
+
resumed without rerunning or reclassifying this failed benchmark.
|
|
2093
|
+
|
|
2094
|
+
|
|
2095
|
+
The final generated-output/prefill composition also passes M4 native and
|
|
2096
|
+
HTTP bf16/KV4/fused-TQ cache continuation, parser/template replay, full-suite
|
|
2097
|
+
and typecheck gates. Its short KV4/MTP2 block-0 benchmark uses source
|
|
2098
|
+
`af91e6a64649df5af9eb73e4a35739109f6799a5c8ba7ddc47c3543876cb19c0`.
|
|
2099
|
+
All 14 measured requests plus warmup match the prefill-policy control's
|
|
2100
|
+
request hashes, response text, prompt/generated counts and cached counts.
|
|
2101
|
+
Five decode requests take 55,636.28 versus 55,619.41 ms, a 0.03% increase;
|
|
2102
|
+
median decode is 19.171 versus 19.195 tok/s. Cached first output is 99.06
|
|
2103
|
+
versus 97.56 ms, and aggregate throughput is 15.859 versus 16.203 tok/s.
|
|
2104
|
+
Source and preflights are stable with no failures. This is one matched
|
|
2105
|
+
composition check with flat decode; it establishes no overall speed win or
|
|
2106
|
+
strict serial-domination result. Long Kanban and pressure acceptance remain.
|
|
2107
|
+
Raw: `composition-baseline/decode-output-prefill-kv4-mtp2-short-0.md.json`.
|
|
2108
|
+
|
|
2109
|
+
|
|
2110
|
+
The isolated variable-proposal verifier passes M4 uniform/variable bf16/KV4
|
|
2111
|
+
native controls, the full suite and typecheck. Its first short KV4/MTP2
|
|
2112
|
+
block-0 comparison is slower: five decode requests take 58,907.66 versus
|
|
2113
|
+
55,636.28 ms, a 5.88% increase; median decode is 17.936 versus 19.171 tok/s.
|
|
2114
|
+
Cached first output is 97.51 versus 99.06 ms and aggregate throughput is
|
|
2115
|
+
15.911 versus 15.859 tok/s. All measured requests plus warmup preserve
|
|
2116
|
+
request hashes, responses, prompt/generated/cache counts and speculation
|
|
2117
|
+
statistics. Source `885f542f07ea48e119a6bdaf533b4e2605ff293c3d7eb373ac202410032e24dd`
|
|
2118
|
+
and both preflights are stable, with no failures. This single ordered
|
|
2119
|
+
comparison does not distinguish a code regression from machine drift.
|
|
2120
|
+
Alternating frozen control/candidate repeats below test whether that slowdown
|
|
2121
|
+
follows the source.
|
|
2122
|
+
Raw: `composition-baseline/decode-variable-proposals-kv4-mtp2-short-0.md.json`.
|
|
2123
|
+
|
|
2124
|
+
The subsequent M4 Pro 24 GB A/B/B/A repeats use the same two frozen sources,
|
|
2125
|
+
KV4, MTP2, 192-token limit, block-0 workload and runtime environment. All 15
|
|
2126
|
+
requests per arm, including warmup, match request/output hashes, token counts,
|
|
2127
|
+
finish reasons and complete usage/speculation records. Both preflights pass
|
|
2128
|
+
and each source remains unchanged, with no request or phase failures.
|
|
2129
|
+
|
|
2130
|
+
| Arm | Five decode requests, total ms | Median decode tok/s | Cached first output ms | Aggregate tok/s |
|
|
2131
|
+
|---|---:|---:|---:|---:|
|
|
2132
|
+
| Control 1 | 55,559.96 | 19.154 | 98.90 | 15.853 |
|
|
2133
|
+
| Candidate 1 | 55,618.37 | 19.152 | 97.29 | 15.674 |
|
|
2134
|
+
| Candidate 2 | 55,566.01 | 19.189 | 97.23 | 15.880 |
|
|
2135
|
+
| Control 2 | 55,604.33 | 19.166 | 99.06 | 15.917 |
|
|
2136
|
+
|
|
2137
|
+
Combined candidate decode wall time is **0.018% higher**. The initial 5.88%
|
|
2138
|
+
slowdown does not reproduce; this screen supports preserving fixed-MTP decode
|
|
2139
|
+
performance while adding variable proposals. Aggregate throughput varies and
|
|
2140
|
+
establishes no gain. This does not qualify actual prompt-lookup performance,
|
|
2141
|
+
long contexts or serial deletion. The verifier patch is adopted in the working
|
|
2142
|
+
tree after the both-machine correctness gates; the main suite and typecheck pass.
|
|
2143
|
+
Raw reports and derived identity/timing comparison:
|
|
2144
|
+
`composition-baseline/variable-proposals/decode-variable-alternating-*.md.json`
|
|
2145
|
+
and `composition-baseline/variable-proposals/alternating-comparison.json`.
|
|
2146
|
+
|
|
2147
|
+
The prompt-lookup integration's fixed-MTP regression screen uses the same M4
|
|
2148
|
+
Pro 24 GB, KV4/MTP2, block-0 requests and runtime settings. Frozen source
|
|
2149
|
+
`3df52152aac2289b9ed860c2789141acb5e8d6ce7a6170899f34bd9ef1ac9a39`
|
|
2150
|
+
retains all 15 request/output hashes and complete usage/speculation records
|
|
2151
|
+
against variable-verifier candidate2 above. Five decode requests take
|
|
2152
|
+
55,620.03 versus 55,566.01 ms, a 0.097% increase; median decode is 19.176
|
|
2153
|
+
versus 19.189 tok/s, cached first output 97.56 versus 97.23 ms, and aggregate
|
|
2154
|
+
throughput 15.778 versus 15.880 tok/s. Source/preflights are stable with no
|
|
2155
|
+
request or phase failures. This one short screen establishes no speedup;
|
|
2156
|
+
actual prompt-lookup serial/shared comparisons remain separate.
|
|
2157
|
+
Raw and comparison: `composition-baseline/ngram-group/decode-ngram-group-kv4-mtp2-short-0.md.json`
|
|
2158
|
+
and `composition-baseline/ngram-group/fixed-mtp-comparison.json`.
|
|
2159
|
+
|
|
2160
|
+
The subsequent delayed-TQ/method composition passes M4 fused/unfused native,
|
|
2161
|
+
SSD, complete-suite, typecheck and hygiene checks. Its short fixed-KV4/MTP2
|
|
2162
|
+
screen, source `88da0dca100cdb012cbd4330638cc43b727dbb853a5b1ef6aded60bc6fe1eb0d`,
|
|
2163
|
+
preserves all 15 request/output hashes and complete usage/speculation records
|
|
2164
|
+
against the frozen lookup base. Five decode requests take 55,812.61 versus
|
|
2165
|
+
55,620.03 ms, a 0.35% increase. Median decode is 19.123 versus 19.176 tok/s,
|
|
2166
|
+
cached first output 98.72 versus 97.56 ms, and aggregate throughput 15.724
|
|
2167
|
+
versus 15.778 tok/s. Source/preflights pass with no failures. This single
|
|
2168
|
+
short composition screen establishes no gain and does not measure delayed
|
|
2169
|
+
TurboQuant performance, since the workload uses KV4.
|
|
2170
|
+
Raw: `composition-baseline/method-composed/decode-tq-method-composed-kv4-mtp2-short-0.md.json`
|
|
2171
|
+
and `composition-baseline/method-composed/fixed-mtp-comparison.json`.
|
|
2172
|
+
|
|
2173
|
+
Two M4 Pro 24 GB prompt-lookup comparisons use KV4, draft depth 3,
|
|
2174
|
+
192-token decode requests, and reversed arm order on two workload seeds.
|
|
2175
|
+
Source is the same frozen lookup candidate above; both preflights and source
|
|
2176
|
+
checks pass with no request or phase failures. All single-request response
|
|
2177
|
+
pairs match, including their generated counts and finish reasons.
|
|
2178
|
+
|
|
2179
|
+
| Arm order | Five decode requests, serial / shared ms | Cached first output, serial / shared ms | Observed aggregate tok/s, serial / shared |
|
|
2180
|
+
|---|---:|---:|---:|
|
|
2181
|
+
| Serial first | 92,140.46 / 91,472.96 | 5,843.26 / 126.77 | 10.213 / 9.430 |
|
|
2182
|
+
| Shared first | 89,953.79 / 89,279.30 | 5,863.21 / 126.66 | 10.798 / 9.608 |
|
|
2183
|
+
|
|
2184
|
+
Single-request decode totals improve by 0.72% and 0.75%. Shared prompt lookup
|
|
2185
|
+
restores 758 and 757 tokens on the cached repetitions; serial restores zero.
|
|
2186
|
+
That is an actual new cache benefit, with different prefill work. All eight
|
|
2187
|
+
concurrent output pairs differ, and observed shared throughput is lower in
|
|
2188
|
+
both orders. An identical-output aggregate comparison and shared-execution
|
|
2189
|
+
dominance remain unproven. Wider verification cost and acceptance need further
|
|
2190
|
+
measurement; the result does not qualify deleting serial. Default-depth-10
|
|
2191
|
+
KV4 serving correctness subsequently passes 219 assertions on each Mac, with
|
|
2192
|
+
all ten proposal positions exercised; this is not depth-10 timing acceptance.
|
|
2193
|
+
Raw: `composition-baseline/ngram-group/decode-ngram-group-kv4-serial-shared-{0,1}.md.json`
|
|
2194
|
+
and `composition-baseline/ngram-group/lookup-paired-comparison.json`.
|
|
2195
|
+
|
|
2196
|
+
A separate M1 Max first-output diagnostic uses a 758-token prompt, KV4/MTP2
|
|
2197
|
+
and eight generated tokens through direct serial/shared execution. All eight
|
|
2198
|
+
outputs match and warm requests restore 757 tokens. Draft seeding accounts
|
|
2199
|
+
for roughly 93 ms on the warm traces; cache lookup is about 0.3–0.6 ms.
|
|
2200
|
+
Instrumenting the native allocator cleanup then identifies 0–6.8 ms inside
|
|
2201
|
+
`clearCache()` after the one-token target forward, on both execution paths.
|
|
2202
|
+
The shared path does not consistently trail serial in this loaded diagnostic;
|
|
2203
|
+
it does not explain the M4 gap by itself. A bounded candidate will skip this
|
|
2204
|
+
cleanup for one-token prefill work while retaining larger-chunk cleanup, with
|
|
2205
|
+
numerical, allocation and M4 request-time checks before adoption. Raw traces:
|
|
2206
|
+
`composition-baseline/mtp-first-output-diagnostic-m1.jsonl` and
|
|
2207
|
+
`composition-baseline/mtp-clear-diagnostic-m1.jsonl`.
|
|
2208
|
+
|
|
2209
|
+
The one-token maintenance candidate also completes a separate-process M1 Max
|
|
2210
|
+
allocation comparison at 8,195 prompt tokens, MTP2/KV4, chunk256, eight output
|
|
2211
|
+
tokens and a 4 GiB RAM cache without SSD. All three paired outputs, cache counts
|
|
2212
|
+
and speculation records match. Both warm repeats restore 8,194 tokens.
|
|
2213
|
+
Warm peak live allocation above the starting live state is 544.717 MiB for
|
|
2214
|
+
control and 544.732 MiB for candidate, a 16,208-byte increase. Final live
|
|
2215
|
+
allocation is effectively unchanged; the candidate's final allocator pool is
|
|
2216
|
+
845.54 versus 709.29 MiB, so it retains about 136 MiB more unused capacity in
|
|
2217
|
+
this run. This loaded M1 diagnostic establishes no speedup and does not replace
|
|
2218
|
+
M4 long-context/SSD pressure coverage. Raw and derived records:
|
|
2219
|
+
`composition-baseline/single-token-maintenance/m1-allocation-{control,candidate}.jsonl`
|
|
2220
|
+
and `composition-baseline/single-token-maintenance/m1-allocation-comparison.json`.
|
|
2221
|
+
|
|
2222
|
+
Four alternating M4 Pro 24 GB fixed-MTP2/KV4 short runs compare the one-token
|
|
2223
|
+
maintenance candidate against the composed source above. Bun is 1.4.2,
|
|
2224
|
+
MLX is 0.32.2, fused TQ decode is enabled and asynchronous Trellis expansion
|
|
2225
|
+
is disabled. Both arms use seed `mtp-serving-block-0`, 192 output tokens,
|
|
2226
|
+
a 4 GiB prompt cache and the same packed target/RTN4 companion. Control source
|
|
2227
|
+
is `88da0dca100cdb012cbd4330638cc43b727dbb853a5b1ef6aded60bc6fe1eb0d`;
|
|
2228
|
+
candidate is `c12b60c1c7f39bf4ccdeaa7cdd16795a04d6ca2246eeb7609ec97cb9eee65315`.
|
|
2229
|
+
All four source snapshots and preflights pass under the recorded audio-CPU
|
|
2230
|
+
allowance. All 60 requests preserve request hashes, output text, complete
|
|
2231
|
+
usage/acceptance records and finish reasons, with no failures.
|
|
2232
|
+
|
|
2233
|
+
| Order | Five decode requests, total ms | Cached first output, ms | Median decode, tok/s | Aggregate tok/s |
|
|
2234
|
+
|---|---:|---:|---:|---:|
|
|
2235
|
+
| Control 1 | 56,424.69 | 98.097 | 18.722 | 15.591 |
|
|
2236
|
+
| Candidate 1 | 55,595.29 | 96.483 | 19.198 | 15.799 |
|
|
2237
|
+
| Candidate 2 | 55,588.63 | 96.517 | 19.171 | 15.916 |
|
|
2238
|
+
| Control 2 | 55,581.64 | 98.214 | 19.174 | 15.959 |
|
|
2239
|
+
|
|
2240
|
+
Cached latency averages 98.156 versus 96.500 ms, a 1.69% reduction. The
|
|
2241
|
+
first control also has slower cold prefill and decode; both candidate decode
|
|
2242
|
+
totals are effectively flat against the second control. This screen supports
|
|
2243
|
+
the narrow cached-latency improvement, not a general throughput gain or
|
|
2244
|
+
serial/shared dominance. The candidate remains isolated pending the direct
|
|
2245
|
+
serial/shared comparison and pressure review. Raw and derived records:
|
|
2246
|
+
`composition-baseline/single-token-maintenance/decode-single-token-maintenance-{control1,candidate1,candidate2,control2}.md.json`
|
|
2247
|
+
and `composition-baseline/single-token-maintenance/alternating-comparison.json`.
|
|
2248
|
+
|
|
2249
|
+
The direct M4 Pro serial/shared follow-up uses that same candidate source,
|
|
2250
|
+
MTP2/KV4 and two seeds with reversed arm order. All 22 single-request pairs
|
|
2251
|
+
preserve output, usage except the lane label, and cache coverage; all request
|
|
2252
|
+
hashes and generated budgets match. Source/preflights pass with no failures.
|
|
2253
|
+
|
|
2254
|
+
| Arm order | Five decode requests, serial / shared ms | Cached first output, serial / shared ms | Observed aggregate tok/s, serial / shared |
|
|
2255
|
+
|---|---:|---:|---:|
|
|
2256
|
+
| Serial first | 56,220.90 / 55,568.01 | 93.761 / 96.858 | 15.734 / 16.003 |
|
|
2257
|
+
| Shared first | 54,119.93 / 54,093.31 | 93.782 / 95.060 | 16.111 / 15.925 |
|
|
2258
|
+
|
|
2259
|
+
The allocator change does not remove the B1 cached-latency regression. Seven
|
|
2260
|
+
of eight concurrent output pairs differ, and observed aggregate throughput
|
|
2261
|
+
moves in opposite directions across the two orders. These results do not
|
|
2262
|
+
qualify shared dominance or serial deletion. The cleanup candidate remains
|
|
2263
|
+
isolated; its narrow improvement against the prior shared implementation is
|
|
2264
|
+
recorded separately above. Raw and derived records:
|
|
2265
|
+
`composition-baseline/single-token-maintenance/decode-maintenance-serial-shared-{0,1}.md.json`
|
|
2266
|
+
and `composition-baseline/single-token-maintenance/serial-shared-comparison.json`.
|
|
2267
|
+
|
|
2268
|
+
Four alternating M4 Pro 24 GB prompt-lookup runs compare wider packed
|
|
2269
|
+
down-projection eligibility against the unchanged operation. Settings are
|
|
2270
|
+
KV4, lookup depth3, 192 output tokens, seed `ngram-serving-block-0`, Bun 1.4.2
|
|
2271
|
+
and MLX 0.32.2. Control source is
|
|
2272
|
+
`88da0dca100cdb012cbd4330638cc43b727dbb853a5b1ef6aded60bc6fe1eb0d`;
|
|
2273
|
+
candidate is `c399a3e7fa4d8e61d720476a53a3abb5055944dccfd32684a99157373a288343`.
|
|
2274
|
+
All 60 requests preserve request hashes, response text, complete usage and
|
|
2275
|
+
finish reasons. Source/preflights pass under the audio-CPU allowance, with no
|
|
2276
|
+
failures. Both-machine projection and full-model B1/B2/B4/B8 state checks pass,
|
|
2277
|
+
including every new projection width and the artifact's three bit widths.
|
|
2278
|
+
|
|
2279
|
+
| Order | Five decode requests, total ms | Cached first output, ms | Aggregate tok/s |
|
|
2280
|
+
|---|---:|---:|---:|
|
|
2281
|
+
| Control 1 | 91,973.51 | 126.671 | 9.456 |
|
|
2282
|
+
| Candidate 1 | 92,261.32 | 129.677 | 9.305 |
|
|
2283
|
+
| Candidate 2 | 91,413.34 | 126.650 | 9.324 |
|
|
2284
|
+
| Control 2 | 91,750.52 | 126.872 | 9.473 |
|
|
2285
|
+
|
|
2286
|
+
Combined single-request time is effectively unchanged, decreasing 0.027%,
|
|
2287
|
+
while aggregate throughput decreases 1.58%. Both candidate aggregate results
|
|
2288
|
+
trail both controls. The wider eligibility is not adopted: exact arithmetic
|
|
2289
|
+
and avoiding dense weight expansion do not establish a serving benefit.
|
|
2290
|
+
Any further kernel tuning needs workload dispatch/cost attribution first.
|
|
2291
|
+
Raw and comparison:
|
|
2292
|
+
`composition-baseline/trellis-batch-width/decode-trellis-width-ngram-{control1,candidate1,candidate2,control2}.md.json`
|
|
2293
|
+
and `composition-baseline/trellis-batch-width/alternating-comparison.json`.
|
|
2294
|
+
|
|
2295
|
+
A bounded M1 Max allocation diagnostic follows the ordinary M4 cached-repeat
|
|
2296
|
+
OOM. At 8,195 prompt tokens, KV4, 12 generated tokens and a 4 GiB RAM cache
|
|
2297
|
+
without SSD, normal pipelining, early first output and disabled pipelining
|
|
2298
|
+
all retain two entries and add the same 375.28 MiB peak allocator demand
|
|
2299
|
+
above the pre-request live allocation on warm repeats. All nine outputs
|
|
2300
|
+
match. This loaded-machine native probe is not a speed benchmark, does not
|
|
2301
|
+
reproduce the 78k failure, and supplies no evidence that pipeline overlap is
|
|
2302
|
+
its allocation cause. Large-context retention and concurrent SSD persistence
|
|
2303
|
+
remain untested by this probe.
|
|
2304
|
+
Raw: `composition-baseline/ordinary-cached-allocation-m1.jsonl`.
|
|
2305
|
+
|
|
2306
|
+
### Current MTP depth two versus four — M4 Pro (2026-09-09)
|
|
2307
|
+
|
|
2308
|
+
Same packed artifact, RTN4 companion, KV4, Bun 1.4.2, MLX 0.32.2 and frozen
|
|
2309
|
+
reference source as the replay experiment above. The source hash is
|
|
2310
|
+
`a01bee0b7e1962c8211f1ffd845d95f7923d6c04bddb18cf06f07483cab9e7e8`.
|
|
2311
|
+
Only the draft depth changes. Each block uses matching request hashes and
|
|
2312
|
+
192 output tokens. Both depth-four blocks precede both depth-two blocks, so
|
|
2313
|
+
this depth comparison is not balanced in execution order. Preflight passes
|
|
2314
|
+
with the recorded audio-CPU allowance; reports retain `canonical:false`.
|
|
2315
|
+
|
|
2316
|
+
| Block | Depth two median decode | Depth four median decode | Five-request complete time, depth two / four | Matching responses |
|
|
2317
|
+
|---|---:|---:|---:|---:|
|
|
2318
|
+
| 0 | 19.33 tok/s | 7.36 tok/s | 56,275.71 / 135,674.99 ms | 6 / 15 |
|
|
2319
|
+
| 1 | 18.31 tok/s | 7.60 tok/s | 57,859.37 / 130,083.45 ms | 6 / 15 |
|
|
2320
|
+
|
|
2321
|
+
Counts, cached coverage and finish reasons match for every request. All five
|
|
2322
|
+
decode and four queued-concurrency responses differ in each block; no phase
|
|
2323
|
+
fails. These are observed results from different continuations, not an
|
|
2324
|
+
identical-output speed ratio or a depth-four acceptance. Depth two remains the
|
|
2325
|
+
current choice. A depth-four verify processes five tokens including the pending
|
|
2326
|
+
token, crossing the existing four-row packed-kernel boundary. R7 already records
|
|
2327
|
+
that boundary's cost and arithmetic difference; the current runs do not isolate
|
|
2328
|
+
its contribution from the changed continuation/acceptance trajectory.
|
|
2329
|
+
|
|
2330
|
+
Raw: `reports/qwen38-closeout/composition-baseline/mtp-depth2-{0,1}.md.json`,
|
|
2331
|
+
`state-replay-reference-{0,1}.md.json` and `mtp-depth-performance-review.json`.
|
|
2332
|
+
All requests here use the one-active-request control; four queued requests do
|
|
2333
|
+
not establish actual batched MTP. Compare fixed-input verification at both
|
|
2334
|
+
window sizes before changing the dispatch policy or promoting depth four.
|
|
2335
|
+
|
|
2336
|
+
### Current standard serve matrix — M1 Max 32 GB (2026-08-22)
|
|
2337
|
+
|
|
2338
|
+
Real-server HTTP matrix on commit `4103ae1`, with the canonical preflight
|
|
2339
|
+
passing at the start of both runs: zero swap, ample free memory, and no large
|
|
2340
|
+
foreign process. The Qwen extension ended with 944 MiB of inactive swap,
|
|
2341
|
+
below the harness's 3 GiB mid-run rejection threshold. No benchmark phase
|
|
2342
|
+
failed. Raw gitignored reports:
|
|
2343
|
+
`benchmarks-serve-2026-08-22-Joshs-MacBook-Pro-2.md` and
|
|
2344
|
+
`benchmarks-serve-2026-08-22-Joshs-MacBook-Pro-2-qwen27b.md`.
|
|
2345
|
+
|
|
2346
|
+
| model | arm | short decode tok/s | decode @ ~15.8k tok/s | aggregate ×4 tok/s | restart TTFT ms (cached tokens) |
|
|
2347
|
+
|---|---|---:|---:|---:|---:|
|
|
2348
|
+
| MiniCPM5-1B | mlx-bun | **267.7** | 122.0 | **420.1** | 207 (15,817) |
|
|
2349
|
+
| | mlx-bun serial | 266.4 | 124.6 | 245.9 | 182 (15,889) |
|
|
2350
|
+
| | mlx-lm | 179.7 | 96.2 | 181.4 | 10,355 (0) |
|
|
2351
|
+
| | mlx-bun mixed | 194.2 | **127.0** | 397.5 | **130 (15,815)** |
|
|
2352
|
+
| gemma-4-e4b | mlx-bun | **61.5** | 43.7 | 20.7 | 18,863 (4) |
|
|
2353
|
+
| | mlx-bun serial | **61.5** | 43.1 | 59.7 | **661 (15,940)** |
|
|
2354
|
+
| | mlx-lm | 52.8 | 42.8 | 72.3 | 20,187 (0) |
|
|
2355
|
+
| | mlx-bun mixed | 57.3 | **49.0** | **97.4** | 20,510 (0) |
|
|
2356
|
+
| gemma-4-12B | mlx-bun | **29.6** | 28.3 | 5.6 | 85,180 (4) |
|
|
2357
|
+
| | mlx-bun serial | **29.6** | **28.4** | 27.5 | **1,338 (15,866)** |
|
|
2358
|
+
| | mlx-lm | 27.1 | 25.8 | 32.5 | 89,504 (0) |
|
|
2359
|
+
| | mlx-bun mixed | 28.7 | 24.4 | **38.7** | 93,068 (6) |
|
|
2360
|
+
| Qwen3.8-27B winner | mlx-bun | **18.5** | 16.5 | 19.3 | 173,215 (0) |
|
|
2361
|
+
| | mlx-bun serial | **18.5** | **16.7** | 15.8 | 172,400 (0) |
|
|
2362
|
+
| | mlx-lm | 16.5 | 14.9 | 18.3 | 177,066 (0) |
|
|
2363
|
+
| | mlx-bun mixed | 18.1 | 14.9 | **19.4** | **3,328 (15,112)** |
|
|
2364
|
+
|
|
2365
|
+
- All four models passed 64-token greedy completion and chat parity for
|
|
2366
|
+
mlx-bun bf16 versus mlx-lm, and unified scheduling versus `--batch 1`.
|
|
2367
|
+
- Qwen's standard mlx-bun arm beat mlx-lm by 12.1% at short decode and
|
|
2368
|
+
10.7% at long-context decode. The mixed arm did not beat bf16 on decode;
|
|
2369
|
+
its useful result was restoring the full 15,112-token cache after restart.
|
|
2370
|
+
- The e4b and 12B unified arms restored only four cached tokens after restart,
|
|
2371
|
+
while their serial controls restored the full cache. This is a real
|
|
2372
|
+
scheduler/SSD-persistence regression and explains their poor aggregate rows.
|
|
2373
|
+
Qwen bf16 restored no cache in either scheduler mode.
|
|
2374
|
+
- Qwen mixed KV is a Lab characterization, not an L2 correctness claim. Its
|
|
2375
|
+
policy is copied from the official same-topology Qwen3.6 OptiQ artifact;
|
|
2376
|
+
Qwen3.8 has no model-specific mixed-KV oracle yet. Its 15,278 MB sampled peak
|
|
2377
|
+
RSS also failed the harness's `mixed < bf16` diagnostic, so the run proves
|
|
2378
|
+
that the policy loads and serves, but not that KV quantization was effective.
|
|
2379
|
+
|
|
2380
|
+
#### Bun 1.4.0 repeat
|
|
2381
|
+
|
|
2382
|
+
The full matrix repeated after upgrading from Bun 1.3.14 to 1.4.0. Starting
|
|
2383
|
+
state was 401 MiB inactive swap, 93% free memory, load 3.7, and no large
|
|
2384
|
+
foreign process, which passed the canonical preflight. All completion, chat,
|
|
2385
|
+
and unified-versus-serial parity probes passed again. Core mlx-bun performance
|
|
2386
|
+
was stable; the largest one-run movements were MiniCPM aggregate +5.0% and
|
|
2387
|
+
Qwen long-context decode +3.0%, neither promoted as a Bun speed claim without
|
|
2388
|
+
repeats.
|
|
2389
|
+
|
|
2390
|
+
| model | engine | short decode tok/s | short prefill tok/s | long decode tok/s | warm TTFT ms | aggregate ×4 tok/s |
|
|
2391
|
+
|---|---|---:|---:|---:|---:|---:|
|
|
2392
|
+
| MiniCPM5-1B | mlx-bun | **265.8** | **2,576** | **124.2** | **26** | **441.3** |
|
|
2393
|
+
| | mlx-lm | 177.0 | 1,907 | 96.5 | 86 | 185.8 |
|
|
2394
|
+
| gemma-4-e4b | mlx-bun | **61.7** | **868** | **43.1** | **39** | 21.2 |
|
|
2395
|
+
| | mlx-lm | 52.4 | 676 | 42.5 | 268 | **72.4** |
|
|
2396
|
+
| gemma-4-12B | mlx-bun | **29.7** | **191** | **28.4** | **77** | 6.0 |
|
|
2397
|
+
| | mlx-lm | 26.7 | 181 | 25.3 | 388 | **33.4** |
|
|
2398
|
+
| Qwen3.8-27B winner | mlx-bun | **18.6** | 64 | **17.0** | **116** | **19.5** |
|
|
2399
|
+
| | mlx-lm | 16.5 | **85** | 14.8 | 284 | 18.6 |
|
|
2400
|
+
|
|
2401
|
+
The e4b and 12B aggregate losses remain contaminated by the SSD durability
|
|
2402
|
+
race. Their unified arms restored 2 and 4 tokens; serial restored 15,939 and
|
|
2403
|
+
15,794. Qwen's short-prefill loss is different: both mlx-bun schedulers lose
|
|
2404
|
+
at the roughly 754-token shape, while sustained prefill reaches 87 tok/s at
|
|
2405
|
+
15.1k versus mlx-lm's 88. This points to fixed graph-build or shape overhead,
|
|
2406
|
+
not a slower sustained prefill kernel. Split timing is still required before
|
|
2407
|
+
assigning the cause.
|
|
2408
|
+
|
|
2409
|
+
### Colibri G1/G3 component matrix — M1 Max 32 GB
|
|
2410
|
+
|
|
2411
|
+
Cleared-machine run on 2026-07-30, commit `47c4d6d`, Bun 1.3.14, pinned
|
|
2412
|
+
Colibri `44e489b`, public artifact revision `3cc8db9`, ten warmups and fifteen
|
|
2413
|
+
measured samples. Values are synchronized median milliseconds at identical
|
|
2414
|
+
production shapes; every arm passed its correctness oracle. These are
|
|
2415
|
+
component timings, not end-to-end generation claims.
|
|
2416
|
+
|
|
2417
|
+
| production-shape cell | direct Colibri Metal | selected mlx-bun path | decision |
|
|
2418
|
+
|---|---:|---:|---|
|
|
2419
|
+
| Q4 dense decode M=1 | 0.302 | 1.372 stock MLX | stock MLX (only mlx-bun dense candidate) |
|
|
2420
|
+
| Q4 dense prefill M=32 | 1.286 | **1.030 stock MLX** | stock MLX |
|
|
2421
|
+
| routed SwiGLU decode, top-8 M=1 | **1.401** | 4.282 custom Metal | custom Metal; 16.0% faster than stock MLX's 5.099 ms |
|
|
2422
|
+
| routed SwiGLU ragged M=11/23 experts | **10.851** | 18.100 stock MLX | stock MLX |
|
|
2423
|
+
| routed SwiGLU prefill M=32/64 experts | **32.906** | 45.558 stock MLX | stock MLX |
|
|
2424
|
+
| absorbed MLA decode, position 128 | **1.014** | 11.506 stock MLX | stock MLX; largest remaining component gap |
|
|
2425
|
+
|
|
2426
|
+
For the selected custom decode path, max absolute delta versus stock is
|
|
2427
|
+
`2.33e-9`, relative RMSE `5.56e-7`, and cosine
|
|
2428
|
+
`0.9999999999998354`. A separate three-warmup/eleven-sample run also selected
|
|
2429
|
+
custom Metal by 5.4%. Swap was unchanged at 339.25 MiB. Matched idle-power
|
|
2430
|
+
arms (baseline, 1, 2, and 4 native workers, repeated in reverse order) show no
|
|
2431
|
+
monotonic CPU/GPU/package-power increase, proving the condition-variable
|
|
2432
|
+
workers are passive; two workers remain the default. Raw gitignored reports:
|
|
2433
|
+
`runs/colibri-g1/*matrix*-2026-07-30.json` and
|
|
2434
|
+
`runs/colibri-g1/passive-worker-power*-2026-07-30.json`.
|
|
2435
|
+
|
|
2436
|
+
### Colibri G4 serial native MTP — M1 Max 32 GB
|
|
2437
|
+
|
|
2438
|
+
Production-artifact separate-process A/B on 2026-07-30, Bun 1.3.14, pinned
|
|
2439
|
+
Colibri `44e489b`, public artifact revision `3cc8db9`, greedy gamma=3, 32-token
|
|
2440
|
+
prompt and 64 generated tokens. Both arms reproduced the same direct-Colibri
|
|
2441
|
+
64/64 target-token trajectory. Generation wall time is the comparison metric;
|
|
2442
|
+
the probe's prefill/decode sub-buckets place the first sample on different
|
|
2443
|
+
sides of that boundary and are therefore not compared.
|
|
2444
|
+
|
|
2445
|
+
| arm | generation wall | wall throughput | target/verify forwards | draft acceptance |
|
|
2446
|
+
|---|---:|---:|---:|---:|
|
|
2447
|
+
| MTP off | 834.172 s | 0.0767 tok/s | 63 continuation | — |
|
|
2448
|
+
| MTP on | **675.654 s** | **0.0947 tok/s (1.235x)** | **31 verify (32 saved)** | 32/92 |
|
|
2449
|
+
|
|
2450
|
+
MTP-on emitted 2.065 tokens per verify forward and reduced end-to-end
|
|
2451
|
+
generation time by 19.0%. Its direct-oracle acceptance prefix was exact for
|
|
2452
|
+
the tie-free first four rounds `[1,1,1,0]` (eight emitted tokens; minimum
|
|
2453
|
+
first-draft margin 3.5675). Later acceptance is intentionally non-gating
|
|
2454
|
+
across engines because direct Colibri's float64 RMSNorm reduction and MLX's
|
|
2455
|
+
float32 graph produce different recurrent MTP hidden states while preserving
|
|
2456
|
+
all target tokens. The machine was not swap-cleared, so the
|
|
2457
|
+
14,679,224,320-byte completed MTP-on physical footprint is not a G5 memory
|
|
2458
|
+
claim. Stable record:
|
|
2459
|
+
`fixtures/colibri-glm52/g4-native-mtp-e2e.json`.
|
|
2460
|
+
|
|
2461
|
+
### Colibri G5–G7 full-model productization — M1 Max 32 GB
|
|
2462
|
+
|
|
2463
|
+
Final curated result for the streamed runtime. Bun 1.3.14, 32 GiB unified
|
|
2464
|
+
memory, 25 GiB process ceiling, batch 1, 4,096-token supported context, 128
|
|
2465
|
+
generated tokens, greedy decoding, true top-8, and quality-preserving defaults.
|
|
2466
|
+
The G5 before/after run is 2026-08-15; G6 learning telemetry is a three-repeat
|
|
2467
|
+
paired run on 2026-08-16; the DSA and API gates are 2026-08-17.
|
|
2468
|
+
|
|
2469
|
+
#### Resource contract
|
|
2470
|
+
|
|
2471
|
+
The current artifact-aware preflight, including the locally installed stock
|
|
2472
|
+
DSA indexer overlay, reports:
|
|
2473
|
+
|
|
2474
|
+
| resource | bytes | GiB |
|
|
2475
|
+
|---|---:|---:|
|
|
2476
|
+
| full artifact on disk (streamed, not resident) | 383,739,826,712 | 357.39 |
|
|
2477
|
+
| resident non-expert weights + DSA indexers | 11,074,469,760 | 10.31 |
|
|
2478
|
+
| main Q4 expert slab (139 slots) | 2,632,646,656 | 2.45 |
|
|
2479
|
+
| MTP Q8 expert slab (25 slots) | 945,356,800 | 0.88 |
|
|
2480
|
+
| target + MTP compressed KV | 789,577,728 | 0.74 |
|
|
2481
|
+
| reconstructed KV + verify + allocator/Bun/safety reserves | 5,910,612,992 | 5.50 |
|
|
2482
|
+
| **planned process** | **21,352,663,936** | **19.89 / 25.00** |
|
|
2483
|
+
| **process/macOS headroom** | **5,490,881,664** | **5.11** |
|
|
2484
|
+
|
|
2485
|
+
The original G5 measurement preceded the 197,202,400-byte stock indexer
|
|
2486
|
+
overlay and planned 21,111,440,128 bytes. The overlay raises the current
|
|
2487
|
+
preflight by 241,223,808 bytes but does not alter the short-context trajectory
|
|
2488
|
+
or the observed G5 footprints below.
|
|
2489
|
+
|
|
2490
|
+
> **Measurement outcome:** the requested before/after observation closed the
|
|
2491
|
+
> 32 GB fit question, but did **not** satisfy the harness's stricter
|
|
2492
|
+
> zero-compression/zero-swap contract. Peak physical footprint stayed at or
|
|
2493
|
+
> below 14,807,789,616 bytes (13.791 GiB), while maximum system/task compressor
|
|
2494
|
+
> growth was 4,402,905,088 / 1,939,537,920 bytes; MTP-off observed 7,143,424
|
|
2495
|
+
> bytes of swapout and MTP-on observed zero. The source result is correctly
|
|
2496
|
+
> labeled `observed`, not `pass`.
|
|
2497
|
+
|
|
2498
|
+
#### Cold/warm MTP and memory
|
|
2499
|
+
|
|
2500
|
+
| arm / turn | decode tok/s | end-to-end tok/s | final physical footprint |
|
|
2501
|
+
|---|---:|---:|---:|
|
|
2502
|
+
| MTP off · cold | 0.1330 | 0.1274 | 13,490,515,008 B |
|
|
2503
|
+
| MTP off · warm | 0.1190 | 0.1139 | 13,510,634,560 B (+19.2 MiB) |
|
|
2504
|
+
| MTP on · cold | 0.1557 | 0.1456 | 14,673,342,512 B |
|
|
2505
|
+
| MTP on · warm | **0.1577** | **0.1487** | 14,697,574,448 B (+23.1 MiB) |
|
|
2506
|
+
|
|
2507
|
+
MTP-on accepted 72/166 drafts over 56 verify forwards on each turn. Warm
|
|
2508
|
+
end-to-end throughput was 1.306x MTP-off. It is also only 55% of the rounded
|
|
2509
|
+
same-machine direct-Colibri MTP-on control (0.27 tok/s), and 0.1487 tok/s is
|
|
2510
|
+
7.43% of the aspirational 2 tok/s target—a **13.45x** remaining gap. The
|
|
2511
|
+
aspiration is not a release gate or a `fit` prediction.
|
|
2512
|
+
|
|
2513
|
+
#### Expert delivery and policy decisions
|
|
2514
|
+
|
|
2515
|
+
The replicated G6 control's median warm turn read exactly
|
|
2516
|
+
1,974,949,363,712 logical bytes from the expert artifact, or
|
|
2517
|
+
15.429291904 decimal GB per generated token. Its hit rate was 1.6597%; median
|
|
2518
|
+
main-tier disk-service p95 was 90.98 ms, foreground-wait p95 92.66 ms, and
|
|
2519
|
+
expert-layer-forward p95 167.84 ms. This is the measured reason the runtime is
|
|
2520
|
+
disk/serialization-bound rather than compute-bound.
|
|
2521
|
+
|
|
2522
|
+
| MTP-on policy (three paired repeats) | warm hit rate | disk GB/token | warm e2e tok/s | decision |
|
|
2523
|
+
|---|---:|---:|---:|---|
|
|
2524
|
+
| control | 1.66% | 15.429 | **0.149** | default |
|
|
2525
|
+
| startup auto-pin | 9.62% | 14.191 | 0.143 | off: 4.06% slower, +3.337 GiB footprint |
|
|
2526
|
+
| auto-pin + live LFRU | 9.62% | 14.191 | 0.148 | off: zero swaps; no benefit beyond run-order noise |
|
|
2527
|
+
|
|
2528
|
+
PILOT measurement found 69.90% next-layer top-8 precision/recall, but advisory
|
|
2529
|
+
`PILOT_K=4` left demand bytes unchanged and reduced warm throughput to 0.9746x.
|
|
2530
|
+
Two-step correction improved recall to 73.01% while reducing warm throughput
|
|
2531
|
+
10.13%. All learning/prediction/hint policies therefore remain off by default.
|
|
2532
|
+
|
|
2533
|
+
#### DSA and served API
|
|
2534
|
+
|
|
2535
|
+
The paired DSA matrix measured 24 eligible fresh-process cells (2K/8K × DSA
|
|
2536
|
+
off/on × MTP off/on × three repeats), all with exact cold/warm/repeat/MTP
|
|
2537
|
+
tokens. Positive decode delta means DSA was faster; negative wall delta means
|
|
2538
|
+
less total time.
|
|
2539
|
+
|
|
2540
|
+
| context | MTP | paired median decode delta | paired median wall delta | decision |
|
|
2541
|
+
|---:|---|---:|---:|---|
|
|
2542
|
+
| 2,048 | off | -2.80% | +4.14% | no speed claim |
|
|
2543
|
+
| 2,048 | on | -32.90% | +20.95% | regression |
|
|
2544
|
+
| 8,192 | off | +12.38% | -1.89% | below 5% total-wall win gate |
|
|
2545
|
+
| 8,192 | on | -34.33% | +8.19% | regression |
|
|
2546
|
+
| 32,768 | off/on | not run | not run | ineligible: 27.320/28.540 GiB exceeds 25 GiB |
|
|
2547
|
+
|
|
2548
|
+
The checkpoint's 21-full/57-shared schedule remains a semantic requirement,
|
|
2549
|
+
but no DSA product-speed claim is made. Stage-2 manifest SHA-256:
|
|
2550
|
+
`90b3fe4ed53714604b7a747991b3bb1b87aedbf57a139915065f5b4be42cda38`.
|
|
2551
|
+
|
|
2552
|
+
Finally, the fresh real-artifact G7 smoke returned HTTP 200 with correct
|
|
2553
|
+
envelopes for chat completions, text completions, Anthropic Messages, and
|
|
2554
|
+
OpenAI Responses; SSE used `text/event-stream`, emitted four events, ended in
|
|
2555
|
+
`[DONE]`, and reported the truthful `serial+spec` lane. Health, discovery,
|
|
2556
|
+
exact-plan stats, and post-run idle rows also passed. This is protocol/API
|
|
2557
|
+
evidence, not a throughput benchmark.
|
|
2558
|
+
|
|
2559
|
+
Primary raw records: machine-local `runs/colibri-g5/{summary,mtp-on,mtp-off}.json`,
|
|
2560
|
+
`runs/colibri-g6-learning-shakeout-2026-08-15/summary.json`, and
|
|
2561
|
+
`~/.cache/mlx-bun/evidence/glm52-dsa-stage2-2026-08-17/`.
|
|
2562
|
+
|
|
2563
|
+
### Served (warm) — the path agents actually use
|
|
2564
|
+
|
|
2565
|
+
decode tok/s · TTFT ms · server-ready s · steady RSS GB
|
|
2566
|
+
|
|
2567
|
+
| model | mlx-bun (mixed) | mlx-bun (bf16) | mlx-lm (bf16) | optiq (mixed)† |
|
|
2568
|
+
|---|---|---|---|---|
|
|
2569
|
+
| MiniCPM5-1B | **252.9** · 34 · 0.17 · 1.22 | — | — | 223.6 · 64 · 0.84 · 1.82 |
|
|
2570
|
+
| gemma-4-e4b | 55.7 · 44 · 0.36 · 7.14 | **57.3** · 48 · 0.36 | 53.5 · 218 · 0.98 · 7.55 | 53.4 · 221 · 0.78 · 7.53 |
|
|
2571
|
+
| gemma-4-12B | **25.9** · 85 · 0.38 · 9.46 | — | — | 25.5 · 326 · 1.24 · 9.86 |
|
|
2572
|
+
| gemma-4-26B | 54.2 · **45** · 0.47 · 18.25 | **55.0** · 44 · 0.47 | 52.3 · 228 · 0.77 · 4.87 | — |
|
|
2573
|
+
|
|
2574
|
+
† **The served `optiq (mixed)` cells are effectively bf16** — optiq's
|
|
2575
|
+
KV-quant patch is inert on mlx-lm 0.31.3's batched server path:
|
|
2576
|
+
`install_mixed_kv` hooks `mlx_lm.generate.maybe_quantize_kv_cache` and
|
|
2577
|
+
`mlx_lm.server.stream_generate`, but the server routes every *seedless*
|
|
2578
|
+
text chat request through `BatchGenerator`, which calls neither hook, and
|
|
2579
|
+
the h2h harness's server requests carry no `seed`. See
|
|
2580
|
+
`lab/repro/optiq-mixed-kv-inert/` for the mechanism + repro. The data
|
|
2581
|
+
fingerprint agrees: e4b optiq-mixed served 53.4 tok/s · 7.53 GB RSS ≡
|
|
2582
|
+
mlx-lm bf16's 53.5 · 7.55. Same caveat applies to any serve-mode
|
|
2583
|
+
optiq-mixed cell in raw `benchmarks-serve-*` artifacts dated ≤ 2026-07-06.
|
|
2584
|
+
The **Direct** and **Long context** optiq (mixed) rows below DID measure
|
|
2585
|
+
real quantized-KV execution (the legs passed `kv_bits=8` straight into
|
|
2586
|
+
`mlx_lm.generate.stream_generate` — old `bench.ts --baseline-kv config` —
|
|
2587
|
+
so the 64k collapse and the lower peaks are genuine quantized-KV
|
|
2588
|
+
behavior), but a second installer defect means the scheme was **uniform
|
|
2589
|
+
8-bit, not the per-layer map**: `install_mixed_kv`'s hook patch lands on
|
|
2590
|
+
the `generate` *function* that shadows `mlx_lm.generate` in mlx-lm's
|
|
2591
|
+
package namespace, never on the module, so mlx-lm's stock uniform
|
|
2592
|
+
`maybe_quantize_kv_cache` is what ran (empirically proven in the repro
|
|
2593
|
+
dir). Read "optiq (mixed)" in those two tables as "optiq (uniform kv8)".
|
|
2594
|
+
mlx-bun (mixed) columns are unaffected — our engine implements the
|
|
2595
|
+
per-layer scheme natively — and the L2 parity goldens stay valid: every
|
|
2596
|
+
`regen-*` oracle script applies the scheme explicitly (direct per-layer
|
|
2597
|
+
`to_quantized`, or calling optiq's patched hook by name), never through
|
|
2598
|
+
the dead serve-path indirection.
|
|
2599
|
+
|
|
2600
|
+
Across every served model: mlx-bun has the fastest decode and the fastest
|
|
2601
|
+
TTFT/startup (2–5×), at ~0% server tax vs its own direct engine.
|
|
2602
|
+
|
|
2603
|
+
### Served h2h post-consolidation (2026-08-22, e4b, single pass — directional)
|
|
2604
|
+
|
|
2605
|
+
Real servers via `bench-serve.ts` on merged main `4103ae1`; loaded machine
|
|
2606
|
+
(ambient loadavg ~3), so treat as directional until a quiet-box pass. Full
|
|
2607
|
+
findings + root-cause sweep: PLAN.md "Prefill vs mlx-lm (2026-08-22)".
|
|
2608
|
+
|
|
2609
|
+
| arm | prefill@1k tok/s | ttft cold/warm ms | decode tok/s | parity |
|
|
2610
|
+
|---|---:|---|---:|---|
|
|
2611
|
+
| mlx-bun | **1143** | 578 / **39** | **53.9** | ✓✓ byte-identical |
|
|
2612
|
+
| mlx-lm | 866 | 772 / 230 | 50.3 | (oracle) |
|
|
2613
|
+
|
|
2614
|
+
Served prefill stays a decisive mlx-bun win (+32% @1k, warm TTFT 5.9×)
|
|
2615
|
+
after the serving-architecture merge. Engine-direct prefill is
|
|
2616
|
+
parity-within-noise elsewhere (cpm5/12B/26B; e4b@256 fresh-process −12%
|
|
2617
|
+
is the one reproducible engine-level residual). Chunk-size tuning below
|
|
2618
|
+
the 2048 convention is NOT L1-safe: logits are convention-pinned in BOTH
|
|
2619
|
+
stacks (mlx reduction-order sensitivity; python drifts more than we do).
|
|
2620
|
+
Open lead from this pass: e4b agg×4 read 26.6 vs mlx-lm 107.3 — RESOLVED
|
|
2621
|
+
same day as a `443f333` regression (bf16 BatchedRotatingCache lost its
|
|
2622
|
+
signature-based route in the join merge → whole-batch drop on joiners;
|
|
2623
|
+
PLAN.md "agg×4 regression"). Post-fix: 122-126 tok/s aggregate, matching
|
|
2624
|
+
pre-merge.
|
|
2625
|
+
|
|
2626
|
+
### Direct (engine only)
|
|
2627
|
+
|
|
2628
|
+
decode tok/s · prefill tok/s · gen-peak GB
|
|
2629
|
+
|
|
2630
|
+
| model | mlx-bun (bf16) | mlx-bun (mixed) | mlx-lm (bf16) | optiq (mixed) |
|
|
2631
|
+
|---|---|---|---|---|
|
|
2632
|
+
| MiniCPM5-1B | 268.6 · 1817 · 1.01 | 241.9 · 1651 · 1.01 | **271.0** · 800 · 1.03 | 249.5 · 706 · 1.03 |
|
|
2633
|
+
| gemma-4-e4b | **57.1** · 304 · 6.61 | 55.7 · 283 · 6.61 | 56.5 · 373 · 6.65 | 56.1 · 368 · 6.65 |
|
|
2634
|
+
| gemma-4-12B | **26.0** · 168 · 8.99 | 25.8 · 166 · 8.99 | 25.9 · 141 · 9.10 | 25.7 · 137 · 9.00 |
|
|
2635
|
+
| gemma-4-26B | 55.0 · 206 · 17.71 | 53.9 · 208 · 17.71 | **55.6** · 187 · 17.78 | 55.0 · 190 · 17.72 |
|
|
2636
|
+
|
|
2637
|
+
Direct decode is at parity-to-slightly-behind mlx-lm (the residual host
|
|
2638
|
+
overhead per step); prefill leads on the larger models. See PLAN.md
|
|
2639
|
+
"Decode gap RESOLVED" for the root-cause/fix history.
|
|
2640
|
+
|
|
2641
|
+
### Logprob metadata readback (2026-07-29)
|
|
2642
|
+
|
|
2643
|
+
Paired internal before/after measurement on the M1 Max 32 GB,
|
|
2644
|
+
Qwen2.5-0.5B-Instruct-4bit, Bun 1.3.14: 256 generated tokens, two warmups,
|
|
2645
|
+
five randomized measured rounds. This isolates mlx-bun's API metadata
|
|
2646
|
+
readback; it is **not** a Bun-versus-Python FFI comparison.
|
|
2647
|
+
|
|
2648
|
+
| arm | before total / decode | after total / decode | overhead vs off, before → after |
|
|
2649
|
+
|---|---:|---:|---:|
|
|
2650
|
+
| off | 802.75 ms / 328.92 tok/s | 803.94 ms / 328.81 tok/s | control |
|
|
2651
|
+
| `logprobs` | 1,185.89 ms / 220.52 tok/s | 802.77 ms / 329.18 tok/s | +47.7% → −0.1% |
|
|
2652
|
+
| `top_logprobs=5` | 1,354.21 ms / 192.69 tok/s | 856.24 ms / 307.63 tok/s | +68.7% → +6.5% |
|
|
2653
|
+
|
|
2654
|
+
The fix reads uint32 IDs directly and expands the few bf16/f16 values on the
|
|
2655
|
+
host instead of queueing `astype(float32)` behind the already-dispatched next
|
|
2656
|
+
decode step. The off control stayed flat; all 40 parity checks and all 1,280
|
|
2657
|
+
selected/top-k comparisons were exact. Clean commits: before `00e597e`, after
|
|
2658
|
+
`b1cb7cb`. Raw artifacts are recorded in the Phase 22 ledger in
|
|
2659
|
+
`docs/archive/investigations/pre-colibri-stabilization.md`.
|
|
2660
|
+
|
|
2661
|
+
### Long context (gemma-4-12B) — where the gap opens
|
|
2662
|
+
|
|
2663
|
+
decode tok/s · gen-peak GB
|
|
2664
|
+
|
|
2665
|
+
| context | mlx-bun (bf16) | mlx-bun (mixed) | mlx-lm (bf16) | optiq (mixed) |
|
|
2666
|
+
|---|---|---|---|---|
|
|
2667
|
+
| 16k | 23.9 · 11.82 | 23.5 · 10.61 | 23.9 · 11.72 | 21.6 · 11.19 |
|
|
2668
|
+
| 64k | **20.9** · 15.77 | 18.7 · 10.46 | 20.9 · 15.91 | 12.3 · 14.89 |
|
|
2669
|
+
|
|
2670
|
+
At 64k mlx-bun holds parity with mlx-lm on bf16 while optiq collapses to
|
|
2671
|
+
12.3 tok/s; mlx-bun's mixed-KV trades ~2 tok/s for ~5 GB lower peak.
|
|
2672
|
+
|
|
2673
|
+
### Attempted but failed (2026-06-14)
|
|
2674
|
+
|
|
2675
|
+
- `gemma-4-12B/optiq/kv=config`: `quantized_matmul` weight/scales
|
|
2676
|
+
shape mismatch (upstream optiq bug; tracked). _(Relabeled from the
|
|
2677
|
+
old-legend name "e4b" = hash `5b…` = 12B; no gen-peak was recorded for
|
|
2678
|
+
this failed run, so the model id here is inferred from the legend, not
|
|
2679
|
+
fingerprinted.)_
|
|
2680
|
+
|
|
2681
|
+
---
|
|
2682
|
+
|
|
2683
|
+
## 3. Quality — for non-bit-exact (Lab) optimizations only
|
|
2684
|
+
|
|
2685
|
+
When a custom path trades bit-exactness for speed, quantify the cost so a
|
|
2686
|
+
perf win is only claimed with its quality delta — e.g. *"+23% tok/s while
|
|
2687
|
+
holding ±5% on the 6-test mean."*
|
|
2688
|
+
|
|
2689
|
+
- **6-test mean** — mean score across `src/eval/tasks/`: bfcl, gsm8k,
|
|
2690
|
+
hashhop, humaneval, ifeval, mmlu — optimized path vs the compatible
|
|
2691
|
+
upstream.
|
|
2692
|
+
- **KL divergence** — optimized vs compatible token distribution.
|
|
2693
|
+
|
|
2694
|
+
This section is the home for a Lab experiment's quality measurements
|
|
2695
|
+
when it's promoted (the bar: paired-A/B win vs L1 on a stable pass +
|
|
2696
|
+
KL PASS — see docs/design/unified-engine-frontier-plan.md §6-7).
|
|
2697
|
+
|
|
2698
|
+
### TurboQuant KV quality-vs-bpw (2026-07-06, M1 Max 32 GB, MiniCPM5-1B)
|
|
2699
|
+
|
|
2700
|
+
> Note: measured on an M1 Max 32 GB, not this file's M4 Pro reference
|
|
2701
|
+
> box — valid as a paired quality/KL measurement (machine-independent),
|
|
2702
|
+
> not as a perf number.
|
|
2703
|
+
|
|
2704
|
+
Opt-in memory/context scheme (`--kv-quant turbo[:k<bits>v<bits>]`), not a
|
|
2705
|
+
speed lever. Teacher-forced serving-decode KL vs bf16 KV (8×128 tokens, 32
|
|
2706
|
+
decode steps, `eval-turboquant-curve.ts (deleted; git history)`); affine rows same harness:
|
|
2707
|
+
|
|
2708
|
+
| scheme | effective KV bits | KV compression | mean KL vs bf16 |
|
|
2709
|
+
|---|---|---|---|
|
|
2710
|
+
| uniform kv8 (g64) | 8.50 | 1.88× | 0.00246 |
|
|
2711
|
+
| turbo k8v8 | 8.75 | 1.83× | 0.00214 |
|
|
2712
|
+
| turbo k8v4 | 6.75 | 2.37× | 0.00936 |
|
|
2713
|
+
| **turbo k8v3 (default)** | **6.25** | **2.56×** | **0.0325** |
|
|
2714
|
+
| uniform kv4 (g64) | 4.50 | 3.56× | 0.0516 |
|
|
2715
|
+
| turbo k4v3 | 4.25 | 3.76× | 0.0622 |
|
|
2716
|
+
| turbo k4v2 | 3.75 | 4.27× | 0.205 |
|
|
2717
|
+
|
|
2718
|
+
Read: turbo k8v3 beats uniform kv4's KL at 2.56× compression; k4v3 is
|
|
2719
|
+
on-curve with affine at matched bits; 2-bit values are the cliff (matches
|
|
2720
|
+
the TurboQuant paper's law). Codec is bit-exact vs the vendored vllm-metal
|
|
2721
|
+
reference (goldens/turboquant.json); details in
|
|
2722
|
+
docs/design/turboquant.md.
|
|
2723
|
+
|
|
2724
|
+
## 4. Composition — feature-default decisions (measured, per pair)
|
|
2725
|
+
|
|
2726
|
+
The doctrine (docs/design/speculative-decoding.md Phase 4e): a feature is ON by
|
|
2727
|
+
default for a (model, config) pair only when it WINS a clean-machine
|
|
2728
|
+
paired A/B on that pair; losing configs stay documented default-off
|
|
2729
|
+
levers. This section records the decisions and the numbers behind them.
|
|
2730
|
+
|
|
2731
|
+
### Packed Trellis with KV4/MTP and paired prefixes, M4 Pro, 2026-09-08
|
|
2732
|
+
|
|
2733
|
+
The configured serial suite passes every phase on the required 12.14 GiB
|
|
2734
|
+
packed Trellis artifact at clean commit `1a80401`, with unchanged source
|
|
2735
|
+
hashes throughout. Machine: `Joshs-MBP-2025.local`, Apple M4 Pro, 24 GB,
|
|
2736
|
+
Bun 1.4.0, bundled MLX 0.32.2. Quiet preflight passes. This is one run,
|
|
2737
|
+
not a matched original/final performance claim or a new Kanban task.
|
|
2738
|
+
|
|
2739
|
+
| Metric | Result |
|
|
2740
|
+
|---|---:|
|
|
2741
|
+
| Short-prompt decode, median of five 192-token samples | **18.806 tok/s** |
|
|
2742
|
+
| Short complete-request time, median | **11.389 s** |
|
|
2743
|
+
| Output / complete-request time, median | 16.859 tok/s |
|
|
2744
|
+
| Cold TTFT, median of three approximately 1K probes | 6.537 s |
|
|
2745
|
+
| Warm TTFT, 754 cached tokens | **94.586 ms** |
|
|
2746
|
+
| Approximately 1K prefill estimate, median | 115.747 tok/s |
|
|
2747
|
+
| Context probe, actual input tokens | 2,677 |
|
|
2748
|
+
| Context prefill estimate | 116.808 tok/s |
|
|
2749
|
+
| Context decode, median of three samples | 22.763 tok/s |
|
|
2750
|
+
| Cached context TTFT | 95.434 ms |
|
|
2751
|
+
| Peak sampled process RSS | 11,973.656 MiB (11.693 GiB) |
|
|
2752
|
+
| Phase failures | 0 |
|
|
2753
|
+
|
|
2754
|
+
Arguments are `--draft-kind mtp --num-draft-tokens 2 --kv-quant 4
|
|
2755
|
+
--prompt-cache 4`, with the folded RTN4 MTP draft. Runtime overrides select
|
|
2756
|
+
Trellis variant 13, uniform KV4 speculation, paired MTP prefixes and prefill
|
|
2757
|
+
chunks of 256. Async Trellis expansion, early-first-token and structural fill
|
|
2758
|
+
are off. Workload seed is `pr47-block-0`, thinking is enabled, and the
|
|
2759
|
+
requested context target is 4,096; the table reports the actual token count.
|
|
2760
|
+
All five short samples emit exactly 192 tokens with no reused prefix.
|
|
2761
|
+
|
|
2762
|
+
The speculative prefix store is RAM-only. Restarting restores zero cached
|
|
2763
|
+
tokens and the context request takes 24.404 seconds to first output. The
|
|
2764
|
+
ordinary SSD flush returns durable with zero entries; this is not proof of
|
|
2765
|
+
speculative SSD persistence. No stock mlx-lm arm supports this packed artifact.
|
|
2766
|
+
The faster context decode sample reflects a different prompt and MTP acceptance
|
|
2767
|
+
workload; it does not establish that increasing context makes inference faster.
|
|
2768
|
+
|
|
2769
|
+
Raw evidence: `reports/qwen38-rd/pr47-trellis-kv4-mtp-serve.md` and its `.md.json`
|
|
2770
|
+
companion. These serving timings are separate from the completed fresh Pi
|
|
2771
|
+
Kanban measurement below.
|
|
2772
|
+
|
|
2773
|
+
### Original and optimized serving diagnostics, M4 Pro, 2026-09-07
|
|
2774
|
+
|
|
2775
|
+
Machine: `Joshs-MBP-2025.local`, Apple M4 Pro, 24 GB, Bun 1.4.0.
|
|
2776
|
+
`bench-serve.ts all` used workload seed `kanban-final-0`, thinking enabled,
|
|
2777
|
+
192 requested output tokens and five decode samples. These are earlier
|
|
2778
|
+
diagnostic runs, with existing swap, rather than final-PR quiet acceptance.
|
|
2779
|
+
All columns below use the serial serving lane and the required packed target
|
|
2780
|
+
weights. Baseline uses `673b43f`, Trellis variant 6 and the older native library;
|
|
2781
|
+
optimized arms use variant 13, the lossless interleaved artifact and the local
|
|
2782
|
+
MLX 0.32.2 candidate. Each run's source stayed fixed.
|
|
2783
|
+
|
|
2784
|
+
All three serving arms use **bf16 KV**, with `--kv-quant off`. The MTP arm
|
|
2785
|
+
adds two drafts and paired RAM prefixes. This differs from the completed
|
|
2786
|
+
long Kanban task's KV4 configuration. These runs predate the later ownership
|
|
2787
|
+
and bounded-range fixes, so they do not measure the exact final task revision.
|
|
2788
|
+
|
|
2789
|
+
| Serial serving metric | Original | Optimized, ordinary decode | Optimized, MTP + RAM cache |
|
|
2790
|
+
|---|---:|---:|---:|
|
|
2791
|
+
| Median decode, tok/s | 10.140 | 11.712 | 19.426 |
|
|
2792
|
+
| Cold-request TTFT, ms | 5,923.576 | 6,164.498 | 5,801.504 |
|
|
2793
|
+
| Cached TTFT, ms | 190.841 | 436.308 | 91.916 |
|
|
2794
|
+
| 1K prefill, tok/s | 127.963 | 122.962 | 130.522 |
|
|
2795
|
+
| Peak process RSS, reported MB | 11,958.984 | 13,859.828 | 12,061.219 |
|
|
2796
|
+
|
|
2797
|
+
Ordinary decode improves **15.5%**. The MTP configuration improves decode
|
|
2798
|
+
**91.6%** relative to the original, with cached TTFT **51.8% lower**.
|
|
2799
|
+
Its cold TTFT changes by -2.1%, prefill by +2.0%, and sampled RSS by +0.9%.
|
|
2800
|
+
Ordinary decode's gain does not extend to every metric: its cached TTFT and
|
|
2801
|
+
RSS regress in this diagnostic. The percentages describe these specific
|
|
2802
|
+
serving configurations; they are not a measured Kanban task-time reduction.
|
|
2803
|
+
|
|
2804
|
+
The baseline context phase crashed and recovered on retry; no context-phase
|
|
2805
|
+
speedup is claimed here. MTP prefix state is RAM-only: the restart probe
|
|
2806
|
+
restored zero tokens and does not establish SSD persistence. Stock mlx-lm
|
|
2807
|
+
cannot read this packed Trellis artifact, so it supplies no same-artifact
|
|
2808
|
+
serving baseline for these rows.
|
|
2809
|
+
|
|
2810
|
+
Raw evidence: `reports/qwen38-rd/kanban-final/suite-driver.json`,
|
|
2811
|
+
`baseline-suite.md.json`, `optimized-ordinary-suite.md.json`, and
|
|
2812
|
+
`optimized-mtp-cache-suite.md.json`. The driver records all commands,
|
|
2813
|
+
environments, source hashes and exits. The completed task and its separate
|
|
2814
|
+
acceptance are recorded below.
|
|
2815
|
+
|
|
2816
|
+
### Fresh Pi kanban diagnostic, M4 Pro, 2026-09-07
|
|
2817
|
+
|
|
2818
|
+
Machine: `Joshs-MBP-2025.local`, M4 Pro, 24 GB; Bun 1.4.0, Pi 0.85.1,
|
|
2819
|
+
MLX 0.32.2. These are task diagnostics with existing swap. The first attempt
|
|
2820
|
+
also had a brief background browser-test CPU burst. Neither is a quiet-machine
|
|
2821
|
+
speed claim.
|
|
2822
|
+
The model is the required 12.14 GiB packed Qwen3.8-27B Trellis artifact with
|
|
2823
|
+
lossless interleaving. The selected Luke profile is
|
|
2824
|
+
`qwen3.8-27b-q3_k_xl-coding-128k`, pinned at repository commit
|
|
2825
|
+
`3288d1918fa6140c10f3b2de2d37f9d717a5ab75`. It uses the unchanged prompt,
|
|
2826
|
+
xhigh thinking, temperature 0.6, seed 42 and 131072 context. The MLX mapping
|
|
2827
|
+
uses target affine KV4 group64, two MTP drafts, paired RAM prompt prefixes
|
|
2828
|
+
and 256-token prefill chunks.
|
|
2829
|
+
|
|
2830
|
+
| Attempt | Time until Pi stopped | Output tokens | Overall tok/s | First-turn tok/s, including prefill | First reasoning TTFT | Peak server + Pi RSS | Result |
|
|
2831
|
+
|---|---:|---:|---:|---:|---:|---:|---|
|
|
2832
|
+
| History fixed; original tool-value parser | 65m 30.245s | 53,631 | 13.646 | 15.965 | 22.869s | 12.042 GiB | Failed: only HTML and two JS modules; final edit call remained assistant text |
|
|
2833
|
+
| History and tool-value parsing fixed | 106m 6.531s | 82,015 confirmed | 12.882 | 16.154 | 22.892s | 13.795 GiB | Failed inference: Metal out of memory at the 85,238-token request; Pi did not finish |
|
|
2834
|
+
|
|
2835
|
+
All four request prompt counts matched independent renders. Later requests
|
|
2836
|
+
reused 2,549, 53,174 and 54,859 prompt tokens, with MTP active. Pi had no
|
|
2837
|
+
automatic retries or compactions. Its clean process exit did not mean the
|
|
2838
|
+
app was complete: the mandatory README was absent and most app files were
|
|
2839
|
+
never written. The untouched output fails acceptance. No successful task
|
|
2840
|
+
completion time or matched task-time speedup is established by this row.
|
|
2841
|
+
|
|
2842
|
+
The saved final edit parameter is valid JSON. The engine decoded XML
|
|
2843
|
+
entities before JSON parsing and its repair pass misidentified the nested
|
|
2844
|
+
array as the outer call. The corrected parser preserves the complete argument
|
|
2845
|
+
array through the actual tokenizer and streaming path.
|
|
2846
|
+
|
|
2847
|
+
The fresh attempt with both fixes completed ten requests. Every completed
|
|
2848
|
+
prompt count matched the independent render and every response used MTP.
|
|
2849
|
+
The aggregate accepted/drafted ratio was 80.038%. The first tool transition
|
|
2850
|
+
took 524.244 seconds to first output while processing newly generated history.
|
|
2851
|
+
Later requests reused progressively longer prompt prefixes. The cache still
|
|
2852
|
+
captures prompt boundaries rather than the newly generated history.
|
|
2853
|
+
|
|
2854
|
+
The eleventh request reached a Metal allocation failure after its first
|
|
2855
|
+
reasoning fragment. Its terminal usage was unavailable, so the output total
|
|
2856
|
+
counts only completed responses. The wall-clock interval includes that failed
|
|
2857
|
+
request, prefill, tools and agent overhead. Ten completed response intervals,
|
|
2858
|
+
excluding TTFT, average 15.270 output tokens/s. This is distinct from both
|
|
2859
|
+
overall task throughput and the short-context serving-suite decode rate.
|
|
2860
|
+
There were no retries, compactions or tool errors. Engine source hashes stayed
|
|
2861
|
+
fixed. All inference processes exited during bounded cleanup.
|
|
2862
|
+
|
|
2863
|
+
The untouched app has HTML, CSS, twelve JavaScript modules and package.json,
|
|
2864
|
+
but no README. Syntax checks pass. A separate browser smoke test after server
|
|
2865
|
+
shutdown shows the default columns and keyboard card creation work, but opening
|
|
2866
|
+
the editor throws `ReferenceError: renderLabels is not defined`. Remaining UI
|
|
2867
|
+
checks were not run after that blocking failure. No app edits or repair prompts
|
|
2868
|
+
were supplied. These are findings about an incomplete artifact, not a completed
|
|
2869
|
+
model submission. No successful completion time or matched task-time gain exists.
|
|
2870
|
+
|
|
2871
|
+
Process RSS does not measure all Metal allocations. The out-of-memory failure
|
|
2872
|
+
does not establish the model's architectural context limit; the tested KV4,
|
|
2873
|
+
MTP and retained-prefix combination needs a separate memory diagnosis.
|
|
2874
|
+
|
|
2875
|
+
Protocol and design: [decode-speed-program §7.7](../../design/decode-speed-program.md#77-gates-scheduling-and-completion).
|
|
2876
|
+
Raw evidence: `reports/qwen38-rd/kanban-final/luke-q3-128k-xhigh-history-fixed/`
|
|
2877
|
+
and `luke-q3-128k-xhigh-tool-values-fixed/`, including `quality-static.json`,
|
|
2878
|
+
`quality-browser.json` and screenshots. Portable report:
|
|
2879
|
+
`reports/qwen38-rd/kanban-final/comparison.html`.
|
|
2880
|
+
|
|
2881
|
+
### Kanban capacity diagnosis, M4 Pro, 2026-09-08
|
|
2882
|
+
|
|
2883
|
+
Native Bun screen on `Joshs-MBP-2025.local`, Apple M4 Pro, 24 GB, using the
|
|
2884
|
+
same 12.14 GiB target, MTP head, MLX 0.32.2 candidate and KV4/prefix settings
|
|
2885
|
+
as the failed Pi attempt above. The saved failing history renders to 85,238
|
|
2886
|
+
tokens. Fixed text tokens extend it to 110,000 for this capacity screen.
|
|
2887
|
+
No Pi task runs in this screen. Sampling follows the selected profile, but
|
|
2888
|
+
EOS stopping is disabled to require a short continuation. This is neither
|
|
2889
|
+
a fresh task result nor a quiet-machine performance claim.
|
|
2890
|
+
|
|
2891
|
+
The unchanged control finished target prefill and emitted one token, then
|
|
2892
|
+
failed with Metal out of memory in the first MTP draft round. Its wall time
|
|
2893
|
+
was 1,482.497 seconds. Peak active Metal allocation reached 19,451,721,310
|
|
2894
|
+
bytes against a recommended working set of 19,069,665,280 bytes. Immediately
|
|
2895
|
+
before draft prefill, active allocation was 14,593,938,440 bytes; at the
|
|
2896
|
+
first emitted token it was 17,494,527,842 bytes. The retained prefix reported
|
|
2897
|
+
2,633,836,544 logical bytes. These counters measure different things from
|
|
2898
|
+
process RSS and do not establish a model context limit. Source hashes stayed
|
|
2899
|
+
fixed; the worker exited with failure and bounded cleanup completed.
|
|
2900
|
+
|
|
2901
|
+
Raw control: `reports/qwen38-rd/kanban-capacity-110k-control.json` and its
|
|
2902
|
+
allocation event log. A focused small ownership regression retains 8,405,016
|
|
2903
|
+
bytes before the fix, despite requiring only small KV state and one hidden
|
|
2904
|
+
row. The isolated candidate now evaluates draft KV at each existing prefill
|
|
2905
|
+
chunk and materializes the retained final hidden row. The ownership,
|
|
2906
|
+
prefix-position and provider-disposal tests pass. Full-model exactness and
|
|
2907
|
+
large-context acceptance are checked separately. A sampling-failure
|
|
2908
|
+
regression retains 524,288 bytes before scoped disposal; it now passes the
|
|
2909
|
+
under-4-KiB cleanup guard without running GC after the failure.
|
|
2910
|
+
|
|
2911
|
+
The final-source small native comparison uses the same first 8,192 history
|
|
2912
|
+
tokens and generates 32 tokens twice. Before and after the ownership changes,
|
|
2913
|
+
both responses and all MTP acceptance decisions match exactly. Each process
|
|
2914
|
+
first prefills from zero, then restores 8,191 cached tokens. Peak active
|
|
2915
|
+
allocation is 13,330,783,014 bytes before and 13,105,695,458 after. Both source
|
|
2916
|
+
manifests stay fixed. This is one correctness/allocation comparison, not a
|
|
2917
|
+
request-time speed claim. Typechecks pass. Evidence: `kanban-capacity-8k-final-comparison.json`
|
|
2918
|
+
and its two referenced control/candidate reports in `reports/qwen38-rd/`.
|
|
2919
|
+
|
|
2920
|
+
The final native capacity screen passes at 110,000 prompt tokens. It completes
|
|
2921
|
+
three identical 256-token continuations, with 109,999 tokens restored on each
|
|
2922
|
+
cached request. Between the latter two, an intentional output-sink error after
|
|
2923
|
+
eight emitted tokens exercises request cleanup. Retained active allocation is
|
|
2924
|
+
14,911,641,794 bytes after every completed or intentionally failed request.
|
|
2925
|
+
The next request recovers in the same process and reproduces the continuation.
|
|
2926
|
+
Peak active allocation is 17,981,018,362 bytes, 1,470,702,948 bytes below the
|
|
2927
|
+
failing control, despite the longer continuation. The first request takes
|
|
2928
|
+
1,525.095 seconds including full prefill; the two complete cached requests take
|
|
2929
|
+
33.148 and 33.175 seconds. Instrumented synthetic-context timings are not
|
|
2930
|
+
Kanban completion estimates. Final provider/weight disposal leaves 101,892,102
|
|
2931
|
+
active bytes; the equal per-request counters establish no incremental retention
|
|
2932
|
+
from the injected failure, not zero global runtime allocation. The worker exits
|
|
2933
|
+
successfully, its source hashes stay fixed and its deadline is not reached.
|
|
2934
|
+
|
|
2935
|
+
The main source has the same ownership fixes. Its focused memory/provider tests
|
|
2936
|
+
and a real-target MTP/non-MTP short greedy identity gate pass, as do all
|
|
2937
|
+
typechecks.
|
|
2938
|
+
Native evidence: `reports/qwen38-rd/kanban-capacity-110k-owned-final.json`.
|
|
2939
|
+
|
|
2940
|
+
The saved-history HTTP gate also passes on the isolated candidate. It first
|
|
2941
|
+
replays the exact failed request, then appends that response and synthetic
|
|
2942
|
+
tool/user history to test growth. Tool calls are recorded but never executed
|
|
2943
|
+
by this diagnostic. Each response allows up to 512 output tokens and stops
|
|
2944
|
+
naturally. Both repeated responses preserve all text, tool arguments, output
|
|
2945
|
+
counts and MTP acceptance decisions.
|
|
2946
|
+
|
|
2947
|
+
| Prompt tokens | Cached tokens | Output tokens | Complete request, s | TTFT, s |
|
|
2948
|
+
|---:|---:|---:|---:|---:|
|
|
2949
|
+
| 85,238 | 0 | 42 | 988.103 | 984.951 |
|
|
2950
|
+
| 85,238 | 85,237 | 42 | 3.283 | 0.225 |
|
|
2951
|
+
| 110,014 | 85,237 | 92 | 401.843 | 393.126 |
|
|
2952
|
+
| 110,014 | 110,013 | 92 | 8.931 | 0.255 |
|
|
2953
|
+
|
|
2954
|
+
Source hashes stay fixed and server cleanup exits successfully. This validates
|
|
2955
|
+
serving capacity and cache reuse, not a completed Kanban task. Raw evidence:
|
|
2956
|
+
`reports/qwen38-rd/kanban-memory-http-owned.json` and the saved request/response
|
|
2957
|
+
files beside it. These checks exercise short continuations. The fresh Pi
|
|
2958
|
+
retry below still fails during sustained generation.
|
|
2959
|
+
|
|
2960
|
+
During the saved-history HTTP prefill, simultaneous read-only `/health` and
|
|
2961
|
+
`/stats` requests both returned 200, taking 4,776.475 and 4,776.682 ms. This
|
|
2962
|
+
single busy-server observation does not establish an idle baseline or latency
|
|
2963
|
+
distribution. It identifies responsiveness during native prefill for a separate
|
|
2964
|
+
serving check. Evidence: `reports/qwen38-rd/kanban-memory-http-responsiveness.json`.
|
|
2965
|
+
|
|
2966
|
+
### Fresh Pi Kanban after MTP ownership fixes, M4 Pro, 2026-09-08
|
|
2967
|
+
|
|
2968
|
+
The fresh retry on `Joshs-MBP-2025.local`, Apple M4 Pro, 24 GB, failed with
|
|
2969
|
+
Metal out of memory after **106m 5.416s**. It used the same 12.14 GiB target,
|
|
2970
|
+
published Luke Q3 128K xhigh profile and unchanged prompt as the preceding
|
|
2971
|
+
attempt. The source and every saved request's profile pass the post-run audit.
|
|
2972
|
+
The first request body is byte-identical to the preceding attempt; its entire
|
|
2973
|
+
response and MTP acceptance trace also match. Later history includes actual
|
|
2974
|
+
tool results, including changed directory timestamps.
|
|
2975
|
+
|
|
2976
|
+
Eight requests completed, reporting **73,831 output tokens**. The ninth
|
|
2977
|
+
request started with **77,077 prompt tokens**, emitted its first output after
|
|
2978
|
+
26.415 seconds and failed after 780.891 seconds, during sustained decode.
|
|
2979
|
+
Its terminal usage is missing. Retokenizing delivered reasoning estimates
|
|
2980
|
+
another 5,659 tokens, but excludes buffered tool arguments, so the full
|
|
2981
|
+
generation count is unknown. The completed-response rate after first output
|
|
2982
|
+
is 15.658 tok/s; this excludes prefill, tool time and the failed response.
|
|
2983
|
+
Peak combined server/Pi RSS is **13.836 GiB**. Completed requests report
|
|
2984
|
+
79.911% MTP acceptance. There were no retries, compactions or tool execution
|
|
2985
|
+
errors. Pi exited with code zero but reported a terminal error; the task
|
|
2986
|
+
therefore failed. No successful completion time or task-time speedup is
|
|
2987
|
+
established.
|
|
2988
|
+
|
|
2989
|
+
The untouched app supplies its README and passes syntax, basic card creation,
|
|
2990
|
+
board/theme persistence, column creation/rename and between-column card drag
|
|
2991
|
+
checks. The card editor throws `ReferenceError: renderLabels is not defined`;
|
|
2992
|
+
the archive panel throws `TypeError: K.render.renderArchive is not a function`.
|
|
2993
|
+
Required functional acceptance fails. Reorder interaction probes remain
|
|
2994
|
+
unconfirmed because their input simulation needs validation. Independent UI
|
|
2995
|
+
checks ran only after inference exited. No app code was edited and no repair
|
|
2996
|
+
prompts were supplied.
|
|
2997
|
+
|
|
2998
|
+
The short native and HTTP capacity checks above did not reproduce this long
|
|
2999
|
+
decode failure. It motivated the sustained allocation check below. Raw result,
|
|
3000
|
+
source/profile audit and untouched
|
|
3001
|
+
app checks: `reports/qwen38-rd/kanban-final/luke-q3-128k-xhigh-mtp-memory-fixed/`
|
|
3002
|
+
contains `result.json`, `measurement-audit.json`, `quality.json` and its
|
|
3003
|
+
referenced evidence.
|
|
3004
|
+
|
|
3005
|
+
### Sustained Kanban decode allocation diagnosis, M4 Pro, 2026-09-08
|
|
3006
|
+
|
|
3007
|
+
A fresh native process loaded the failed task's saved **77,077-token** request
|
|
3008
|
+
and generated **12,288 tokens** with the same model, MTP, KV and sampling
|
|
3009
|
+
settings. EOS stopping was disabled for this bounded diagnostic; no tools
|
|
3010
|
+
were executed. The unchanged control completed in 2,408.753 seconds including
|
|
3011
|
+
923.348 seconds to first output. Decode was 8.272 tok/s. Peak active MLX
|
|
3012
|
+
allocation was **18,204,808,450 bytes**; **1,593,360,390 bytes** remained active
|
|
3013
|
+
after provider/weights disposal and allocator-cache clearing. Source hashes
|
|
3014
|
+
stayed fixed. This is a saved-history diagnostic, not a fresh task result or
|
|
3015
|
+
a quiet-machine speed claim.
|
|
3016
|
+
|
|
3017
|
+
The large-range cache retained every distinct causal-mask range above 65,536
|
|
3018
|
+
elements. Early comparable rounds each added **311,296 bytes**, matching the
|
|
3019
|
+
page-rounded int32 range allocation. A focused regression with 256 changing
|
|
3020
|
+
context lengths retained **79,790,080 bytes** in the old implementation and
|
|
3021
|
+
**7,258,112 bytes** after bounding cached array data to 8 MiB. Three oversized
|
|
3022
|
+
ranges retained **37,748,736 bytes** before and **zero additional bytes** after.
|
|
3023
|
+
The regression fails before the change and passes after it, including exact
|
|
3024
|
+
range values, vocabulary reuse and lazy-view ownership after eviction. Eight
|
|
3025
|
+
focused main-source tests, the candidate regression and both workspace
|
|
3026
|
+
typechecks pass.
|
|
3027
|
+
|
|
3028
|
+
Reconstructing the target prefill lengths and verification windows from the
|
|
3029
|
+
control's acceptance trace predicts 4,685 distinct large mask ranges occupying
|
|
3030
|
+
1,592,344,576 page-rounded bytes. That accounts for more than 99.9% of the
|
|
3031
|
+
observed allocation left after model disposal. This is allocation attribution
|
|
3032
|
+
from the recorded execution and source, not a measurement of every cache entry.
|
|
3033
|
+
|
|
3034
|
+
The bounded-cache full-model repeat passes: all **12,288 output tokens** and
|
|
3035
|
+
all **4,638 MTP acceptance decisions** are identical. Source and harness hashes
|
|
3036
|
+
stay fixed, with `src/mlx/ops.ts` the only engine difference between arms.
|
|
3037
|
+
Both runs exit normally without cleanup errors.
|
|
3038
|
+
|
|
3039
|
+
| Native diagnostic metric | Unbounded cache | Bounded cache |
|
|
3040
|
+
|---|---:|---:|
|
|
3041
|
+
| Complete request time | 2,408.753 s | 2,461.051 s |
|
|
3042
|
+
| Time to first output | 923.348 s | 939.902 s |
|
|
3043
|
+
| Decode rate | 8.272 tok/s | 8.078 tok/s |
|
|
3044
|
+
| Peak active MLX allocation | 18,204,808,450 B | 16,622,195,970 B |
|
|
3045
|
+
| Active MLX allocation after model disposal | 1,593,360,390 B | 8,224,774 B |
|
|
3046
|
+
| Observed peak process RSS | 14,324,711,424 B | 12,745,523,200 B |
|
|
3047
|
+
| OS lifetime peak process footprint | 18,969,882,768 B | 18,826,963,720 B |
|
|
3048
|
+
|
|
3049
|
+
Peak active allocation falls by **1,582,612,480 bytes**. The single diagnostic
|
|
3050
|
+
pair takes **2.171% longer**, so it establishes a memory/ownership correction,
|
|
3051
|
+
not a throughput gain. RSS, active allocation and physical footprint remain
|
|
3052
|
+
distinct measurements. The process monitor started during control prefill
|
|
3053
|
+
and before candidate prefill; native allocation instrumentation is identical.
|
|
3054
|
+
The fresh Pi task with this correction completed; its separate task result
|
|
3055
|
+
and functional acceptance are recorded below.
|
|
3056
|
+
|
|
3057
|
+
Raw evidence: `reports/qwen38-rd/kanban-sustained-77k-owned-control.json`, its
|
|
3058
|
+
allocation/process-memory traces, `kanban-arange-allocation-evidence.json`,
|
|
3059
|
+
`kanban-arange-regression.json`, `kanban-arange-micro-memory.json` and
|
|
3060
|
+
`kanban-arange-reconstruction.json`. Full-model comparison:
|
|
3061
|
+
`kanban-sustained-arange-comparison.json`, with both raw runs and their traces.
|
|
3062
|
+
|
|
3063
|
+
### Completed fresh Pi Kanban with bounded range cache, M4 Pro, 2026-09-08
|
|
3064
|
+
|
|
3065
|
+
The untouched app passes the required functional checks after a fresh Pi run
|
|
3066
|
+
on `Joshs-MBP-2025.local`, Apple M4 Pro, 24 GB, using the required 12.14 GiB
|
|
3067
|
+
Trellis target. The published Luke Q3 coding 128K profile, unchanged prompt,
|
|
3068
|
+
xhigh thinking, sampling and seed 42 remain fixed. The candidate uses MLX
|
|
3069
|
+
0.32.2, target KV4, MTP depth 2 and paired RAM prefixes. Processes, application
|
|
3070
|
+
caches, Pi session and task workspace started fresh; OS file cache was not purged.
|
|
3071
|
+
|
|
3072
|
+
| Completed task metric | Result |
|
|
3073
|
+
|---|---:|
|
|
3074
|
+
| Prompt submitted to Pi settled | **3h 33m 7.685s** |
|
|
3075
|
+
| Including server startup | 3h 33m 8.581s |
|
|
3076
|
+
| First request time to first output | 23.145 s |
|
|
3077
|
+
| Reported output tokens, including reasoning and compaction | **130,494** |
|
|
3078
|
+
| Completed inference requests | 62 |
|
|
3079
|
+
| Output / whole task elapsed time | 10.205 tok/s |
|
|
3080
|
+
| Completed-response rate after first output | 13.904 tok/s |
|
|
3081
|
+
| Sum of request time before first output | 56.665 min |
|
|
3082
|
+
| MTP draft-token acceptance | 79.706% |
|
|
3083
|
+
| Peak sampled combined server/Pi RSS | 11.916 GiB |
|
|
3084
|
+
|
|
3085
|
+
All 443 source, profile, request, usage and timing audit checks pass. Every
|
|
3086
|
+
response has terminal usage; the output total is exact. Pi and the server
|
|
3087
|
+
exit normally, with no inference error or automatic retry. Pi encounters
|
|
3088
|
+
seven tool execution errors during its own debugging and completes the task
|
|
3089
|
+
without external repair prompts.
|
|
3090
|
+
|
|
3091
|
+
One context compaction is included in the total. Its summary request uses
|
|
3092
|
+
90,214 input tokens, reports 1,404 output tokens, and takes **19m 42.705s**,
|
|
3093
|
+
including 17m 37.551s before first output. The following coding request has
|
|
3094
|
+
28,126 input tokens and takes another 4m 22.552s before first output.
|
|
3095
|
+
Both prompts have zero cached tokens because the summary changes the exact
|
|
3096
|
+
serialized prefix. The first ordinary tool turn separately takes 8m 53.415s
|
|
3097
|
+
before first output after the initial 50,533-token response; its cached prefix
|
|
3098
|
+
contains only 2,549 tokens. These are measured targets for reducing repeated
|
|
3099
|
+
prefill, not claimed savings. The frozen outcome helper recorded zero
|
|
3100
|
+
compactions because it recognized only `auto_compaction_start`; derived
|
|
3101
|
+
reports count the observed `compaction_start` while preserving the raw result.
|
|
3102
|
+
|
|
3103
|
+
The server's last observed OS lifetime peak physical footprint is
|
|
3104
|
+
**18,913,094,336 bytes**. The external monitor began during the task and
|
|
3105
|
+
sampled through five seconds before exit; lifetime counters include earlier
|
|
3106
|
+
process history but may miss the final interval. Physical footprint and the
|
|
3107
|
+
runner's sampled combined RSS are different measurements. Separate process
|
|
3108
|
+
lifetime peaks are not added as though they were concurrent.
|
|
3109
|
+
|
|
3110
|
+
After inference exited, independent browser checks passed card creation,
|
|
3111
|
+
required-title editing, description/labels/assignee fields, combined filters,
|
|
3112
|
+
archive/restore, column creation/rename/safe deletion/restore, native card
|
|
3113
|
+
and column reordering, the Done indicator, and persisted theme/board/order.
|
|
3114
|
+
The app supplies run instructions and modular vanilla code. No generated
|
|
3115
|
+
source was edited. Earlier automated reorder probes remain recorded; native
|
|
3116
|
+
mouse motion with dragover before release confirms both reorder operations.
|
|
3117
|
+
|
|
3118
|
+
This establishes a completed task on the frozen candidate. There is no
|
|
3119
|
+
matched successful original baseline, so it establishes no task-time speedup
|
|
3120
|
+
percentage. The complete first response and every MTP acceptance decision
|
|
3121
|
+
match the preceding failed attempt; its time changes from 3,152.595 to
|
|
3122
|
+
3,147.633 seconds, effectively flat in one pair. The bounded range cache's
|
|
3123
|
+
measured benefit remains retained-memory correction and successful completion.
|
|
3124
|
+
|
|
3125
|
+
Raw evidence: `reports/qwen38-rd/kanban-final/luke-q3-128k-xhigh-arange-bounded/`
|
|
3126
|
+
contains `result.json`, `measurement-audit.json`, `quality.json`, referenced
|
|
3127
|
+
browser evidence, `memory-summary.json`, the untouched app and saved sources.
|
|
3128
|
+
The derived HTML report is `reports/qwen38-rd/kanban-final/comparison.html`.
|
|
3129
|
+
|
|
3130
|
+
Offline analysis of this successful trace reconciles all 62 terminal usage
|
|
3131
|
+
records to 130,494 output tokens, including the 1,404-token compaction. The
|
|
3132
|
+
server reports 3,980,688 cumulative prompt tokens and 3,701,542 cached tokens
|
|
3133
|
+
through the enabled paired target/draft RAM prefix cache; these are repeated
|
|
3134
|
+
request counts, not unique text or a measured time-saving percentage. An
|
|
3135
|
+
exact-substring analysis of 593,994 Unicode characters from 380 original
|
|
3136
|
+
input/output segments finds 2,830 maximal repeats of at least 32 characters
|
|
3137
|
+
(after excluding separator noise). The longest is 10,304 characters, a file
|
|
3138
|
+
write followed by a read. Replayed history and duplicated log events are
|
|
3139
|
+
excluded; nested/overlapping repeat families remain, so counts do not imply
|
|
3140
|
+
removable work. Local derived evidence and methodology:
|
|
3141
|
+
`~/.cache/mlx-bun/analysis/kanban-success/{analysis,duplicates}/report.md`,
|
|
3142
|
+
with the hashed source snapshot, per-request counts and repeat locations.
|
|
3143
|
+
Token-ID analysis of those same independently retokenized segments contains
|
|
3144
|
+
160,352 tokens and 2,756 maximal repeats of at least eight tokens after the
|
|
3145
|
+
same noise filter; the longest is 2,732 tokens, occurring twice. This is
|
|
3146
|
+
reconstructed-text tokenization, not the sampled-token stream. Methodology,
|
|
3147
|
+
source/tokenizer hashes, all matches and histogram are retained alongside
|
|
3148
|
+
that evidence under `kanban-success/token-duplicates/`.
|
|
3149
|
+
Counting only later generated positions matching earlier generated content,
|
|
3150
|
+
with first occurrences retained and overlapping intervals merged, gives
|
|
3151
|
+
48,932 duplicated retokenized positions at the eight-token cutoff, including
|
|
3152
|
+
26,965 tool-argument positions matching prior reasoning. At a 32-token cutoff
|
|
3153
|
+
the total is 26,602. These are approximate 37.50%/20.39% shares of the 130,494
|
|
3154
|
+
reported output tokens: the normalized generated corpus has 127,905 tokens
|
|
3155
|
+
and excludes wire framing/escaping. They are not measured time savings.
|
|
3156
|
+
Method and interval evidence: `generated-duplicate-report.md` and its JSON
|
|
3157
|
+
companions in the same token-analysis directory.
|
|
3158
|
+
|
|
3159
|
+
A narrative reconstruction with an embedded source browser is saved at
|
|
3160
|
+
`~/.cache/mlx-bun/analysis/kanban-success/timeline/kanban-story.html`.
|
|
3161
|
+
Its clock uses cumulative completion tokens and places external actions at
|
|
3162
|
+
completed assistant-response boundaries: the first tool action follows
|
|
3163
|
+
50,533 generated tokens. The account distinguishes code drafted in reasoning, file writes,
|
|
3164
|
+
repairs to the synthetic DOM test harness, and concrete application fixes.
|
|
3165
|
+
The trace identifies candidates for shortening the run; it does not establish
|
|
3166
|
+
which reasoning could be removed while preserving the successful outcome.
|
|
3167
|
+
|
|
3168
|
+
### Speculative decoding — "should spec be on?" (decision pending Phase 0/1 runs)
|
|
3169
|
+
|
|
3170
|
+
Decision rule: spec defaults ON for a (target, drafter) pair iff
|
|
3171
|
+
serve-path decode ≥ 1.3× serial at the recommended γ, clean-machine
|
|
3172
|
+
paired (`scripts/bench-serve.ts all` preflight, `bench-feature-matrix.ts --cells
|
|
3173
|
+
serial,spec`), with acceptance within 3 pts of the bf16-drafter baseline
|
|
3174
|
+
(`scripts/dspark.ts ab`). Prediction to test: ON for
|
|
3175
|
+
12B + quantized DeepSpec drafter, OFF for e4b + anything.
|
|
3176
|
+
|
|
3177
|
+
| target | drafter | γ | acceptance | τ | spec tok/s | serial tok/s | verdict |
|
|
3178
|
+
|---|---|---|---|---|---|---|---|
|
|
3179
|
+
| 12B-OptiQ-4bit | DeepSpec bf16 (6.9 GB) | 7 | 26–33% | ≈2.8 | 14.6 agg | 49.8 agg | **OFF** — drafter tax −3.4× (2026-07-07 first live run, loaded box, conc-4; directional) |
|
|
3180
|
+
| 12B-OptiQ-4bit | DeepSpec affine-q4-g64 (1.8 GB, built 2026-07-07) | best-of-0b | _1d run_ | _1d run_ | _0b/6 run_ | _0b/6 run_ | _pending_ |
|
|
3181
|
+
| e4b-OptiQ-4bit | (expected-negative control) | — | — | — | — | — | _pending_ |
|
|
3182
|
+
|
|
3183
|
+
Runbook (Josh's shell; directional passes fine loaded, the FINAL pair
|
|
3184
|
+
clean-machine per the house rule):
|
|
3185
|
+
1. **1d acceptance A/B** (no server): `bun scripts/dspark.ts ab
|
|
3186
|
+
--target gemma-4-12B-it-OptiQ-4bit --drafter-a <bf16-snap>
|
|
3187
|
+
--drafter-b <q4-snap> --json ab-q4.json` — gate: drop ≤ 3 pts AND
|
|
3188
|
+
wall-clock strictly improves.
|
|
3189
|
+
2. **0b γ sweep** (server): serve 12B `--draft-model <q4-snap>
|
|
3190
|
+
--num-draft-tokens {2,3,5,7}` × `bun scripts/bench-matrix.ts features
|
|
3191
|
+
--concurrency 1 --cells serial,spec` — pick best-γ by per-request tok/s.
|
|
3192
|
+
3. **Phase 6 decision pair** (clean machine: reboot + `sudo purge`):
|
|
3193
|
+
best-γ config, `--cells serial,spec` at conc 1 AND agg×4 — fill the
|
|
3194
|
+
table, flip the features-matrix default cell if ≥ 1.3×.
|
|
3195
|
+
|
|
3196
|
+
### TurboQuant KV — decided OFF (2026-07-06, re-affirmed post-leak-fix)
|
|
3197
|
+
|
|
3198
|
+
Opt-in memory/context lever, not a speed feature (v1 dequant-on-fetch is
|
|
3199
|
+
slower per step at long context; no speed claim made). The KL-vs-bpw
|
|
3200
|
+
curve above is the quality evidence. NOTE: any turbo perf/RSS impression
|
|
3201
|
+
formed before 2026-07-07 is invalid — the pre-fix build leaked
|
|
3202
|
+
window-scale buffers per decode step (PLAN Phase 13 post-merge fix).
|
|
3203
|
+
|
|
3204
|
+
|
|
3205
|
+
### Shared Gemma assistant drafting, M4 Pro 24 GB, 2026-09-10
|
|
3206
|
+
|
|
3207
|
+
Four `bench-serve.ts all` arms in control/candidate/candidate/control order,
|
|
3208
|
+
Bun 1.4.2, MLX 0.32.2. Gemma4 12B OptiQ4 target with its bf16 assistant,
|
|
3209
|
+
draft depth 2, bf16 target KV, 2 GiB RAM cache plus temporary SSD, 192 decode
|
|
3210
|
+
tokens, four concurrent requests and default capacity eight. Workload seed
|
|
3211
|
+
`assistant-spec-0`; diagnostic mode under Josh's CPU/swap policy. Source snapshots
|
|
3212
|
+
`c8213540beb87f438fbafad7115b49f494e92526c28acca930f134883d5cfdcf`
|
|
3213
|
+
→ `db38e64dbc3421ba5750485d8d6328afad63b64883bae8b945ff76e0ae6f1f21`.
|
|
3214
|
+
The candidate includes the shared assistant graph/provider, hidden companions,
|
|
3215
|
+
donor validity ports and the oracle-aligned strided weight views.
|
|
3216
|
+
|
|
3217
|
+
| Metric, mean of two arms | Previous implementation | Shared assistant | Change |
|
|
3218
|
+
|---|---:|---:|---:|
|
|
3219
|
+
| Median single-request decode, tok/s | 25.637 | 26.583 | +3.69% |
|
|
3220
|
+
| Four-request aggregate, tok/s | 24.815 | 34.129 | +37.53% |
|
|
3221
|
+
| Four-request wall time, ms | 20,632.8 | 15,002.1 | −27.29% |
|
|
3222
|
+
| Cached prefill, ms | 2,573.4 | 116.7 | −95.47% |
|
|
3223
|
+
| Cold prefill, ms | 2,581.1 | 2,527.6 | −2.08% |
|
|
3224
|
+
| Server readiness, ms | 723.5 | 1,016.1 | +40.45% |
|
|
3225
|
+
| Cold start, ms | 2,244.1 | 2,094.7 | −6.66% |
|
|
3226
|
+
| Peak RSS, MiB | 9,744.6 | 10,042.8 | +3.06% |
|
|
3227
|
+
|
|
3228
|
+
All 60 requests complete without failures with matching request bodies and token
|
|
3229
|
+
budgets. Single-request text and raw completion/chat probes match. Three of four
|
|
3230
|
+
concurrent responses differ across implementations; each implementation repeats
|
|
3231
|
+
exactly, including usage. Shared cached requests reuse 668 tokens, versus zero.
|
|
3232
|
+
Mean cold-start improvement is within substantial variation: candidate arms are
|
|
3233
|
+
1.712 and 2.478 seconds. Readiness regresses by 293 ms; strict startup dominance
|
|
3234
|
+
remains open. These numbers compare implementations with the same assistant,
|
|
3235
|
+
not assistant speculation versus ordinary decoding. Defaults are unchanged.
|
|
3236
|
+
|
|
3237
|
+
Both-machine e4b/12B graph and serving/cache tests pass; e4b matches unmodified
|
|
3238
|
+
optiq `spec_generate` end to end. The pinned 12B loader lacks tensor-presence head
|
|
3239
|
+
detection, so its numerical test explicitly binds the artifact's tied embedding
|
|
3240
|
+
head while retaining upstream layers. Both-machine Qwen MTP/TQ regressions, full
|
|
3241
|
+
suites and all typechecks pass. Evidence:
|
|
3242
|
+
`reports/qwen38-closeout/composition-baseline/assistant-batch/`.
|
|
3243
|
+
|
|
3244
|
+
|
|
3245
|
+
### Shared DeepSpec drafting, M4 Pro 24 GB, 2026-09-10
|
|
3246
|
+
|
|
3247
|
+
Four `bench-serve.ts all` arms in control/candidate/candidate/control order,
|
|
3248
|
+
Bun 1.4.2, MLX 0.32.2. Gemma4 12B OptiQ4 target with the DeepSpec affine-q4-g64
|
|
3249
|
+
drafter, trained depth seven, bf16 target KV, 2 GiB RAM cache plus temporary SSD,
|
|
3250
|
+
192 decode tokens, four concurrent requests and default capacity eight. Seed
|
|
3251
|
+
`deepspec-spec-0`; diagnostic mode under Josh's CPU/swap policy. Frozen sources
|
|
3252
|
+
`db38e64dbc3421ba5750485d8d6328afad63b64883bae8b945ff76e0ae6f1f21`
|
|
3253
|
+
→ `39b289a30244e8f37bc8457c7e8f4e36deae428340157cd90c3a4c2287610dda`.
|
|
3254
|
+
The candidate adds shared context projections, batched proposals and persisted
|
|
3255
|
+
method companions. Both arms use the same target, drafter and settings.
|
|
3256
|
+
|
|
3257
|
+
| Metric, mean of two arms | Previous implementation | Shared DeepSpec | Change |
|
|
3258
|
+
|---|---:|---:|---:|
|
|
3259
|
+
| Median single-request decode, tok/s | 25.288 | 25.950 | +2.62% |
|
|
3260
|
+
| Four-request aggregate, tok/s | 25.191 | 53.187 | +111.14% |
|
|
3261
|
+
| Four-request wall time, ms | 20,326.0 | 9,626.5 | −52.64% |
|
|
3262
|
+
| Cached prefill, ms | 2,724.6 | 345.1 | −87.33% |
|
|
3263
|
+
| Cold prefill, ms | 2,715.1 | 2,737.0 | +0.81% |
|
|
3264
|
+
| Server readiness, ms | 612.5 | 1,319.1 | +115.37% |
|
|
3265
|
+
| Cold start, ms | 2,509.8 | 2,918.0 | +16.26% |
|
|
3266
|
+
| Peak RSS, MiB | 10,772.8 | 11,057.6 | +2.64% |
|
|
3267
|
+
|
|
3268
|
+
All 60 requests complete without failures and use matching request bodies and
|
|
3269
|
+
budgets. Single-request text and raw completion/chat probes match. One of four
|
|
3270
|
+
concurrent responses differs; both implementations repeat exactly, including
|
|
3271
|
+
usage. Cached requests reuse 671 tokens versus zero. Decode samples within each
|
|
3272
|
+
arm span roughly 15–16%, although the repeated medians agree. The small B1 gain
|
|
3273
|
+
should be read with that variation. Readiness regresses by 707 ms and cold start
|
|
3274
|
+
by 408 ms on average; strict startup dominance remains open. Defaults are unchanged.
|
|
3275
|
+
|
|
3276
|
+
Both-machine bf16/4-bit graph controls, depth-seven serving/generated RAM/SSD,
|
|
3277
|
+
regression suites and all typechecks pass. The graph comparisons preserve the
|
|
3278
|
+
frozen implementation; they are not a new external DeepSpec oracle. Real-window
|
|
3279
|
+
checks confirm active shared speculation across wrap. Evidence:
|
|
3280
|
+
`reports/qwen38-closeout/composition-baseline/deepspec-batch/`.
|
|
3281
|
+
|
|
3282
|
+
|
|
3283
|
+
### Shared projected-context extraction, M4 Pro 24 GB, 2026-09-10
|
|
3284
|
+
|
|
3285
|
+
Four `bench-serve.ts all` arms, control/candidate/candidate/control, use the same
|
|
3286
|
+
Gemma4 12B OptiQ4 target, trained DeepSpec q4-g64 drafter, depth seven, bf16 target
|
|
3287
|
+
KV, 2 GiB RAM plus temporary SSD, 192 decode tokens, four concurrent requests,
|
|
3288
|
+
default capacity eight and seed `deepspec-spec-0`. Bun 1.4.2, MLX 0.32.2,
|
|
3289
|
+
diagnostic mode under Josh's CPU/swap policy. Frozen sources
|
|
3290
|
+
`39b289a30244e8f37bc8457c7e8f4e36deae428340157cd90c3a4c2287610dda`
|
|
3291
|
+
→ `9f8484fa9dca140b31ad685a2701563ed5a1e0a2638d27f48e31d1df4160f4ab`.
|
|
3292
|
+
The candidate extracts context ownership for reuse by DSpark/DFlash and DeepSpec.
|
|
3293
|
+
This measures the extraction with a trained DeepSpec drafter; no trained DSpark
|
|
3294
|
+
checkpoint was available for its own performance comparison.
|
|
3295
|
+
|
|
3296
|
+
| Metric, mean of two arms | DeepSpec-specific owner | Shared context owner | Change |
|
|
3297
|
+
|---|---:|---:|---:|
|
|
3298
|
+
| Median single-request decode, tok/s | 25.800 | 25.695 | −0.41% |
|
|
3299
|
+
| Four-request aggregate, tok/s | 53.597 | 52.229 | −2.55% |
|
|
3300
|
+
| Four-request wall time, ms | 9,552.8 | 9,805.0 | +2.64% |
|
|
3301
|
+
| Cached prefill, ms | 342.2 | 348.3 | +1.79% |
|
|
3302
|
+
| Cold prefill, ms | 2,722.4 | 2,778.2 | +2.05% |
|
|
3303
|
+
| Server readiness, ms | 1,318.4 | 1,421.7 | +7.84% |
|
|
3304
|
+
| Cold start, ms | 2,943.2 | 3,321.3 | +12.85% |
|
|
3305
|
+
| Peak RSS, MiB | 11,070.5 | 11,068.2 | −0.02% |
|
|
3306
|
+
|
|
3307
|
+
All 60 requests complete without failures; every request body, response and usage
|
|
3308
|
+
record matches across all four arms. Cached requests reuse 671 tokens in both.
|
|
3309
|
+
The first control cold start is 2.615 seconds; the other three arms range from
|
|
3310
|
+
3.272 to 3.337 seconds. Candidate aggregate arms are 52.99 and 51.47 tok/s versus
|
|
3311
|
+
53.75 and 53.44 controls. The measured cost is retained; this is not a speed win
|
|
3312
|
+
or strict dominance. Defaults are unchanged. Both-machine pinned Markov/RNN and
|
|
3313
|
+
independent confidence/sampling tests, seeded real-Gemma serving/generated RAM/SSD,
|
|
3314
|
+
trained DeepSpec regressions, full suites and typechecks pass. Evidence:
|
|
3315
|
+
`reports/qwen38-closeout/composition-baseline/dflash-batch/`.
|
|
3316
|
+
|
|
3317
|
+
|
|
3318
|
+
### Reused artifact identity, M4 Pro 24 GB, 2026-09-10
|
|
3319
|
+
|
|
3320
|
+
Four `bench-serve.ts all` arms, control/candidate/candidate/control, use Gemma4 12B
|
|
3321
|
+
OptiQ4, trained DeepSpec q4-g64, depth seven, bf16 target KV, 2 GiB RAM plus temporary
|
|
3322
|
+
SSD, 192 decode tokens, four concurrent requests, default capacity eight and seed
|
|
3323
|
+
`deepspec-spec-0`. Bun 1.4.2, MLX 0.32.2, diagnostic mode under Josh's CPU/swap
|
|
3324
|
+
policy. Frozen sources `9f8484fa9dca140b31ad685a2701563ed5a1e0a2638d27f48e31d1df4160f4ab`
|
|
3325
|
+
→ `e17613b8496e5820bb8f4a193e735a4d9129b5333c851886bb22cbd0c9c41bed`.
|
|
3326
|
+
The candidate resolves the same full configuration/name/byte SHA-256 through a
|
|
3327
|
+
shared artifact-identity store. Its unchanged-file memo was populated during
|
|
3328
|
+
native validation. These fresh server starts hit the identity memo; first-ever
|
|
3329
|
+
identity calculation still reads all shard bytes. Memo writes are queued.
|
|
3330
|
+
|
|
3331
|
+
| Metric, mean of two arms | Rehash each load | Reuse unchanged identity | Change |
|
|
3332
|
+
|---|---:|---:|---:|
|
|
3333
|
+
| Median single-request decode, tok/s | 25.881 | 25.975 | +0.37% |
|
|
3334
|
+
| Four-request aggregate, tok/s | 52.449 | 52.831 | +0.73% |
|
|
3335
|
+
| Four-request wall time, ms | 9,761.8 | 9,691.3 | −0.72% |
|
|
3336
|
+
| Cached prefill, ms | 350.0 | 346.1 | −1.12% |
|
|
3337
|
+
| Cold prefill, ms | 2,783.3 | 2,763.5 | −0.71% |
|
|
3338
|
+
| Server readiness, ms | 1,422.2 | 713.1 | −49.86% |
|
|
3339
|
+
| Cold start, ms | 3,332.1 | 2,709.7 | −18.68% |
|
|
3340
|
+
| Peak RSS, MiB | 11,072.1 | 10,784.0 | −2.60% |
|
|
3341
|
+
|
|
3342
|
+
All 60 requests complete without failures; every request body, response and usage
|
|
3343
|
+
record matches across all four arms. Cached requests reuse 671 tokens in both.
|
|
3344
|
+
Candidate readiness is 610/816 ms versus 1,422/1,422 ms; cold start is 2,590/2,829 ms
|
|
3345
|
+
versus 3,345/3,319 ms. Peak RSS decreases by 288.1 MiB on average. Throughput changes
|
|
3346
|
+
are small; the material gain is repeat loading. Sampling, draft-depth and KV
|
|
3347
|
+
defaults are unchanged. Both-machine Qwen MTP/TurboQuant and DeepSpec serving and
|
|
3348
|
+
generated RAM/SSD, complete suites and typechecks pass. Identity tests cover the
|
|
3349
|
+
previous digest, zero weight reads on memo hits, file/config/symlink mutation and
|
|
3350
|
+
failed persistence. Existing KV namespaces remain compatible. Evidence:
|
|
3351
|
+
`reports/qwen38-closeout/composition-baseline/artifact-identity/`.
|
|
3352
|
+
|
|
3353
|
+
|
|
3354
|
+
### Affine rotating speculation, M4 Pro 24 GB, 2026-09-11
|
|
3355
|
+
|
|
3356
|
+
Six `bench-serve.ts all` arms run control/candidate/KV4/KV4/candidate/control.
|
|
3357
|
+
All use Gemma4 12B OptiQ4 weights, trained DeepSpec q4-g64 at depth seven,
|
|
3358
|
+
2 GiB RAM plus temporary SSD, 192 decode tokens, four concurrent requests,
|
|
3359
|
+
default capacity eight and seed `deepspec-spec-0`. Bun 1.4.2 and MLX 0.32.2;
|
|
3360
|
+
diagnostic mode follows Josh's background-CPU/swap policy. Control and candidate
|
|
3361
|
+
use bf16 target KV; KV4 changes only that setting on the candidate source.
|
|
3362
|
+
Frozen source hashes are
|
|
3363
|
+
`e17613b8496e5820bb8f4a193e735a4d9129b5333c851886bb22cbd0c9c41bed`
|
|
3364
|
+
and `9f8819cce7c759eab2e86f5ba35e20d99e436491fd46c39966c59048ab44e60d`.
|
|
3365
|
+
Every arm retains its source hash through completion.
|
|
3366
|
+
|
|
3367
|
+
| Metric, mean of two arms | Control bf16 | Candidate bf16 | Candidate KV4 |
|
|
3368
|
+
|---|---:|---:|---:|
|
|
3369
|
+
| Median single-request decode, tok/s | 25.778 | 25.895 | 25.880 |
|
|
3370
|
+
| Four-request aggregate, tok/s | 52.947 | 52.995 | 55.398 |
|
|
3371
|
+
| Four-request wall time, ms | 9,671.7 | 9,661.4 | 9,242.3 |
|
|
3372
|
+
| Cached prefill, ms | 345.7 | 346.5 | 352.9 |
|
|
3373
|
+
| Cold prefill, ms | 2,749.7 | 2,748.8 | 2,814.0 |
|
|
3374
|
+
| Server readiness, ms | 611.5 | 611.7 | 612.1 |
|
|
3375
|
+
| Cold start, ms | 2,600.5 | 2,427.5 | 2,424.3 |
|
|
3376
|
+
| Peak RSS, MiB | 10,775.3 | 10,767.2 | 10,802.8 |
|
|
3377
|
+
|
|
3378
|
+
The source-only comparison is effectively flat: decode +0.45%, aggregate +0.09%,
|
|
3379
|
+
cached prefill +0.22%, cold prefill −0.03%. All 60 bf16 requests have identical
|
|
3380
|
+
request bodies, responses and usage records. Each setting repeats exactly.
|
|
3381
|
+
All 90 requests complete without benchmark failures and reuse 671 cached tokens.
|
|
3382
|
+
|
|
3383
|
+
KV4 reaches +4.63% aggregate throughput versus the bf16 control, with +2.07%
|
|
3384
|
+
cached and +2.34% cold prefill time. Ten of fifteen responses per KV4 arm differ
|
|
3385
|
+
from bf16, and accepted draft tokens total 1,042 versus 1,032. This is a measured
|
|
3386
|
+
precision/configuration tradeoff, not an isolated engine speed gain. Short-run
|
|
3387
|
+
RSS does not establish a memory saving; startup varies within the candidate
|
|
3388
|
+
arms. Defaults remain unchanged. Context/pressure and strict serial-dominance
|
|
3389
|
+
acceptance are not covered by this short comparison. Native tests separately
|
|
3390
|
+
cover generated RAM/SSD restoration, real-window rollback and KV4/KV8 provider
|
|
3391
|
+
composition on both Macs. Evidence:
|
|
3392
|
+
`reports/qwen38-closeout/composition-baseline/rotating-spec-quant/`.
|
|
3393
|
+
|
|
3394
|
+
|
|
3395
|
+
### TurboQuant provider composition and centroid correction, M4 Pro 24 GB, 2026-09-11
|
|
3396
|
+
|
|
3397
|
+
Two six-arm `bench-serve.ts all` comparisons use
|
|
3398
|
+
control/candidate/TQ/TQ/candidate/control. Both use Bun 1.4.2, MLX 0.32.2,
|
|
3399
|
+
192 decode tokens, four concurrent requests, capacity eight, 2 GiB RAM plus
|
|
3400
|
+
temporary SSD and fused TQ decoding enabled. Control/candidate target KV is
|
|
3401
|
+
bf16; the TQ arms select K8/V3 on the candidate. The CLI keeps start zero;
|
|
3402
|
+
sliding layers remain bf16. Diagnostic mode follows Josh's CPU/swap policy.
|
|
3403
|
+
Sources stay fixed through every arm:
|
|
3404
|
+
`9f8819cce7c759eab2e86f5ba35e20d99e436491fd46c39966c59048ab44e60d`
|
|
3405
|
+
→ `f4c9fe17c9f0a691907ded7777e7814cc5eaed7811ac9941b4d1528ad75070bd`.
|
|
3406
|
+
|
|
3407
|
+
The candidate adds owned TQ donor attention and capability-based grouped draft
|
|
3408
|
+
selection, captures immutable numerical options and distinct per-layer cache
|
|
3409
|
+
identities, and corrects the small assistant's centroid head to the pinned
|
|
3410
|
+
bf16 multiply/sum arithmetic and lowest-token-ID tie rule. The independent M1
|
|
3411
|
+
oracle exposed the previous matmul shortcut; its decoded KV and hidden state
|
|
3412
|
+
were exact but its selected token differed. This correction applies at every B.
|
|
3413
|
+
|
|
3414
|
+
#### Gemma4 12B + trained DeepSpec
|
|
3415
|
+
|
|
3416
|
+
OptiQ4 target weights, q4-g64 DeepSpec block7, draft depth seven and seed `deepspec-spec-0`.
|
|
3417
|
+
|
|
3418
|
+
| Metric, mean of two arms | Control bf16 | Candidate bf16 | Candidate K8/V3 |
|
|
3419
|
+
|---|---:|---:|---:|
|
|
3420
|
+
| Median single-request decode, tok/s | 25.912 | 25.428 | 26.749 |
|
|
3421
|
+
| Four-request aggregate, tok/s | 53.635 | 51.962 | 54.258 |
|
|
3422
|
+
| Four-request wall time, ms | 9,546.956 | 9,854.496 | 9,436.373 |
|
|
3423
|
+
| Cached prefill, ms | 341.823 | 343.041 | 352.446 |
|
|
3424
|
+
| Cold prefill, ms | 2,688.505 | 2,758.072 | 2,772.306 |
|
|
3425
|
+
| Server readiness, ms | 616.147 | 616.509 | 610.971 |
|
|
3426
|
+
| Cold start, ms | 2,604.734 | 2,604.987 | 2,612.562 |
|
|
3427
|
+
| Peak RSS, MiB | 10,784.125 | 10,762.719 | 10,780.617 |
|
|
3428
|
+
|
|
3429
|
+
Source-only bf16 decode decreases 1.87% and aggregate throughput decreases
|
|
3430
|
+
3.12%; cached prefill is +0.36%, cold prefill +2.59%. All 60 bf16 requests have
|
|
3431
|
+
identical bodies, responses and usage. The cost remains recorded and is under
|
|
3432
|
+
separate attribution testing. It is not a refactor speed win.
|
|
3433
|
+
|
|
3434
|
+
K8/V3 increases decode 3.23% and aggregate throughput 1.16% versus the old bf16
|
|
3435
|
+
control, with cached and cold prefill each about 3.1% slower. Nine of fifteen
|
|
3436
|
+
responses per TQ arm differ from bf16. Accepted draft tokens total 1,044 versus
|
|
3437
|
+
1,032. Each TQ repeat matches its own responses and usage exactly.
|
|
3438
|
+
|
|
3439
|
+
#### Gemma4 e4b + assistant
|
|
3440
|
+
|
|
3441
|
+
OptiQ4 target weights, bf16 assistant, draft depth three and seed `assistant-spec-0`.
|
|
3442
|
+
|
|
3443
|
+
| Metric, mean of two arms | Control bf16 | Candidate bf16 | Candidate K8/V3 |
|
|
3444
|
+
|---|---:|---:|---:|
|
|
3445
|
+
| Median single-request decode, tok/s | 55.374 | 55.106 | 57.532 |
|
|
3446
|
+
| Four-request aggregate, tok/s | 94.152 | 93.340 | 91.267 |
|
|
3447
|
+
| Four-request wall time, ms | 5,438.005 | 5,485.344 | 5,609.896 |
|
|
3448
|
+
| Cached prefill, ms | 88.692 | 89.947 | 92.351 |
|
|
3449
|
+
| Cold prefill, ms | 962.402 | 960.880 | 967.007 |
|
|
3450
|
+
| Server readiness, ms | 621.475 | 610.243 | 611.252 |
|
|
3451
|
+
| Cold start, ms | 1,309.033 | 894.498 | 906.810 |
|
|
3452
|
+
| Peak RSS, MiB | 6,880.625 | 6,889.672 | 6,929.180 |
|
|
3453
|
+
|
|
3454
|
+
The centroid correction and interface changes decrease bf16 decode 0.49%
|
|
3455
|
+
and aggregate throughput 0.86%. All bf16 response text is unchanged, while
|
|
3456
|
+
draft-acceptance usage changes: 530 accepted tokens per candidate arm versus
|
|
3457
|
+
532 in each control. Each arm repeats its own response and usage exactly.
|
|
3458
|
+
The first control cold start is 1,726 ms; all later arms are 888–914 ms, so
|
|
3459
|
+
the mean startup difference is not attributed to this change.
|
|
3460
|
+
|
|
3461
|
+
K8/V3 increases decode 3.90% versus the old bf16 control but decreases aggregate
|
|
3462
|
+
throughput 3.06%; cached prefill is +4.13%, cold prefill +0.48%. Nine of fifteen
|
|
3463
|
+
responses per TQ arm differ from bf16, and draft acceptance totals 557.
|
|
3464
|
+
The TQ arms repeat exactly. This setting benefits single-request decode on
|
|
3465
|
+
this workload and loses concurrent throughput.
|
|
3466
|
+
|
|
3467
|
+
All 180 requests complete without benchmark failures. Cached requests retain
|
|
3468
|
+
671 tokens for 12B and 668 for e4b. These are short configuration tradeoffs, not
|
|
3469
|
+
long-context memory or pressure acceptance. Defaults remain unchanged and strict
|
|
3470
|
+
serial dominance stays open. Both-machine native coverage includes assistant,
|
|
3471
|
+
DeepSpec, standalone and lookup serving/generated RAM/SSD, delayed conversion,
|
|
3472
|
+
independent assistant codec/graph controls, seeded DSpark heads and Qwen MTP
|
|
3473
|
+
regressions; the final suites and typechecks pass. Evidence and source manifests:
|
|
3474
|
+
`reports/qwen38-closeout/composition-baseline/turboquant-donor/`.
|
|
3475
|
+
|
|
3476
|
+
### TurboQuant option-capture attribution (M4 Pro, 2026-09-11)
|
|
3477
|
+
|
|
3478
|
+
Same Gemma4-12B/DeepSpec7 workload and settings as the TurboQuant composition comparison above, all using bf16 KV. The sequence isolates request-option capture from numerical kernels. Frozen integrated source `f4c9fe17…` is unchanged; the key-restored variant is `cb063841…`, and the shallow-clone/conditional-assignment variant is `09e02ca6…`.
|
|
3479
|
+
|
|
3480
|
+
| Arm, in execution order | Decode median tok/s | Aggregate tok/s | Cached TTFT ms | Cold TTFT ms |
|
|
3481
|
+
|---|---:|---:|---:|---:|
|
|
3482
|
+
| deep-key-ablation-1 | 25.898 | 53.222 | 343.92 | 2728.18 |
|
|
3483
|
+
| deep-candidate-attribution-1 | 25.899 | 52.984 | 346.27 | 2748.01 |
|
|
3484
|
+
| deep-options-capture-1 | 25.910 | 53.942 | 339.04 | 2640.71 |
|
|
3485
|
+
| deep-candidate-attribution-2 | 25.897 | 53.063 | 346.38 | 2752.70 |
|
|
3486
|
+
| deep-options-capture-2 | 25.895 | 52.690 | 350.81 | 2769.67 |
|
|
3487
|
+
|
|
3488
|
+
The unchanged integrated build recovered the original decode rate on both repeats. Neither key restoration nor the option-copy variant establishes a repeatable speed benefit; retain the integrated implementation. The earlier measured source-only costs remain recorded, but attributing them to a code regression is not supported by these repeats. All five arms retain five distinct decode samples (reported within-arm spread about 1.15–1.16); these medians are comparisons of that fixed workload, not five identical requests. Raw requests, source identities and comparison: `reports/qwen38-closeout/composition-baseline/turboquant-donor/{m4,performance-attribution.json}`.
|
|
3489
|
+
|
|
3490
|
+
### Delayed/per-layer affine rotating speculation (M4 Pro, 2026-09-11)
|
|
3491
|
+
|
|
3492
|
+
Gemma4-12B OptiQ-4bit with the q4 DeepSpec block-7 drafter, depth seven, Bun 1.4.2/MLX 0.32.2, 192 decode tokens, four concurrent requests, scheduler capacity eight, 2 GiB RAM prompt cache plus temporary SSD. Same `deepspec-spec-0` workload as the previous composition comparison. Order: control bf16, candidate bf16, candidate per-layer, candidate per-layer, candidate bf16, control bf16. The control source is `f4c9fe17…`; candidate `072bf3ca…`. All six source snapshots remain fixed through completion.
|
|
3493
|
+
|
|
3494
|
+
| Setting (mean of two arms) | Decode tok/s | Aggregate tok/s | Aggregate wall ms | Cached TTFT ms | Cold TTFT ms | Ready ms | Startup ms | Peak RSS MiB |
|
|
3495
|
+
|---|---:|---:|---:|---:|---:|---:|---:|---:|
|
|
3496
|
+
| control | 25.898 | 53.455 | 9579.865 | 344.315 | 2696.925 | 616.786 | 2603.127 | 10795.445 |
|
|
3497
|
+
| candidate | 25.713 | 53.643 | 9545.352 | 339.185 | 2680.571 | 614.743 | 2544.107 | 10775.914 |
|
|
3498
|
+
| per-layer | 27.430 | 52.456 | 9760.580 | 353.531 | 2655.698 | 616.945 | 2544.832 | 10816.516 |
|
|
3499
|
+
|
|
3500
|
+
Source-only bf16 comparison: decode −0.716%, aggregate +0.353%, cached TTFT −1.490%, cold TTFT −0.606%. Every bf16 request, response and usage record matches. The first candidate decode median is lower than its second repeat; the small source-only cost remains recorded and does not satisfy strict B1 dominance.
|
|
3501
|
+
|
|
3502
|
+
Model-defined mixed per-layer affine KV versus control bf16: decode +5.916%, aggregate −1.868%, cached TTFT +2.677%, cold TTFT −1.529%. Ten of fifteen responses differ from bf16; each configuration repeats exactly, including usage. All ninety requests complete with no phase failures. Precision changes affect the numerical trajectory and draft acceptance, so this setting comparison is not an engine-only same-output speedup. Defaults remain unchanged.
|
|
3503
|
+
|
|
3504
|
+
Both-machine native serving/generated RAM/SSD, delayed transition and real-window hidden/logit controls pass for the qualified providers. Seeded DSpark fixtures establish Markov/RNN execution and state contracts, not trained quality or acceptance. Raw arms and exact pair comparisons: `reports/qwen38-closeout/composition-baseline/delayed-rotating-spec/{m4,benchmark-comparison.json}`.
|
|
3505
|
+
|
|
3506
|
+
|
|
3507
|
+
### Paged storage in the shared executor (M4 Pro, 2026-09-11)
|
|
3508
|
+
|
|
3509
|
+
Gemma4-12B OptiQ-4bit, bf16 KV, Bun 1.4.2/MLX 0.32.2, 192 decode tokens, four concurrent requests, 2 GiB RAM cache plus temporary SSD, workload `paged-compose-0`. Paged storage uses 256-token blocks and bypasses both cache tiers. The ordinary source comparison keeps continuous scheduling on both sides. The paged comparison uses the old serial executor versus the candidate shared executor (capacity eight). Frozen source: control `db451918…`, candidate `a9fe941c…`; both include identical benchmark argument plumbing. Each configuration runs twice, with reversed control/candidate order. All source snapshots remain fixed.
|
|
3510
|
+
|
|
3511
|
+
| Configuration (mean of two arms) | Decode tok/s | Aggregate tok/s | Aggregate wall ms | Repeated-prompt TTFT ms | Cold TTFT ms | Ready ms | Startup ms | Peak RSS MiB |
|
|
3512
|
+
|---|---:|---:|---:|---:|---:|---:|---:|---:|
|
|
3513
|
+
| Ordinary control | 26.455 | 72.894 | 7023.933 | 153.036 | 2436.522 | 616.814 | 1452.364 | 8936.141 |
|
|
3514
|
+
| Ordinary candidate | 26.480 | 72.913 | 7022.101 | 154.218 | 2437.542 | 613.202 | 1588.357 | 8946.594 |
|
|
3515
|
+
| Paged serial control | 26.310 | 24.832 | 20618.569 | 2462.690 | 2443.653 | 613.156 | 1425.283 | 8915.117 |
|
|
3516
|
+
| Paged shared candidate | 26.289 | 70.240 | 7289.413 | 2490.439 | 2479.725 | 611.401 | 1218.411 | 8940.664 |
|
|
3517
|
+
|
|
3518
|
+
Ordinary source cost is effectively flat: decode +0.094%, aggregate +0.026%, cold TTFT +0.042% and cached TTFT +0.772%. Every paired response and usage record is identical. Startup varies more (+9.36% in the two-arm mean); this short comparison does not establish startup dominance.
|
|
3519
|
+
|
|
3520
|
+
Shared paged execution increases four-request throughput **182.86% (2.83×)** and reduces task wall time **64.65%**. Single-request decode changes −0.081%; cold TTFT increases 1.48% and repeated-prompt TTFT 1.13%. The first concurrent request reaches output in 365.84 versus 365.86 ms. Peak RSS increases 25.55 MiB. Two concurrent responses differ from serial in each pair; all single-request responses and token counts match. Every configuration repeats its own text and usage exactly. The repeated paged prompt restores zero tokens, as expected; ordinary restores 669. This is concurrent execution scaling, not a single-request decode-kernel speedup.
|
|
3521
|
+
|
|
3522
|
+
Eight successful arms complete 120 requests without phase failures. Four earlier paged setup attempts failed before readiness because the harness enables SSD while `--prompt-cache 0` disables its required RAM tier; those reports remain in the evidence, and both paged sides were rerun with the same 2 GiB setting. The machine retained about 1.65 GiB swap with 91% free memory and no competing GPU job; diagnostic mode follows Josh's campaign policy.
|
|
3523
|
+
|
|
3524
|
+
The long native comparison initially allowed ordinary cache snapshots to change prefill cohort/query boundaries while paging bypassed them. Holding arrivals alone did not equalize that graph. The corrected storage comparison holds arrivals and disables snapshot splitting on both sides; it checks full logits and tokens beyond the default block boundary. Separate HTTP coverage checks sampling, logprobs and grammar. Raw arms, source manifest, setup failures and exact request comparisons: `reports/qwen38-closeout/composition-baseline/paged-rows/`. Direct paged attention, block sharing and composed quantized/speculative paging remain open; defaults are unchanged.
|
|
3525
|
+
|
|
3526
|
+
|
|
3527
|
+
### Adapter-qualified prompt lookup (M4 Pro, 2026-09-11)
|
|
3528
|
+
|
|
3529
|
+
Gemma4 e4b OptiQ-4bit with the existing `upper` LoRA adapter (weights SHA-256 `94f83569ba85df9e05557238809101cd19f9eabd0149c7931904e2a58774a05b`), bf16 KV, Bun 1.4.2/MLX 0.32.2, scheduler capacity eight, 192 decode tokens, four concurrent requests, 2 GiB RAM cache plus temporary SSD. Same `adapter-lookup-0` request bodies in every arm. Frozen control `a9fe941c…` and candidate `cce6e1e6…`; two repetitions per configuration in reversed control/candidate order.
|
|
3530
|
+
|
|
3531
|
+
The ordinary arms omit draft flags and isolate source cost. The lookup arms request ngram depth three: the old control disables speculation for adapters, while the candidate honors it through the grouped provider capability. This second comparison therefore measures newly enabled behavior.
|
|
3532
|
+
|
|
3533
|
+
| Configuration (mean of two arms) | Decode tok/s | Aggregate tok/s | Aggregate wall ms | Cached TTFT ms | Cold TTFT ms | Ready ms | Startup ms | Peak RSS MiB |
|
|
3534
|
+
|---|---:|---:|---:|---:|---:|---:|---:|---:|
|
|
3535
|
+
| ordinary-control | 53.888 | 159.078 | 3218.551 | 38.040 | 526.635 | 610.894 | 893.690 | 6751.648 |
|
|
3536
|
+
| ordinary-candidate | 53.800 | 158.943 | 3221.290 | 38.246 | 523.882 | 610.938 | 893.021 | 6763.688 |
|
|
3537
|
+
| lookup-control | 53.746 | 159.064 | 3218.837 | 38.244 | 524.087 | 611.516 | 951.899 | 6731.523 |
|
|
3538
|
+
| lookup-candidate | 53.136 | 78.537 | 6519.231 | 30.925 | 518.250 | 611.589 | 945.210 | 6766.641 |
|
|
3539
|
+
|
|
3540
|
+
Ordinary source cost is effectively flat: decode −0.163%, aggregate −0.085%, cold TTFT −0.523% and cached TTFT +0.543%. Every ordinary response and usage record matches across source versions.
|
|
3541
|
+
|
|
3542
|
+
Enabling lookup decreases single-request decode 1.14% and four-request throughput **50.63%**, increasing aggregate wall time **102.53%**. It lowers cached TTFT 19.14%. Each concurrent block accepts only 26 of 444 proposed tokens (5.86%); repeated rejection makes this configuration a poor throughput choice. Concurrent cached prefixes also change from 11 tokens under ordinary execution to zero under the paired lookup namespace. That small prefill difference does not establish the cause of the decode cost.
|
|
3543
|
+
|
|
3544
|
+
Eight of fifteen responses change with the enabled method, including five single-request decode probes and three concurrent responses; token counts and finish reasons match. Each configuration repeats its own responses and usage exactly. All 120 requests complete without phase failures. This is not a same-output speed gain and does not justify a default change. A stricter ngram-match screen follows separately.
|
|
3545
|
+
|
|
3546
|
+
Native composition checks cover bf16/KV4 and TurboQuant, compatible adapter cohorts, seeded logprobs, namespace replacement, callback failure and generated RAM/SSD restart identity on both Macs. The HTTP fixture explicitly checks token alignment with the generated SSD header: appending an extra newline changes the M4 KV4 boundary, so the original fixture correctly reused an earlier prompt checkpoint. Preserving the generated newline restores the complete generated boundary; no cache assertion was relaxed. Raw arms, source manifest and request comparison: `reports/qwen38-closeout/composition-baseline/adapter-lookup/`.
|
|
3547
|
+
|
|
3548
|
+
|
|
3549
|
+
### Ngram match-length screen with the upper adapter (M4 Pro, 2026-09-11)
|
|
3550
|
+
|
|
3551
|
+
Same e4b/upper-adapter artifact, bf16 KV, depth three, cache settings and `adapter-lookup-0` workload as above. Source `ef832276…` differs only by adding benchmark forwarding for the existing `--ngram-min`/`--ngram-max` flags. Order is 1–3, 2–3, 3–3, 5–5, then the reverse. Each arm retains five decode samples; table values are means of the two arm medians for decode and means for other timings.
|
|
3552
|
+
|
|
3553
|
+
| Minimum–maximum match | Decode tok/s | Aggregate tok/s | Aggregate wall ms | Cached TTFT ms | Cold TTFT ms | Aggregate accepted/proposed, arm A |
|
|
3554
|
+
|---|---:|---:|---:|---:|---:|---:|
|
|
3555
|
+
| min1-max3 | 53.949 | 78.566 | 6516.923 | 30.535 | 529.999 | 39/455 |
|
|
3556
|
+
| min2-max3 | 56.532 | 115.274 | 4442.253 | 47.959 | 537.508 | 26/90 |
|
|
3557
|
+
| min3-max3 | 53.552 | 130.850 | 3913.573 | 47.439 | 533.417 | 17/30 |
|
|
3558
|
+
| min5-max5 | 50.495 | 134.898 | 3796.100 | 47.561 | 525.433 | 20/24 |
|
|
3559
|
+
|
|
3560
|
+
Requiring longer matches avoids many rejected proposals. Minimum two has the highest single-request decode in this screen; minimum five has the highest aggregate throughput. Neither dominates ordinary execution from the adjacent matched campaign (about 53.8 decode and 159 aggregate tok/s). Minimum two improves single-request decode but still gives up concurrent throughput; minimum five lowers both decode and aggregate throughput versus ordinary. Lookup stays opt-in; these results do not establish a global match-length default.
|
|
3561
|
+
|
|
3562
|
+
Three concurrent responses/usage records differ between the minimum-one repeats (39/455 versus 26/444 accepted/proposed); their aggregate timings remain close. The other settings repeat their own responses and usage exactly. Different match thresholds change response trajectories, so the timing differences are configuration results, not same-output engine speedups. All eight arms complete 120 requests without phase failures. Raw commands, request hashes, source identity and comparisons: `reports/qwen38-closeout/composition-baseline/ngram-settings/`.
|
|
3563
|
+
|
|
3564
|
+
|
|
3565
|
+
### Independent greedy sampling across verification positions (M4 Pro, 2026-09-11)
|
|
3566
|
+
|
|
3567
|
+
Apple M4 Pro, 24 GB, Bun 1.4.2, MLX 0.32.2. Twelve matched `bench-serve.ts all` arms compare frozen control `ef832276f7a43d2a203e8d8e4b41c362459bf55d7389803af18ca8e995c83838` with candidate `22d1a38a761ea28c0dcd3ec90374a6a6931bbd9d2965bb7c64a65458aae45398`. Gemma e4b OptiQ with the upper adapter, bf16 KV, scheduler capacity eight, four concurrent requests, 192 decode tokens, 2 GiB prompt cache plus SSD, workload seed `adapter-lookup-0`. Each setting runs control/candidate/candidate/control. Diagnostic mode follows Josh's CPU/swap policy; retained swap and background App Store CPU activity are recorded in raw reports.
|
|
3568
|
+
|
|
3569
|
+
The sampler exposes a stateless operation for compatible greedy rows. Ordinary decode and speculative verification share normalized-score argmax; verification reads its independent token rectangle once. Grammar, processors, stochastic sampling, logprobs and custom sampler functions retain request-local sampling. Tests include rounding-created ties where raw-logit argmax would choose a different token.
|
|
3570
|
+
|
|
3571
|
+
Means of the two arm medians for single-request decode/cold latency; means of the two measured aggregate/cached values:
|
|
3572
|
+
|
|
3573
|
+
| Method | Decode control → candidate, tok/s | Aggregate control → candidate, tok/s | Aggregate change | Cached TTFT control → candidate, ms | Cold TTFT control → candidate, ms |
|
|
3574
|
+
|---|---:|---:|---:|---:|---:|
|
|
3575
|
+
| Ordinary | 54.198 → 54.278 | 162.724 → 162.721 | −0.002% | 38.378 → 37.283 | 530.258 → 522.210 |
|
|
3576
|
+
| Lookup depth 3, min/max 1/3 | 55.101 → 54.898 | 79.716 → 80.779 | +1.334% | 30.760 → 30.517 | 518.664 → 516.427 |
|
|
3577
|
+
| Lookup depth 3, min/max 5/5 | 51.405 → 51.712 | 136.141 → 138.956 | +2.067% | 47.652 → 47.348 | 539.549 → 536.417 |
|
|
3578
|
+
|
|
3579
|
+
Ordinary decode changes +0.148%; lookup 1/3 changes −0.368%, and lookup 5/5 changes +0.598%. Aggregate wall time changes +0.002%, −1.319% and −2.025%, respectively. Startup changes +0.045%, +10.505% and −7.777%, while ready time stays within 0.3%; the small source change does not establish startup dominance. Peak RSS changes −0.321%, −0.248% and +0.413%.
|
|
3580
|
+
|
|
3581
|
+
All 180 requests succeed and every arm retains its source hash. The first paired comparisons preserve every response and usage record. Ordinary and 5/5 repeats are exact, as are both candidate 1/3 runs. The 1/3 control repeat changes three concurrent responses and speculation usage; it is not an exact repeated trajectory. The stricter lookup setting still loses aggregate throughput to ordinary decoding, so no lookup default changes. Both-machine numerical, full-suite/typecheck and adapter native/generated RAM/SSD checks pass. Raw commands, source inventories, results and response comparisons are under `reports/qwen38-closeout/composition-baseline/independent-sampling/`.
|
|
3582
|
+
|
|
3583
|
+
|
|
3584
|
+
### Shared ordinary checkpoints and queued persistence (M4 Pro, 2026-09-11)
|
|
3585
|
+
|
|
3586
|
+
Apple M4 Pro, 24 GB, Bun 1.4.2, MLX 0.32.2. Ten matched `bench-serve.ts all` arms compare frozen control `6ab45ad7bda4adf9760eb69312bbf1dacdb8fe17592df9bc8f5699e7c8b692a9` with candidate `4dcf90668b7a319538ba648de196b72d81a8a26aa1bcef7d45ba5ce4f393c6e8`. Gemma e4b OptiQ, bf16 KV, no adapter, 192 decode tokens, four concurrent requests, 2 GiB prompt cache plus SSD, workload seed `ordinary-continuation-0`. Shared scheduler capacity is eight. Ordinary arms run control/candidate/candidate/control; checkpoint interval 64 runs old serial/new serial/new shared/new shared/new serial/old serial. Diagnostic mode follows Josh's CPU/swap policy; retained swap and background App Store CPU activity are recorded.
|
|
3587
|
+
|
|
3588
|
+
The candidate shares ordinary restore/capture through a checkpoint-policy interface and queues owned SSD snapshots through the existing idle gate. Completion invalidates the checkpoint immediately and queues ordered disk cleanup. Means of the two arm medians for decode/cold latency; means of aggregate/cached measurements:
|
|
3589
|
+
|
|
3590
|
+
| Execution | Decode tok/s | Aggregate tok/s | Aggregate wall ms | Cached TTFT ms | Cold TTFT ms |
|
|
3591
|
+
|---|---:|---:|---:|---:|---:|
|
|
3592
|
+
| Ordinary control | 59.401 | 169.043 | 3028.808 | 67.649 | 551.692 |
|
|
3593
|
+
| Ordinary candidate | 59.258 | 168.873 | 3031.856 | 67.720 | 553.158 |
|
|
3594
|
+
| Checkpoint, old serial | 58.702 | 57.265 | 8940.938 | 67.800 | 559.996 |
|
|
3595
|
+
| Checkpoint, queued serial | 59.011 | 57.458 | 8910.919 | 67.758 | 565.658 |
|
|
3596
|
+
| Checkpoint, queued shared | 58.905 | 168.159 | 3044.730 | 67.975 | 566.320 |
|
|
3597
|
+
|
|
3598
|
+
The ordinary source comparison changes decode −0.241%, aggregate throughput −0.101%, cached TTFT +0.105%, cold TTFT +0.266%, startup +0.480% and peak RSS +0.084%. Queuing serial persistence changes decode +0.526%, aggregate +0.337%, cold TTFT +1.011% and peak RSS −1.141% versus old serial. Moving checkpoint-enabled requests from queued serial to shared execution raises aggregate throughput **192.667% (2.927×)** and reduces aggregate wall time **65.831%**; single-request decode changes −0.179%, cached TTFT +0.321%, cold TTFT +0.117%, startup +0.648% and peak RSS +0.239%. This establishes concurrent throughput improvement on this workload, with the small single-request costs recorded.
|
|
3599
|
+
|
|
3600
|
+
All 150 requests succeed, source hashes stay fixed, and each arm repeats its own response/usage records exactly. Ordinary source and queued-serial comparisons preserve all responses and usage. Shared versus queued serial changes one concurrent response; all 15 usage records report the different execution lane and three concurrent requests reuse 11 rather than 13 prompt tokens. Other usage fields match. These timed requests complete normally; separate both-machine native and HTTP interruption/flush/fresh-server checks establish exact checkpoint restoration at matching batch geometry, including compiled and mixed-grammar bf16 controls. Those checks found a resumed shared cached-token counter could include replayed output; its clamp is under validation in the subsequent quantized candidate and is not part of this frozen timing source. This is not a process-crash durability or full Kanban acceptance result. Raw commands, source inventory and comparisons: `reports/qwen38-closeout/composition-baseline/ordinary-continuation-composition/`.
|
|
3601
|
+
|
|
3602
|
+
### Shared ordinary continuation composition (M4 Pro, 2026-09-11)
|
|
3603
|
+
|
|
3604
|
+
Eight completed `bench-serve.ts all` arms on the Apple M4 Pro, 24 GB, Bun 1.4.2 and MLX 0.32.2. Gemma e4b OptiQ, no adapter, 192 decode tokens, four concurrent requests, scheduler capacity eight, 2 GiB RAM cache plus temporary SSD, checkpoint interval 64 and workload seed `ordinary-continuation-0`. Diagnostic mode follows Josh's campaign policy. Frozen control `4dcf90668b7a319538ba648de196b72d81a8a26aa1bcef7d45ba5ce4f393c6e8` and candidate `c918d6e76e702f86d66f17095f33f0aa00d912e8c7f4a469e9992dfbe90a03a0` run control/candidate/KV4/TurboQuant, then the reverse. Context sweeps are omitted in this short comparison.
|
|
3605
|
+
|
|
3606
|
+
The candidate composes ordinary continuation with shared cache layouts, fixes resumed cached-token accounting and the pending-token dtype, and materializes Gemma's model constants before compiler capture. Separate native/HTTP tests cover actual interruption and restoration; the timed requests complete normally. Decode and cold latency are means of arm medians; other columns are means of the two arms.
|
|
3607
|
+
|
|
3608
|
+
| Shared checkpoint configuration | Decode tok/s | Aggregate tok/s | Aggregate wall ms | Cached TTFT ms | Cold TTFT ms | Startup ms | Peak RSS MiB |
|
|
3609
|
+
|---|---:|---:|---:|---:|---:|---:|---:|
|
|
3610
|
+
| Control, bf16 KV | 59.186 | 168.196 | 3044.070 | 67.724 | 556.523 | 904.388 | 6751.820 |
|
|
3611
|
+
| Candidate, bf16 KV | 59.034 | 168.304 | 3042.116 | 67.836 | 558.943 | 908.403 | 6738.312 |
|
|
3612
|
+
| Candidate, affine KV4 | 58.286 | 164.636 | 3109.894 | 70.515 | 564.785 | 916.674 | 6768.227 |
|
|
3613
|
+
| Candidate, TurboQuant k8v3 | 57.197 | 165.002 | 3102.993 | 71.260 | 559.206 | 899.109 | 6744.930 |
|
|
3614
|
+
|
|
3615
|
+
At unchanged bf16 settings, decode changes −0.256%, aggregate throughput +0.064%, cached TTFT +0.166% and cold TTFT +0.435%. This is effectively flat performance. All source-comparison responses and usage records match. All four configurations repeat their own responses and usage exactly, all 120 requests succeed without phase failures, and every source hash remains fixed.
|
|
3616
|
+
|
|
3617
|
+
Compared with candidate bf16, KV4 changes decode −1.267% and aggregate throughput −2.179%; TurboQuant changes decode −3.112% and aggregate throughput −1.962%. KV4 changes ten response texts and TurboQuant nine, with unchanged usage records. These short-context settings do not improve speed or establish a memory advantage from peak RSS. They remain configuration tradeoffs rather than new defaults. Raw arms and derived response/timing comparisons: `reports/qwen38-closeout/composition-baseline/ordinary-continuation-final/`.
|