Files

158 lines
9.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Qwen row-map expert gather (#112)
The sorted Qwen gate/up path now retains the uint32 token row map, builds GPU
per-expert row/tile prefix sums, and dispatches the pinned 64×64×64 NAX kernel.
The kernel reads original token rows and emits SwiGLU directly. Down projection
continues through the #110 guarded stock gather. The unsorted decode/verify
path is unchanged. Packed and separate gate/up weights preserve their original
activation rounding and fallback ordering.
Oracle: MTPLX `9882703f3105363ddc37eca9f97aa09a1d387112`, MLX 0.32.2.
Installed Bare-Speed artifact: `74559cdf34fbfc0b593de72d17e93f37fd4f9ea7`;
artifact hashes and machine details are in ../issue104-ar/environment.json.
Native pre-port baseline: `8965e77ea173c932e00f70759d0a83ac1c5072f0`.
Only GPU shader source is shipped from the oracle: the MTPLX kernel body and
its MLX 0.32.2 GPU template/functor closure, with MIT licenses in `metal/`.
`tools/issue112-extract-metal.py` reproduces those files from the pinned
reference environment. All scheduling, policy, graph construction, checking,
model loading and sessions remain Rust. There is no production Python/MLX/C
runtime dependency and the pinned runtime metallib is unchanged.
## Route and failure contract
- All original tensor/layout predicates, affine BF16/F16, b4/b8, groups
32/64/128, N/K multiples of 64, and the 4,096-routed-row threshold apply.
- Below-threshold, non-NAX and ineligible inputs retain the stock path.
`MTPLX_MOE_SORTED_GATHER_KERNEL=0` and the GPU-family rehearsal switch are
resolved by Qwen policy without mutating the process environment.
- Whole-first-call canaries are keyed by compiled instantiation and the
under/from-64-rows-per-expert regime. They compare uint16 bits, including
signed zero, then reuse the checked result. Compile/dispatch failures or
mismatches disable that key for the process with a reason and counters.
- A failed packed SwiGLU canary tries the separately checked plain row-map
gather before guarded stock fallback, as upstream does. Separate SwitchGLU
returns to its original up/gate/compiled-activation chain.
- The only generalized helper is Qwen's GatherQMM: its existing BF16 behavior
is retained, with the F16/group-128 specializations needed for the oracle's
supported canary/fallback contract. All callers are in the Qwen module.
## Isolated verification
The native synthetic matrix covers 72 cases: BF16/F16 × b4/b8 × g32/64/128 ×
packed/separate × 4,096/8,193/32,769 routed rows. It includes empty expert runs,
partial tiles, both canary regimes, a strided uint32 row map and int64 expert
IDs. Every result equals guarded stock and the pinned oracle bit for bit;
48 first-use canaries pass. Actual installed layer-0 projections additionally
cover 410/2,048/3,277/4,095/4,096/8,192 tokens (12 packed/separate cases).
Failure injection uses actual invalid Metal source, a changed output sign bit,
and explicitly differing positive/negative zero. Each disables its key and
subsequent calls use exact stock output without another canary. Metadata and
policy tests cover all exclusion predicates and switch spellings. The full
model off-switch run checks the unchanged output/state and absence of kernel
activation.
The full-model large-prefix control reuses #110's 7,374-token cold prompt and
3,278-token warm suffix at chunks 2,048 and 4,096. It checks every logit and
cache array against the pre-port, pinned-oracle receipts, plus cancellation
and retry. Explicit hidden-state tests use an MTP-capable runtime with cold
4,096-token and warm 2,048-token-suffix prefills; an AR-only runtime correctly
omits warm hidden arrays in the oracle. The AR timing tests compare complete
state after one generated token. State reads occur after measured intervals.
## Paired release measurements
M5 Max, 128 GiB; serial before/after processes, three repetitions per chunk
and phase, identical installed artifacts and token IDs. Both default boundary
splitting (tail interval 256) and full chunks (tail interval 0) are measured.
The latter exercises the wide row regime and guarded partial tails. The
release baseline uses unchanged committed production source with only the
same measurement test module added. No other GPU workload or build ran during
these measurements.
Cells show median ± sample standard deviation across all three repetitions.
Repetition zero includes first-use initialization/canary work; this is not an
isolated measurement of canary overhead. All individual times and means are
in release-performance.json. TTFT starts at the request call and ends at its
first token callback, after model loading.
| Tail policy / chunk / phase | Before TTFT s | After TTFT s | Before prefill tok/s | After prefill tok/s |
|---|---:|---:|---:|---:|
| Default / 2048 / cold | 2.959 ± 0.473 | 2.953 ± 0.480 | 1385.831 ± 183.340 | 1388.955 ± 186.819 |
| Default / 2048 / warm | 1.839 ± 0.075 | 1.900 ± 0.088 | 1115.426 ± 45.227 | 1079.363 ± 52.619 |
| Default / 4096 / cold | 3.690 ± 0.063 | 3.684 ± 0.029 | 1111.739 ± 19.009 | 1113.593 ± 8.843 |
| Default / 4096 / warm | 2.012 ± 0.013 | 1.989 ± 0.019 | 1019.529 ± 6.863 | 1031.159 ± 10.182 |
| Full / 2048 / cold | 2.411 ± 0.475 | 2.504 ± 0.428 | 1699.510 ± 259.818 | 1636.600 ± 239.080 |
| Full / 2048 / warm | 1.262 ± 0.063 | 1.334 ± 0.052 | 1623.785 ± 78.593 | 1536.347 ± 64.230 |
| Full / 4096 / cold | 3.100 ± 0.116 | 2.999 ± 0.136 | 1321.520 ± 49.755 | 1366.360 ± 58.429 |
| Full / 4096 / warm | 1.767 ± 0.057 | 1.634 ± 0.086 | 1159.717 ± 36.444 | 1254.103 ± 61.907 |
Peak physical footprint: default 84.724 → 84.669 GB; full chunks
88.579 → 87.952 GB. The results are mixed and do not establish an overall
speedup. In particular, the default 256-token tail grid often keeps the small
stock route; setting chunk size 4096 does not imply every body call has that
width. The port fulfills the current-route obligation without assuming the
upstream isolated-kernel speedup applies to this server benchmark.
## Reproduction
Set `DS4_QWEN38_ARTIFACTS` to the installed artifact directory. Build the release
test executable with `cargo test --release --all-features --bin ds4-server
issue112 --no-run`, then copy the executable reported by Cargo outside `target`
before running it. Run each ignored test in its own serial process under
`target/debug/test-supervisor MEMORY_MIB 60 120 --command TEST_EXECUTABLE FILTER
--ignored --nocapture --test-threads=1`:
- `issue112_all_kernel_variants` and `issue112_canary_failures`: 4096 MiB.
- `issue112_installed_gate_up`: 16384 MiB.
- `issue112_full_model_state`: 114688 MiB,
`DS4_ISSUE110_DIR=OUTPUT_DIRECTORY`, `MTPLX_GDN_BOUNDARY_TAIL_INTERVAL=0`.
- `issue112_hidden_prefill`: 114688 MiB,
`DS4_ISSUE112_DIR=OUTPUT_DIRECTORY`, `MTPLX_GDN_BOUNDARY_TAIL_INTERVAL=0`.
- `issue112_paired_prefill`: 114688 MiB,
`DS4_ISSUE112_DIR=OUTPUT_DIRECTORY`, optionally tail interval 0;
`DS4_ISSUE112_REPEATS` defaults to 3. Also run a one-repetition full-chunk
control with `MTPLX_MOE_SORTED_GATHER_KERNEL=0`.
Keep child stdout/stderr separate from the supervisor's resource output to
avoid interleaved JSON writes. Under the isolated MLX 0.32.2 reference Python,
run `tools/issue112-reference.py PINNED_CHECKOUT NATIVE_VARIANT_OUTPUT`,
`tools/issue112-installed-reference.py PINNED_CHECKOUT MODEL_DIR NATIVE_OUTPUT`,
and `tools/issue112-model-reference.py PINNED_CHECKOUT MODEL_DIR NATIVE_DIR
ORACLE_DIR` (add `--hidden` for the hidden-state run; use matching tail policy).
The full-model oracle uses the server's lazy-snapshot policy for cache
fingerprints, matching the native session entry; a deep clone adds zero and
would change negative-zero key bits during measurement itself.
For the before arm, build commit `8965e77` with only `issue112_bench.rs` and its
`#[cfg(test)] mod issue112_bench;` registration added. Do not use an off-switch
run as the only baseline: the preserved pre-port executable is the baseline.
Both arms use the same test harness. Run timing arms without other builds or
GPU work; correctness checks may run alongside CPU-only compilation.
## Completion review
All 72 synthetic and 12 installed projection receipts match guarded stock
and pinned MTPLX; compile/sign-bit/signed-zero failures pass sticky-fallback
checks. All four large-prefix snapshots match #110's pre-port/oracle fixtures.
The 24 release before/after state comparisons and four explicit hidden-state
comparisons are exact. The direct pinned oracle matches all four representative
release states and all four hidden-prefill states, including every cache bit.
The off-switch matches all four baseline states with zero kernel activation.
DeepSeek's `resident_multi_session_switching_preserves_each_kv_frontier` and
GLM's `glm53_two_row_verifier_restores_recurrent_state` both pass on the preserved
before binary and the final after binary with installed models. Source review
confirms no DS4/GLM model, sampling, cache, shader, or orchestration path changed.
Their DS4 oracle behavior remains assigned to those families; this is the Qwen
MTPLX route port, not a new DS4Server-only feature. Non-NAX predicates are tested;
no physical M1–M4 run is claimed.
All required commit gates pass: formatting, warning-free Clippy, signed app
bundle, and all-features tests (312 application + 8 tool tests; 234 explicitly
ignored hardware/reference tests). Relevant ignored tests above were run
separately under the resource supervisor. Machine-readable evidence, exact
state fingerprints, gate logs, resource summaries and binary/source provenance
are stored beside this file. No acceptance item is deferred to a stub.