Skip to content

perf(moe): precompute Q4_K scales for Muse concurrent decode - #1056

Closed
shinyuser2345-svg wants to merge 1 commit into
gittensor-ai-lab:mainfrom
shinyuser2345-svg:perf/q4k-down-mma-precomputed-scales
Closed

perf(moe): precompute Q4_K scales for Muse concurrent decode#1056
shinyuser2345-svg wants to merge 1 commit into
gittensor-ai-lab:mainfrom
shinyuser2345-svg:perf/q4k-down-mma-precomputed-scales

Conversation

@shinyuser2345-svg

Copy link
Copy Markdown

Summary

Replacement submission for #1055, with the same source code. GitHub refused to reopen that PR after a commit-message-only force-push; restoring its recorded head and trying both REST and GraphQL did not reopen it. The original PR remains closed and unmerged. Its evaluation discussion and DSpark result remain part of this submission's history. This is not a second optimization or a claim for duplicate credit.

Performance target: Muse Glimmer concurrent decode at c8/c16. The local same-RTX-5090 measurements are +2.699% and +2.651%, respectively. These are local results awaiting official Muse verification; this PR does not claim a Qwen3.8 ModelOpt/DSpark speedup.

Evaluation status: the published DSpark result for the original head reported +0.2% (none) with its correctness and no-regression gates passing. The requested next step is a complete run of the existing Muse evaluator, including all normal guards. The Muse c8/c16 axes already exist.

Wording-only revision: pushed branch commit a7bd73c2c9b37bc9b041f88880872e7e311d9f1f rewords the commit message of 1bb4f593659de504d71c51bd78221412324b1873. This replacement requests the outstanding complete Muse evaluation, with all normal accuracy and cross-model/no-regression guards. Their source trees are identical (f69c51b53937b7eea4ce2213390cfa1f04d516aa). The measurements and test results below were collected for the original source before this message-only revision; no new GPU run or additional speedup is claimed.

Kernel change

Precompute the eight Q4_K down-MMA B scale/min pairs cooperatively while loading
each weight tile, replacing the single-lane metadata expansion and repeated
consumer multiplications. Pad the shared array to a nine-pair row stride to
avoid the consumer's four-way bank aliasing. This targets Lane 1, real measured
inference speedup.

Both existing B loaders are supported. Split-K, row-width dispatch, A staging,
quantization, the MMA instructions and the remaining fold association are
unchanged. A binary16 value times a six-bit integer fits exactly in FP32, so
storing that product introduces no additional rounding. The tradeoff is 1536
additional shared bytes per CTA (12.75 / 15.25 / 20.25 KiB at M8 / M16 / M32).

Proof of speedup

  • Tested on RTX 5090 (sm_120)

Target model(s)

  • Muse Glimmer
  • Qwen3.8-27B (ModelOpt NVFP4 / DSpark)
  • Shared / both — shared Q4_K kernel; both model guards checked

Decode tok/s (end-to-end Muse concurrent decode @c16, aggregate):

decode tok/s
before (main) 814.9
after (this PR) 836.5

The source-built command is the evaluator's qwen3_gguf_cb_bench "$GGUF" C 256 256 512,
not an isolated-kernel microbenchmark. bench/scripts/bench.sh defaults to release
prebuilt binaries; these measurements use separate builds of clean main
bc0e47b799cf39b0429f346b5901bfee208e357e and this change. Same physical RTX 5090,
driver 595.71.05, CUDA 12.8.93, SM120, no implementation-toggle overrides.
SPARKINFER_BENCH_SWEEP_CTXS/REPS are set only for the documented sweep recipe.

Each CB axis has a discarded warmup for each build followed by six interleaved
measured legs (main/PR/PR/main/main/PR); table values are three-run medians.
Every leg checks decode_tokens == C*256+8. Downloads and profiling were stopped
before timing. All raw measured samples are included below, not just the best run.

Axis Main This PR Change
Muse CB decode c2 156.7 157.3 +0.383%
Muse CB decode c4 225.7 225.7 +0.000%
Muse CB decode c8 407.6 418.6 +2.699%
Muse CB decode c16 814.9 836.5 +2.651%
Muse CB decode c32 1130.1 1138.9 +0.779%
Muse decode ctx128 104.6295 104.4162 -0.204%
Muse prefill ctx128 9748.7726 9739.2224 -0.098%
Muse decode ctx512 103.8064 103.6790 -0.123%
Muse prefill ctx512 15249.6373 15199.8482 -0.326%
Muse decode ctx4096 101.2445 101.1920 -0.052%
Muse prefill ctx4096 14434.1239 14408.8772 -0.175%
Muse decode ctx16384 100.3656 100.2667 -0.099%
Muse prefill ctx16384 13764.8172 13747.9518 -0.123%
Muse decode ctx32768 99.1356 99.0909 -0.045%
Muse prefill ctx32768 12640.3508 12629.3382 -0.087%
Muse decode ctx65536 97.2415 97.1979 -0.045%
Muse prefill ctx65536 10924.8947 10928.0034 +0.028%
Qwen3.6 guard decode ctx32768 462.1273 461.8103 -0.069%
Qwen3.6 guard prefill ctx32768 25468.5173 25515.2597 +0.184%
Qwen3.8 ModelOpt guard decode ctx32768 94.5386 94.5328 -0.006%
Qwen3.8 ModelOpt guard prefill ctx32768 10963.9644 10945.8229 -0.165%
Raw measured CB agg_tok_s samples (main / this PR), warmups excluded:
c2   [157.9, 156.7, 156.4]    / [157.6, 157.3, 155.8]
c4   [225.7, 225.4, 225.7]    / [225.7, 225.5, 225.7]
c8   [407.3, 407.6, 407.7]    / [417.9, 419.1, 418.6]
c16  [814.9, 814.9, 813.7]    / [836.1, 836.5, 837.0]
c32  [1111.4, 1130.1, 1131.2] / [1138.9, 1139.1, 1118.0]

Representative real harness lines, c16, main then this PR:
wall_s=5.036 decode_tokens=4104 agg_tok_s=814.9 mean_itl_ms=17.92 max_itl_ms=459.32
wall_s=4.906 decode_tokens=4104 agg_tok_s=836.5 mean_itl_ms=17.40 max_itl_ms=461.50

c32 exhibited two timing patterns in both builds; all samples are retained above.
The repeatable c8/c16 gains, not the highest individual c32 observation, are the
speedup claim. Every measured axis remains above the 98% no-regression floor.

Muse AR uses the unmodified sweep executable, 128 generated tokens, contexts
128/512 at five repeats, 4k/16k/32k at one repeat, and 64k at one repeat in a
separate load, matching the current Muse evaluator's recipe. Both cross-model
guards use 32k and five repeats. These are local reproductions; the official
evaluator's result remains authoritative.

Correctness and tests

  • Full configured CTest suite: 25/25 reported passed, zero failures. Optional
    LMCache integration internally skips when its external sidecar is unavailable;
    this is not a claim of testing LMCache deployment.
  • Added two CTest processes exercising both B loader variants through the
    production launcher. Independent pre-packing double-precision oracle covers
    full six-bit scale/min metadata, eight distinct group activation magnitudes,
    signed inputs and routing weights, two different experts, multiple K-split
    counts and uneven splits, H/F 256/256, 1024/2304, 6656/19968, and M8/9/16/17/32.
  • Two persistent nonblocking streams, explicit initialization ordering, eager
    execution and four CUDA-graph replays across A -> zero -> A. Final test passed
    both loader modes on main and this PR (52 shape-width cases across four runs).
  • Mutation check: using an even scale for an odd group fails the final oracle
    immediately (got=177, want=80.8588639, tolerance=0.646870911). Mutant isolated
    from the tested final build.
  • Final test under compute-sanitizer memcheck: 0 errors for each loader mode.
  • Existing down-MMA synthetic fixture: baseline/candidate output dumps
    byte-identical at M8/9/16/17/32, twice each.
  • Muse teacher-forced qwen3_gguf_score: baseline/candidate numeric output
    byte-identical, SHA256 002574803daad976ce0671340ef7ad50bbb2281daa29e5719747d20f839589e4.
  • Unmodified accuracy_compare.py against native Muse llama.cpp
    5bda51bfbc62e64193221e639f6ad4e08767d760: 99 positions,
    top1=0.969697, KL=0.090603, PPL_spark=2.6881. Both accuracy bars pass.

No evaluator, benchmark script, frozen reference, scoring rule or other
maintainer-owned path is modified.

Reproducibility

Muse: meta-models/Muse-Glimmer-30B-GGUF revision
70bf1b61ac09f91b24d39038091b41c582bc5d7a, KQuant17GB Q4_K_M GGUF,
file SHA256 4cc57c0f51040a226e5a72cc47b7613f7772950e460a665f7083de89f183f60e.
Qwen3.6 guard: unsloth/Qwen3.6-35B-A3B-GGUF revision
a483e9e6cbd595906af30beda3187c2663a1118c, UD-Q4_K_M SHA256
ac0e2c1189e055faa36eff361580e79c5bd6f8e76bffb4ce547f167d53e31a61.
Qwen3.8 guard: gittensor-model-hub/Qwen3.8-27B-NVFP4-RTX5090 revision
5b7a687fc8211a5d631c8ca6a593dd37eb26ce33, both safetensors shards hash-verified.

# Each source revision built separately with CUDA 12.8.93 and SM120.
cmake -S . -B build-cuda12.8 -G Ninja -DCMAKE_CUDA_ARCHITECTURES=120 \
  -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS_RELEASE="-O3 -UNDEBUG" \
  -DBUILD_TESTS=ON -DBUILD_EXAMPLES=ON -DBUILD_CUTE_KERNELS=OFF -DBUILD_SERVER=OFF
cmake --build build-cuda12.8 -j12
ctest --test-dir build-cuda12.8 --output-on-failure
SPARKINFER_MMA_BDEDUP=1 compute-sanitizer --tool memcheck --error-exitcode 99 \
  build-cuda12.8/kernels/tests/down_mma_scales_gpu_test
SPARKINFER_MMA_BDEDUP=0 compute-sanitizer --tool memcheck --error-exitcode 99 \
  build-cuda12.8/kernels/tests/down_mma_scales_gpu_test
build-cuda12.8/runtime/qwen3_gguf_cb_bench "$GGUF" 16 256 256 512
SPARKINFER_BENCH_SWEEP_CTXS=128,512 SPARKINFER_BENCH_SWEEP_REPS=5 \
  build-cuda12.8/runtime/qwen3_gguf_bench "$GGUF" 128 sweep

Expand the eight down-MMA weight scale/min pairs cooperatively in the B
loaders and store them in a padded float2[32][9] shared array. This avoids
serial metadata expansion, repeated consumer products and shared-bank
aliasing, at a cost of 1536 additional shared bytes per CTA.

The measured performance target is Muse Glimmer concurrent decode, not
Qwen3.8 ModelOpt/DSpark. Local same-RTX-5090, source-built three-run medians
against bc0e47b were:
  c8:  407.6 -> 418.6 aggregate tok/s (+2.699%)
  c16: 814.9 -> 836.5 aggregate tok/s (+2.651%)
Command: qwen3_gguf_cb_bench "$GGUF" C 256 256 512
The full matrix, raw samples and correctness evidence are in PR gittensor-ai-lab#1055.
These are local results; an official Muse verdict is still required.

Keep both B loaders, split-K, row-width dispatch, MMA instructions and
the remaining fold association unchanged. Cover scale/min unpacking,
uneven shapes, both loaders, streams and graph replay with independent
reference tests. Shared-code scope and cross-model guards remain intact.

This is a commit-message-only rewording of
1bb4f59, with an identical source tree.
The previous DSpark evaluation reported no verified speedup (+0.2%) and
passed its correctness and no-regression gates. No new source change,
GPU measurement, DSpark gain or scoring override is claimed here.
@shinyuser2345-svg

Copy link
Copy Markdown
Author

Maintainer request: complete Muse evaluation

This is the clearly linked replacement for closed PR #1055, which GitHub would not reopen after a message-only force-push, including after restoring its recorded head. The original request and evaluation history are retained.

Please evaluate Muse Glimmer, including the complete scored matrix and all normal accuracy and Qwen3.6/ModelOpt no-regression guards. The claimed benefit is concurrent decode:

  • c8: 407.6 -> 418.6 aggregate tok/s (+2.699%).
  • c16: 814.9 -> 836.5 aggregate tok/s (+2.651%).

These are the original local same-RTX-5090, source-built three-run medians against bc0e47b799cf39b0429f346b5901bfee208e357e, using qwen3_gguf_cb_bench "$GGUF" C 256 256 512. They require official confirmation. The full matrix, raw samples, model hashes, and correctness evidence are in the PR description.

Head a7bd73c2c9b37bc9b041f88880872e7e311d9f1f only rewords the message of 1bb4f593659de504d71c51bd78221412324b1873; their source trees are identical. No fresh GPU run or additional speedup is claimed. The original DSpark none result (+0.2%, correctness/guards passed) is not disputed.

The existing Muse evaluator already scores c8/c16. Muse and Shared/both remain checked because this is shared-kernel code. Could a maintainer ensure the full Muse result is considered, or clarify the permitted routing for this Muse-targeted shared-kernel change? No guard bypass, new axis, or manual tier is requested.

@skyrocket2026

Copy link
Copy Markdown
Member

sparkinfer DSpark auto-eval — eval-dspark:none

metric value
label eval-dspark:none
scored at DSpark decode + batched prefill @4k/@16k/@32k; target prefill @256k; concurrent decode @c2/c4/c8/c16/c32 on the ModelOpt NVFP4 checkpoint
winning axis dspark-decode@4k — the dimension this label came from
PR DSpark @4k 129.80 tok/s
main DSpark @4k 129.83 tok/s
DSpark decode @4k vs main +0.0%
PR prefill @4k 14990.5 pp/s
main prefill @4k 15011.9 pp/s
prefill @4k vs main -0.1%
PR DSpark @16k 130.47 tok/s
main DSpark @16k 130.41 tok/s
DSpark decode @16k vs main +0.0%
PR prefill @16k 11656.2 pp/s
main prefill @16k 11650.6 pp/s
prefill @16k vs main +0.0%
PR DSpark @32k 97.75 tok/s
main DSpark @32k 97.79 tok/s
DSpark decode @32k vs main +0.0%
PR prefill @32k 10499.2 pp/s
main prefill @32k 10526.7 pp/s
prefill vs main -0.2%
PR prefill @256k 4958.3 pp/s
main prefill @256k 4973.0 pp/s
PR decode @256k 94.73 tok/s
main decode @256k 94.76 tok/s
prefill @256k vs main -0.2%
PR concurrent decode @c2 186.9 tok/s agg
main concurrent decode @c2 187.0 tok/s agg
concurrent decode @c2 vs main -0.1%
PR concurrent decode @C4 325.4 tok/s agg
main concurrent decode @C4 325.6 tok/s agg
concurrent decode @C4 vs main -0.1%
PR concurrent decode @c8 535.6 tok/s agg
main concurrent decode @c8 536.7 tok/s agg
concurrent decode @c8 vs main -0.2%
PR concurrent decode @c16 773.7 tok/s agg
main concurrent decode @c16 774.8 tok/s agg
concurrent decode @c16 vs main -0.1%
PR concurrent decode @C32 1309.8 tok/s agg
main concurrent decode @C32 1309.8 tok/s agg
concurrent decode @C32 vs main +0.0%
PR concurrent decode @c1 (floor) 93.7 tok/s agg
main concurrent decode @c1 (floor) 95.1 tok/s agg
concurrent @c1 vs main (floor) -1.5%
PR AR tok/s (floor) 88.56
main AR tok/s (floor) 88.61
AR vs main (floor) +0.0%
DSpark vs AR 1.473× — above 1.0 means speculation finally pays
mean accept τ 1.730 (main 1.730, ceiling 7)
accuracy gate ✅ top1=1.000 (bar >=0.9) · KL=0.0000 (bar <=0.1)
cross-run determinism ✅ identical output across 3 clean runs
losslessness gate ✅ DSpark matches the AR reference token-for-token, verified across 3 independent runs
losslessness @4k ✅ DSpark matches AR token-for-token, verified across 3 independent runs
losslessness @32k ✅ DSpark matches AR token-for-token, verified across 3 independent runs
mean accept τ @4k ✅ 1.6623 (main 1.6623)
mean accept τ floor ✅ 1.7297 vs main 1.7297 (bar ≥95%)
mean accept τ @32k ✅ 1.3299 (main 1.3299)
qwen3.8 (upstream unsloth) guard @16k ✅ no regression (decode+prefill) — decode 82.8 tok/s · prefill 10030 pp
qwen3.6 guard @16k ✅ no regression (decode+prefill) — decode 461.2 tok/s · prefill 27387 pp
PPL PR / main 3.0301 / 3.0301
Polaris receipt collected, not signed (no key configured)
commit a7bd73c2c

within significance gate — not a verified dspark-decode@4k improvement

Scored on the pinned eval box vs same-box origin/main: DSpark speculative decode and production batched prefill at ctx=4k, ctx=16k and ctx=32k, plus target prefill at ctx=256k, on the ModelOpt NVFP4 checkpoint. The AR reference is measured in the same process and the same model load. Both a regression in AR decode and any divergence from the AR token sequence are hard REJECTs — a speculative decoder that is fast because it skips verification is not faster, it is wrong. τ is the lever, and the row above reports it against a block_size of 7. This is informational, not a judgment on your PR: a none label just means no measurable improvement on any scored axis was verified, which is expected and fine if that isn't what your change is about. Automated — merge behaviour depends on SPARKINFER_DSPARK_AUTOMERGE.

@skyrocket2026 skyrocket2026 added the eval:none sparkinfer auto-eval verdict: none label Sep 12, 2026
@skyrocket2026

Copy link
Copy Markdown
Member

Closed: no verified speedup — eval-dspark:none

Measured on the pinned RTX 5090 against the same-box origin/main: 0.0% on the best scored axis (DSpark decode and batched prefill @ 4k/16k/32k, target prefill and decode @ 256k).

This is not a finding that anything is wrong with your PR. Nothing regressed and every correctness gate passed — the change just did not move a number this bot measures. The queue is closed rather than left open so it reflects work that can still be scored.

Three ways forward, depending on which applies:

  • Targeting a different model? Tick it under Target model(s) in the PR template — this bot only measures Qwen3.8-27B, and a PR declared for another model is skipped rather than scored none here.
  • Nothing here measures your optimization yet? Open an issue describing the axis you need — model, metric, context, and the command that measures it — with your before/after numbers, then reopen and ask for the hold label so it stays open while the axis is added.
  • Correctness fix, refactor, test or docs? Welcome, reviewed by hand, score 0 by design. Reopen as a draft or ask for hold and say so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

eval:none sparkinfer auto-eval verdict: none eval-dspark:none DSpark decode@128 eval tier

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants