Skip to content

[lora] Auto-tune config for MoE LoRA shrink split-K kernel#2

Closed
zcnrex wants to merge 2 commits into
mainfrom
lora-shrink-moe
Closed

[lora] Auto-tune config for MoE LoRA shrink split-K kernel#2
zcnrex wants to merge 2 commits into
mainfrom
lora-shrink-moe

Conversation

@zcnrex

@zcnrex zcnrex commented Jun 1, 2026

Copy link
Copy Markdown
Owner

Auto-tune config for the MoE LoRA shrink split-K kernel

Adds offline tuning + a runtime config loader for _moe_lora_shrink_splitk_kernel
(the LoRA-A / shrink stage of the merged-experts MoE LoRA path), mirroring the
fused_moe_triton config layout.

What's included

  • benchmark/kernels/lora_moe_shrink/ — tuner that sweeps num_warps,
    num_stages, and SPLIT_K (plus BLOCK_SIZE_M in the prefill regime), with
    BLOCK_SIZE_N pinned to the rank and BLOCK_SIZE_K=256. It prunes configs that
    exceed the device shared-memory cap and times with CUDA-graph amortization
    (the kernel is sub-10 µs, so per-launch overhead must be amortized away).
    Benchmark routing is seeded for reproducibility.
  • moe_lora_shrink_config.py — loads configs keyed by (E, N, K, device);
    within a file it selects the entry for the closest token count M.
  • virtual_experts.py — the shrink stage now prefers the tuned config
    (including SPLIT_K), and the same BLOCK_SIZE_M is reused to align the MoE
    routing so the routing and kernel block sizes stay consistent. The heuristic
    fallback (when no tuned file exists) is unchanged.
  • moe_shrink_configs/triton_3_6_0/ — tuned configs for
    E ∈ {96, 192, 384} × rank ∈ {16, 32, 64} × hidden = 7168 on NVIDIA B200.

Kernel latencies (NVIDIA B200, bf16, triton 3.6.0, CUDA-graph amortized)

M is the config key = number of input tokens; in decode M equals the batch
size (1 token/request), in prefill it is the total token count.

num_experts (E) hidden_size (K) rank (N) batch size / num_tokens (M) latency (µs)
96 7168 16 16 6.62
96 7168 16 32 7.46
96 7168 16 64 7.84
96 7168 16 2048 29.56
96 7168 32 16 8.00
96 7168 32 32 9.95
96 7168 32 64 10.00
96 7168 32 2048 38.82
96 7168 64 16 10.95
96 7168 64 32 13.85
96 7168 64 64 14.04
96 7168 64 2048 54.96
192 7168 16 16 7.84
192 7168 16 32 9.06
192 7168 16 64 10.44
192 7168 16 2048 37.99
192 7168 32 16 10.00
192 7168 32 32 12.27
192 7168 32 64 14.58
192 7168 32 2048 53.67
192 7168 64 16 14.33
192 7168 64 32 23.32
192 7168 64 64 29.94
192 7168 64 2048 80.94
384 7168 16 16 8.12
384 7168 16 32 11.27
384 7168 16 64 14.00
384 7168 16 2048 44.87
384 7168 32 16 10.60
384 7168 32 32 14.86
384 7168 32 64 22.96
384 7168 32 2048 61.81
384 7168 64 16 18.09
384 7168 64 32 30.40
384 7168 64 64 42.56
384 7168 64 2048 90.14

🤖 Generated with Claude Code


CI States

Latest PR Test (Base): ❌ Run #26739997874
Latest PR Test (Extra): ❌ Run #26739997813

Adds an offline tuner and a runtime config loader for
_moe_lora_shrink_splitk_kernel (the LoRA-A shrink stage of the merged-experts
MoE LoRA path), mirroring the fused_moe_triton config layout.

- benchmark/kernels/lora_moe_shrink/: tuner that sweeps num_warps / num_stages /
  SPLIT_K (and BLOCK_SIZE_M for prefill), pins BLOCK_SIZE_N=rank and
  BLOCK_SIZE_K=256, prunes configs over the device SMEM cap, and times with
  CUDA-graph amortization (the kernel is us-scale, so per-launch overhead must be
  removed). Benchmark routing is seeded for reproducibility.
- moe_lora_shrink_config.py: loads configs keyed by (E, N, K, device); within a
  file the entry for the closest token count M is used.
- virtual_experts.py: the shrink stage now prefers the tuned config (including
  SPLIT_K), and the same BLOCK_SIZE_M is used to align the MoE routing so the
  routing and kernel block sizes stay consistent. Heuristic fallback unchanged.
- moe_shrink_configs/triton_3_6_0/: tuned configs for E in {96,192,384} x
  rank {16,32,64} x hidden 7168 on NVIDIA B200.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@github-actions github-actions Bot added documentation Improvements or additions to documentation lora labels Jun 1, 2026
Re-tuned E=96 (rank 16/32/64, K=7168) with a dense small-batch decode grid
(M = 1..8, 16, 24, 32, 48, 64) instead of just {16,32,64}. At small batch the
active-block count scales with M (grid is under-saturated, bs*top_k < E), so the
optimal split_k differs from the saturated regime: e.g. E=96/N=16 M=1 is 3.86us
@ split_k=7 vs 6.60us for the M=16 config it previously snapped to. Tuned
serially with seeded routing on NVIDIA B200.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@zcnrex

zcnrex commented Jun 1, 2026

Copy link
Copy Markdown
Owner Author

Superseded by upstream PR sgl-project#26899.

@zcnrex zcnrex closed this Jun 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation lora

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant