Skip to content

fix(trellis): make mixed expert counts runtime-dynamic - #117

Merged
lukealonso merged 6 commits into
masterfrom
fix/mixed-trellis-runtime-counts-benchmark-20260803
Aug 6, 2026
Merged

fix(trellis): make mixed expert counts runtime-dynamic#117
lukealonso merged 6 commits into
masterfrom
fix/mixed-trellis-runtime-counts-benchmark-20260803

Conversation

@voipmonitor

@voipmonitor voipmonitor commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Mixed Trellis K3/K4 expert counts and shared-H rotation flags are checkpoint
data, not compile geometry. This PR passes both through the runtime ABI while
preserving one compiled kernel for compatible 256-expert partitions.

The first commit retains Michel Belleau's original #114 change with authorship
preserved. The follow-up fixes the benchmark's storage contract, carries the
broadcast-H metadata through the mixed wrapper/cache, and adds focused
regression coverage.

Problem

The shared-H GLM-5.2 EXL3 3.42 bpw checkpoint changes its tier partition by
layer:

  • layer 3: 206 K3 + 50 K4 experts;
  • layers 4-77: 148 K3 + 108 K4 experts;
  • layer 78: 256 K3 experts.

Legacy checkpoints also use other valid partitions, including 192/64.
Embedding these counts or the H-storage layout in a cached kernel can reuse
stale bounds, offsets, or strides when the next layer differs.

The old benchmark also materialized only 16 experts per tier while advertising
a 192/64 launch and padded W13 only. ABI 5 correctly rejected its tight W2 and
global-scale storage before binding raw pointers.

Changes

  • pass K3/K4 counts as runtime kernel arguments;
  • pass per-tier broadcast-H flags through the mixed wrapper and cache;
  • derive tier views and offsets from runtime metadata;
  • keep the compile cache key partition-agnostic where geometry is unchanged;
  • validate expert-sized W13, W2, and global-scale storage before launch;
  • make the benchmark materialize its complete declared storage contract;
  • add regression coverage for dynamic partitions, shared-H, cache reuse,
    storage bounds, and CUDA graph replay.

Validation

  • Mixed-Trellis SM120 suite: 15 passed, including CUDA graph capture/replay,
    changing partitions, shared-H flags, high expert IDs, and storage rejection.
  • Exact layer-3/rank-0 3.42 checkpoint benchmark:
    206/50, shared-H on both tiers, zero relative error, cosine 1.0.
  • Mixed kernel: 70.43 us versus 110.38 us for serial K3 + K4 launches
    (1.567x).
  • Clean TP4 runtime validation on the exact checkpoint passed DCP1/MTP0,
    DCP1/MTP3, and DCP4/MTP3, including CUDA graphs and c8/c16 batching.
  • Legacy 3.25 bpw checkpoint still selects its qualified 192/64 path and boots
    with CUDA graphs.

Relationship to #114

This supersedes #114 because its external head cannot be amended here. The
runtime-count change is retained and credited through its original commit; the
additional commits supply the shared-H contract and validation required for a
mergeable implementation.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Mixed Trellis now reconstructs expert-sized views from runtime tier counts and raw device pointers. The benchmark pads complete tier storage. Compilation supports SUH and SVH broadcasts, and runtime validation checks storage and pointer requirements before execution.

Changes

Mixed Trellis runtime

Layer / File(s) Summary
Exact tier storage preparation
benchmarks/benchmark_mixed_trellis.py, tests/moe/test_benchmark_mixed_trellis.py
The benchmark pads W13, W2, and global-scale storage to the compiled expert count. Tests verify copied data, zero-filled experts, and unit scales.
Runtime expert-count kernel ABI
sparkinfer/moe/_shared/kernels/w4a16/mixed_trellis.py, tests/moe/test_w4a16_mixed_trellis.py
The ABI passes tier expert counts at launch. Dispatch and MoE bounds use those counts. The kernel rebuilds tensor views from raw pointers.
Broadcast-aware compilation and cache metadata
sparkinfer/moe/_shared/kernels/w4a16/mixed_trellis.py, tests/moe/test_w4a16_mixed_trellis.py
Compilation accepts SUH and SVH broadcast options. Cache results refresh launch metadata. Tests cover shared rotations, partition reuse, numerical equivalence, repeated execution, and CUDA graphs.
Fail-closed launch validation
sparkinfer/moe/_shared/kernels/w4a16/mixed_trellis.py, tests/moe/test_w4a16_mixed_trellis.py
Validation checks dtypes, devices, contiguity, sizes, expert counts, routing maps, and 16-byte alignment. Tests cover malformed storage and misaligned rotations.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller as mixed_trellis runtime
  participant Cache as compilation cache
  participant Validator as tier storage validation
  participant Kernel as MixedTrellis kernel
  Caller->>Cache: request compilation with tier counts and broadcast flags
  Cache-->>Caller: return compiled artifact metadata
  Caller->>Validator: validate storage, maps, and rotations
  Validator-->>Caller: return validated raw pointers
  Caller->>Kernel: launch with pointers and runtime expert counts
  Kernel->>Kernel: reconstruct views and enforce expert bounds
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: making mixed Trellis expert counts runtime-dynamic.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/mixed-trellis-runtime-counts-benchmark-20260803

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/moe/test_w4a16_mixed_trellis.py`:
- Line 343: Update the pytest.raises call’s match pattern to use a raw string
literal, preserving the existing regex and error text; follow the nearby
rf-string style used in the same test module.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f0885793-7bf6-4366-a0f3-4d80afd48128

📥 Commits

Reviewing files that changed from the base of the PR and between 77154c1 and cf2662b.

📒 Files selected for processing (4)
  • benchmarks/benchmark_mixed_trellis.py
  • sparkinfer/moe/_shared/kernels/w4a16/mixed_trellis.py
  • tests/moe/test_benchmark_mixed_trellis.py
  • tests/moe/test_w4a16_mixed_trellis.py

Comment thread tests/moe/test_w4a16_mixed_trellis.py Outdated
@malaiwah

malaiwah commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Independent AIBeast field validation: exact r25 / #117 head — PASS

I independently qualified the released implementation on the full 3.36-bpw
checkpoint, including both of its real mixed partitions.

Immutable inputs

  • Image: voipmonitor/vllm:gilded-gnosis-v20-vllmf5981f1-si978cdb3-fi801d57a-cu132-20260803-r25
  • Manifest: sha256:042936fd8d9e4c2aa579ab9b736dd0a2faf2678c6ba36bf4dfce7db566c6fd11
  • PR head: cfeee9b42d21c19a74d85ed5576f8387168df53c
  • Shipped mixed_trellis.py SHA-256: edf3790e04252fb3d65507ff778e8af1d497dcd119ec0cd7dd61c3af4d47bc82
  • Checkpoint: willfalco/GLM-5.2-EXL3-TR3-3.36bpw@8d9aa923a17502675ca23737349b67f2e66bb69d
  • Hardware: 4x RTX PRO 6000 Blackwell 96 GiB, driver 595.71.05, CUDA 13.2, 280 W/GPU; physical CUDA order 2,1,0,3

Appliance production shape

TP4 / DCP4 / MTP3 probabilistic+standard / ONLINE_QUANT=exl3-b6 / dynamic-token NVFP4 MLA+FP8 RoPE / seq=8 / graph=32 / batch=3072 / EXL3 prefill capacity=3072 / GMU=.957 / fixed 2048 blocks = 524288 logical KV tokens, plus LMCache 125 GiB DRAM and bounded 512 GiB NVMe.

This intentionally extends the release's 2,048-token/greedy gate with our
previously qualified PP-first scheduler and real agent speculation posture.

Runtime and memory evidence

  • layer 3 logged tiers=((3, 206), (4, 50))
  • layers 4–77 logged tiers=((3, 160), (4, 96))
  • both layouts planned one-grid decode=32 and one-grid prefill=3072/3072
  • model 81.07 GiB/rank; peak activation 3.29 GiB; non-Torch 0.44 GiB; graphs 0.21 GiB
  • exact active GPU KV: 524,288 tokens
  • no request failure, preemption, CUDA OOM, stale-layout symptom, or degeneration

Matched benchmark

metric result
cold unique-prefix PP 3K / 32K / 128K 2362.8 / 2284.9 / 2143.8 tok/s
aggregate TG C1 / C2 / C4 / C8 100.7 / 162.2 / 240.1 / 297.0 tok/s
MTP MAL C1 / C2 / C4 / C8 3.13 / 3.43 / 3.41 / 3.02

Strict structured output with thinking passed. The release gate used an actual
521,275-token prompt and recovered 5/5 needles at 1/25/50/75/99% depth in
300.8 s, with no degeneration or OOM.

I also qualified the exact #117 source over the older r20 integration before
r25 arrived; its 3K/32K/128K PP was 2350.8/2276.4/2128.9 tok/s, C1 was 118.9
tok/s, and the same 521K five-depth gate passed. The r25 packaged result is
therefore consistent with the exact-source candidate rather than only passing
at the unit/kernel-test layer.

Conclusion: #117 fixes the actual 206/50 versus 160/96 geometry and is ready
for this four-GPU production workload from my side.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
sparkinfer/moe/_shared/kernels/w4a16/mixed_trellis.py (1)

1219-1232: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Validate the 16-byte alignment of x before binding it as an aligned pointer.

The new validation block checks dtype, device, contiguity, element count, and % 16 != 0 alignment for every tier-storage buffer and every rotation table. x is checked only for dtype and contiguity, yet line 1346 binds it with assumed_align=16. A caller-supplied misaligned view, for example a narrowed or externally wrapped bf16 buffer, then violates the alignment promise given to the compiler and the kernel performs undefined vectorized loads. Contiguity does not imply 16-byte base alignment.

Add the same alignment check that the rotation tables use.

🛡️ Proposed fail-closed check
         if not tensor.is_contiguous():
             raise ValueError(f"mixed Trellis {name} must be contiguous")
+    if int(x.data_ptr()) % 16 != 0:
+        raise ValueError(
+            "mixed Trellis input must have at least 16-byte alignment"
+        )

Also applies to: 1341-1347

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sparkinfer/moe/_shared/kernels/w4a16/mixed_trellis.py` around lines 1219 -
1232, Update the input validation loop for the “input” tensor x to verify its
data pointer is 16-byte aligned, matching the rotation-table alignment check,
before x is bound with assumed_align=16. Preserve the existing dtype and
contiguity checks and raise the established validation error when x is
misaligned.
🧹 Nitpick comments (1)
tests/moe/test_w4a16_mixed_trellis.py (1)

540-552: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add the reverse fail-closed case.

The test rejects broadcast rotations against a non-broadcast launch. The opposite direction is untested: expanded, per-expert rotations against broadcast_launch must also fail, because validation requires exactly 1 * hidden_size elements when launch.broadcast_suh is true. That direction is the one a caller hits after switching a layer to broadcast without shrinking the tables, so it is worth pinning.

💚 Proposed additional assertion
     with pytest.raises(ValueError, match=r"gate SUH.*512 elements"):
         run_mixed_trellis(
             x,
             tier0,
             tier1,
             topk_weights,
             topk_ids,
             global_to_combined,
             descriptor,
             broadcast_rotations,
             expanded_launch,
             expanded_buffers,
         )
+    with pytest.raises(ValueError, match=r"gate SUH.*128 elements"):
+        run_mixed_trellis(
+            x,
+            tier0,
+            tier1,
+            topk_weights,
+            topk_ids,
+            global_to_combined,
+            descriptor,
+            expanded_rotations,
+            broadcast_launch,
+            broadcast_buffers,
+        )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/moe/test_w4a16_mixed_trellis.py` around lines 540 - 552, Add a reverse
validation test alongside the existing mixed-trellis ValueError case: invoke
run_mixed_trellis with expanded per-expert rotation tables and broadcast_launch
enabled, then assert it raises ValueError mentioning the required gate SUH size
of 1 × hidden_size. Reuse the existing test fixtures and arguments while
switching only the launch/rotation configuration needed to cover the broadcast
validation path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@sparkinfer/moe/_shared/kernels/w4a16/mixed_trellis.py`:
- Around line 1219-1232: Update the input validation loop for the “input” tensor
x to verify its data pointer is 16-byte aligned, matching the rotation-table
alignment check, before x is bound with assumed_align=16. Preserve the existing
dtype and contiguity checks and raise the established validation error when x is
misaligned.

---

Nitpick comments:
In `@tests/moe/test_w4a16_mixed_trellis.py`:
- Around line 540-552: Add a reverse validation test alongside the existing
mixed-trellis ValueError case: invoke run_mixed_trellis with expanded per-expert
rotation tables and broadcast_launch enabled, then assert it raises ValueError
mentioning the required gate SUH size of 1 × hidden_size. Reuse the existing
test fixtures and arguments while switching only the launch/rotation
configuration needed to cover the broadcast validation path.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a8baca17-605c-4ff8-8689-0889e087eb50

📥 Commits

Reviewing files that changed from the base of the PR and between cfeee9b and c969cea.

📒 Files selected for processing (2)
  • sparkinfer/moe/_shared/kernels/w4a16/mixed_trellis.py
  • tests/moe/test_w4a16_mixed_trellis.py

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants