Skip to content

[Engine] sm_80 tuning measured on a CMP 170HX (GA100): prompts up to 2.0x, decode +20 %, conversation switches 5-10x faster; five PRs to follow #3712

Closed

Description

@linxuhao

Area

[Engine] (speed, kernels, models, the server and API)

What do you want to do?

Make Strata fast on sm_80 (GA100-class) cards with every expert resident. Today none of the engine's per-card tables has an sm_80 entry: the wide dense dequant default, the MMVQ-IL rows and the fused prompt-expert thread shapes. #3252 reports A100 slowdowns, and you said you have no sm_80 card. We have one and spent the last weeks tuning for it. We would like to agree on scope here before opening five PRs. The PRs are written and build on CUDA sm_80, HIP gfx1100 and HIP gfx906. Their per-PR GPU runs are in progress.

Card and setup. CMP 170HX: GA100, sm_80, 70 SMs, 64 GB HBM2e, PCIe Gen2 x4 (the engine's probe reads 1.6 GB/s host to device). The card runs at a 1650 MHz clock ceiling with a +250 MHz V/F offset (an undervolt), and its power cap was 235 W or 250 W across these runs.

  • Model: Qwen3.8-Flash-Next IQ3_S native pack, every expert resident (24,576 slots, 46.84 GiB).
  • Engine args: --kv int8 --spec 3 --mtp --prefill 8192 --max-context 262144 --conversation-cache-mib 8192.
  • Software: Linux, driver 610, CUDA 13.3. Measured against 9de04cd (0.2.1.4). The PR branches are now rebased onto main 011c9e6 (0.2.2, engine 0.1.47). None of the 238 commits since 9de04cd overlaps these changes. The rebase had two textual conflicts, each resolved by keeping both sides. This box has two sockets, so 0.2.2's NUMA-split CPU expert pool turns itself on here. The rerun below sets STRATA_NUMA_POOL=0 in both arms, because the automatic split on the arena path gives remote reads and an unstable decode (NUMA pool split on a two-socket Xeon (2x 6226R, 2x R9700): on/off numbers, and the "arena path" limitation #3708).

Overall result. Fresh engine per run, same box.

stock 0.2.1.4 our branch
prompt, ~3K words (tok/s) 2,071 / 2,004 / 2,001 4,136 / 4,145 / 4,042 2.0x
prompt, ~12K words 2,911 / 2,768 4,464 / 4,452 1.57x
prompt, ~48K words (51.8K tokens) 3,114 4,363 1.40x
decode, 384 tokens after a ~3K-word prompt 106.6 / 110.3 129.4 / 131.1 1.20x
park a 3.3K-token conversation (ms) 212-217 21.5-40.1 5-10x
restore (ms) 96-126 28-47; 6.5-12.6 from the second restore of a run

How the two columns were set up:

  • Stock is the release binary with STRATA_PF_FUSED=1 STRATA_OWNED_PRICE=exact.
  • Our branch turns on the switches of all five PRs and several existing upstream switches, for example STRATA_SIDE_MIXER=2, STRATA_GR_UP75=1 and STRATA_QIL=1.
  • It also turns on two switches that are in no PR: STRATA_GDN_OUT_NORM_LOOP and STRATA_MTP_PRIO_ALWAYS. Neither showed a gain.
  • The park and restore "before" times are from our builds with the new switches off. We have no conversation-check run of the stock binary.
  • Greedy answers (11 prompts, 256 tokens, temperature 0) are identical to stock for every bitwise change.

A same-session rerun is queued and will replace this table. It runs on the rebased branches and has three rows:

  1. stock;
  2. stock plus upstream's existing switches;
  3. the five PRs merged, with their switches.

Switches. Every switch is opt-in except the two sm_80 defaults in PR 1, which are bitwise. The effects below were measured on our working builds. Per-switch off/on pairs on the PR branches themselves are in progress, and the table will be updated with them.

switch PR default output effect on the CMP 170HX
wide dense dequant on sm_80 (STRATA_DEQUANT_WIDE) 1 on for sm_80 bitwise 3,259-token prompt GPU time 857 -> 792 ms; prompts +6.3..+7.2 % at 3.3K tokens, +3.9 % at 52K
MMVQ-IL sm_80 row tables (STRATA_MMVQ_IL_SM80=0 restores the shared table) 1 on for sm_80 bitwise decode +2.7..+3.2 % over the shared table
STRATA_PF_FUSED_NT=256 (256-thread fused IQ prompt experts) 1 off bitwise in progress
STRATA_PF_BATCH=N (whole-layer launches, up to 512 experts) 1 off bitwise in progress
STRATA_PLE_COMPACT=1 (raw IQ4_NL PLE rows, dequantized on the device) 2 off bitwise prompts +1.0..+1.7 %
STRATA_PLE_COPY_STREAM=1, STRATA_EMBED_VRAM=1, STRATA_DEQUANT_SIDE=1 2 off bitwise 51.8K-token prompt, measured as a bundle: "ple" 95-103 -> 47 ms, "embed+steps" 191-201 -> 70 ms
STRATA_PF_FUSED_F16=1 / STRATA_PF_FUSED_WS=1 (f16 mma fused experts) 3 off rounding prompts +2..+6 % over the 256-thread kernels; 1 of 11 greedy answers changes
STRATA_GDN_TC=1 (DeltaNet prompt recurrence as a chunked tensor-core scan) 3 off rounding recurrence 105 -> 34 ms at 3.3K tokens, 1,705 -> 547 ms at 52K; prompts +6.6..+7.6 %; within 2.3e-6 of FP32 in gdn_rec_parity; 0 of 11 greedy answers change
STRATA_CKPT_ASYNC=1, STRATA_CKPT_VRAM_SLOTS=N 4 off bitwise turn checkpoint 71.4 -> 0.9 ms; restore 114-126 -> 28-47 ms
STRATA_PARK_ASYNC=1, STRATA_CKPT_POOL=N, STRATA_CKPT_GATHER=1 4 off bitwise park at 3.3K tokens 212-217 -> 21.5-40.1 ms
STRATA_PARK_VRAM_MIB=N 4 off bitwise later restores 6.5-12.6 ms
STRATA_GRAPH_PRIO=1 (verify-window graph nodes keep their stream priority) 5 off bitwise decode +1.8 %
STRATA_MMVQ_IL_PF=1 (hoisted-load integer MMVQ-IL kernels for Q6_K) 5 off bitwise decode +1.4 %

The five PRs. Each PR has one commit per feature, so any of them can be split further.

  1. sm_80 defaults: the two bitwise default changes plus PF_FUSED_NT and PF_BATCH. Upstream's default fused kernels keep identical SASS. Cost: the 256-thread instances add 365,632 bytes of sm_80 device code to every CUDA build.
  2. Prefill over a slow host link: four opt-in switches. Metal gets stubs for the new entry points.
  3. Tensor-core prefill: f16 fused experts and the GDN scan. Both are opt-in and change rounding. Stacked on PR 1. Teacher-forced KL is not run yet.
  4. Conversation cache: background copies, a ready checkpoint pool, VRAM slots. Opt-in and CUDA-only. Compatibility: an existing STRATA_CKPT_POOL=1 now also pre-allocates 2 ready checkpoints (+236 MB of host RSS).
  5. Decode: graph-node priorities and the Q6_K hoisted-load GEMV. Stacked on PR 1, because its table builds on PR 1's sm_80 rows.

PR 1's MMVQ-IL table is the sm_80 counterpart of #3453 (sm_89). The two touch the same table list.

Validation so far.

  • Rebased on 011c9e6, every commit of PRs 1-4 and their branch tips build on CUDA sm_80, HIP gfx1100 (ROCm 7.14) and HIP gfx906, with no new warning in any touched file compared with 011c9e6 built the same way. PR 5's builds are finishing.
  • Before the rebase, PR 3's sources also built for the Dockerfile's architecture list (75, 80, 86, 89, 120). That check has not been redone on 011c9e6.
  • Not run: SYCL and Metal builds, any AMD hardware, CUDA 12, and other sm_80 cards.

Questions.

  1. Five thematic PRs, or a finer split?
  2. Is the 365 KB of sm_80 device code acceptable in every CUDA build, or should it go behind a CMake option?
  3. PRs 3 and 5 are stacked on PR 1. Should we open them as drafts naming PR 1, or wait for PR 1 to merge?

What do you do today instead?

We run our fork's branch (github.com/linxuhao/Strata, opt-sm80 and opt-sm80-hip) with the switches above.

🤖 Generated with Claude Code

Activity

  1. linxuhao commented on Oct 22, 2026

    @linxuhao
    ContributorAuthor

    Draft with all five features, one commit each, rebased on 011c9e6: #3779. Per-feature GPU runs on 011c9e6 are in progress; results will follow here.

    🤖 Generated with Claude Code

  2. linxuhao commented on Oct 23, 2026

    @linxuhao
    ContributorAuthor

    Results on main 011c9e6, same box, STRATA_NUMA_POOL=0 in both arms. The full tables and method are in #3779 #3779 (comment).

    The five PRs merged, with their switches, against stock: 4K prompts 1,980 → 4,131 tok/s (2.09x), 16K 2,889 → 4,458 (1.54x), 52K 3,154 → 4,367 (1.38x), decode 108.6 → 129.5 (1.19x).

    Against stock with upstream's own switches turned on, these PRs add 1.80x / 1.45x / 1.35x on prompts and +8 % on decode. The greedy answers are identical and the A/B/A conversation check is identical.

    🤖 Generated with Claude Code

  3. added 18 commits that reference this issue on Oct 27, 2026
  4. Niko1221 commented on Oct 27, 2026

    @Niko1221
    Owner

    Thank you. #3779 is ported in 0.2.7 with your name on the 18 commits. The bitwise-identical parts (wider dequantisation, the MMVQ tables for sm_80) are on by default for sm_80 (off: STRATA_DEQUANT_WIDE=0, STRATA_MMVQ_IL_SM80=0); the options that change the summation order, need 101 KB of shared memory or have no unit test stay off, and STRATA_DEFAULTS=026 restores 0.2.6. We have no sm_80 card (only sm_86 and sm_120 here); please try 0.2.7 and post your results in the pull request.

    Release: https://github.com/Niko1221/Strata/releases/tag/v0.2.7

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions