Skip to content

[Stacked on #957] perf(kimi3): MNNVL CuTe-DSL finalize tail + K3 comm layer extraction - #1062

Draft
dongjiyingdjy wants to merge 43 commits into
mainfrom
k3-mnnvl-cutedsl-tail
Draft

[Stacked on #957] perf(kimi3): MNNVL CuTe-DSL finalize tail + K3 comm layer extraction#1062
dongjiyingdjy wants to merge 43 commits into
mainfrom
k3-mnnvl-cutedsl-tail

Conversation

@dongjiyingdjy

Copy link
Copy Markdown
Contributor

Summary

Fuse the Kimi-K3 decode MoE tail — finalize (top-k weighted expert combine) + sum-AR + latent RMSNorm — into one collective launch via flashinfer's mnnvl_cutedsl backend (LL protocol), consuming the MoE kernel's deferred-finalize outputs. Extract the K3 communication layer (kimi_k3_comm.py) so all K3 comm sites (attention AR + MoE tail tiers) route through one negotiated module instead of inline branches in kimi_k3.py.

⚠️ Stacked on #957 — do not merge before it. This branch is based on perf/k3-latent-moe-multicast-tail; only the top 3 commits belong to this PR. Will rebase onto main once #957 merges.

Results (8xB300, TP8/EP8, decode bs=1, 6k ctx)

TPOT throughput
baseline (fused-lane tail) 11.31 ms 88.4 tok/s
this PR 10.79 ms (−4.5%) 92.7 tok/s
  • Tail critical path per layer: finalizeKernel (4.3µs) + lane one-shot AR (15.7µs) → mnnvl_cutedsl K1+K2 (5.6µs, nsys) with the shared-expert AR overlapped on the fork's aux stream.
  • Accuracy: AIME26 96.67%, GPQA-diamond 93.94% (reference level); long-generation sanity clean.
  • Also validated against the released nightly (0.6.18.dev20260811), including one autotuner API adaptation it requires.

Commits

  1. perf(kimi3): the fused tail (new K3MoETailTier.MNNVL_CUTEDSL, selector-routed, graph-phase gated, capacity from the workspace) + the kimi_k3_comm.py extraction (one MIN-vote per process instead of one per MoE layer; kimi_k3.py −429 lines; behavior-neutral moves verified by tier unit tests + nsys).
  2. build(deps): pin flashinfer to nightly-v0.6.18-20260811 (first build shipping mnnvl_cutedsl; merged upstream after the 0.6.17 tag) + adapt the CuTe-DSL GEMM tuning config to the 0.6.18 autotuner API. The tail is dormant behind a sentinel import on older flashinfer.
  3. build(deps): carry the K3 tactic tables forward to the nightly version key (tactics from the 0.6.16 sweep; decode validated unchanged, fresh sweep recommended before relying on prefill/large-M).

Review notes

  • EP-friendly: the fused tail negotiates on the tp_ep group (works under EP8 where tier-0 TAIL_FUSION is unavailable); TAIL_FUSION outranks it on pure-TP deployments.
  • Kill switch: TOKENSPEED_MNNVL_CUTEDSL_MOE_TAIL (default off); PDL follows the global pdl_enabled().
  • flashinfer upgrade impact audited: 89 imported symbols resolve, 6 signature changes (1 breaking, fixed here), AllReduceFusionPattern values unchanged (AOT trtllm_comm.so unaffected).

Test plan

  • test_k3_moe_tail_tier.py (20 cases incl. the new tier's priority/capacity/graph gates)
  • Serving smoke + TPOT A/B on 8xB300 (flag on/off), AIME26 + GPQA-diamond via evalscope
  • Follow-ups: tactic re-sweep on 0.6.18 cubins; BEAM-1M behavioral check for 1M-context

🤖 Generated with Claude Code

nperrin-fr and others added 30 commits August 5, 2026 00:48
Replace the fused-AR + replicated up-projection tail with three fused
stages inside the decode CUDA graphs: one kernel for the latent
all-reduce + RMSNorm + shared-expert reduce-scatter, a per-rank-sharded
up-projection (1/tp of the replicated weight traffic) whose epilogue
multicast-stores the shard into every rank's mailbox over NVLS, and a
barrier-free Lamport gather. Buffers come from stock PyTorch symmetric
memory; the CuTe-DSL kernels are vendored under thirdparty/cute_dsl/
(see the package header for provenance and license).

Engages only inside the CUDA-graph phase on plain TP8/TP16 (no EP),
SM100-family, bf16, hidden 7168 / latent 3584, and at most 16 tokens;
eager forwards and larger batches keep the existing fused-AR tail.
TOKENSPEED_K3_MULTICAST_TAIL=0 disables it.

Standalone (8x B300, graph replay): 8.15us vs ~18.6us per layer for the
current lamport-AR + replicated-gemv tail. bs1 decode TPOT: 10.53ms ->
9.96ms (95.0 -> 100.4 tok/s), stable P99 == median.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011oPfcso15ywRoX9NTbbycp
Signed-off-by: Nicolas <nperrin.ai@gmail.com>
Drop the enablement environment variable: the tail already has a full
eligibility chain (platform/TP/shape checks, a symmetric-memory multicast
probe, and a per-layer try/except fallback to the fused-AR tail), so the
switch added no selection power — optional knobs just rot unconfigured.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011oPfcso15ywRoX9NTbbycp
Signed-off-by: Nicolas <nperrin.ai@gmail.com>
…ather

Includes the symmetric cluster-barrier phase fix for the latent tail
collective; the stray fused-o_proj wiring from the original development
branch is not carried over.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
Signed-off-by: Nicolas <nperrin.ai@gmail.com>
The docs advertise the env fallback but the capability-only gating commit
dropped it; restore the operational switch and log engagement so serve
logs show which tail path is live.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
Signed-off-by: Nicolas <nperrin.ai@gmail.com>
Capability gating alone decides; the switch existed for the A/B run.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
Above 2048 tokens the fused-lane AR keeps the replicated up-projection,
whose GEMM dominates the tail. Instead each rank now up-projects only its
hidden shard into the shared partial (addmm_ beta-add), and the shared
all-reduce stitches the shards: same collective volume, 1/tp of the GEMM.
Threshold from the measured tp16 crossover. Real-weight tp16 A/B at 8192
input tokens: median TTFT 685 -> 654 ms (c1), 2546 -> 2425 ms (c4).

The MoE tail dispatch is folded into one _moe_tail method (fused decode
kernel, column-parallel, fused-lane AR, separate-reduce fallback).

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
Stage the routed/shared partials through cached symmetric-memory buffers
and reduce with NVLS multimem (ld_reduce) instead of ring NCCL, keeping
the column-parallel stitch. ld_reduce measures ~2x under NCCL at these
widths and stays flat down to tens of tokens, so the stitch now engages
everywhere above the decode range; the NCCL variant remains as the
no-multicast fallback. Real-weight tp16 A/B, median TTFT: 8192-token
prefill 632 -> 479 ms (c1) and 2300 -> 1749 ms (c4); 1024-token 340 -> 326 ms.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
…gence

Review findings: the stitch gate lacked a graph-phase exclusion, so decode
graphs with bs > 16 captured the multimem path and a later buffer growth
would free symmetric memory those graphs still reference; and per-rank
eligibility probing meant one failing rank could silently fall back while
its peers wait in the barrier. Eligibility is now agreed collectively at
init (min over ranks), the stitch is eager-only, replaced buffers are
retained for in-flight work, growth doubles, and buffers key on group.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
Covers NCCL parity at both sides of every runtime threshold (m=17..4096,
both tail widths), buffer growth/doubling with keep-alive retirement,
width-cache independence, staging refusals, and the view-invalidation
contract. 16 tests, torchrun world size 8/16 (job 8404: 16 passed).

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
The graph-phase exclusion is unnecessary now that replaced symmetric
buffers are retained: captured graphs keep a valid buffer forever, growth
is rank-lockstep, and a capacity miss during capture falls back uniformly.
Tiering by tokens keeps the dispatch a single-axis decision.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
Tier choice was smeared across forward-side booleans (use_tail, lane
enablement, skip_reduce, an inline norm+up-proj block) and an early-return
chain re-testing the same conditions. A K3MoETailTier enum plus a pure
selector in latent.py now decides once from named rank-uniform axes; every
tier is a method receiving raw partials, the shared stitch is one helper,
and the capture-time stage miss became an explicit re-selection instead of
a hidden fall-through. Selector behavior is pinned by a truth-table test.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
Review round 1: the latent-tail init kept the per-rank silent-fallback
divergence the multimem path had already fixed (now agreed via MIN
reduce, folded into the tier refactor); the multimem gate now refuses
attn-DP/CP and world-of-one configs; staging refuses widths that break
16-byte alignment and documents the rank-lockstep capacity contract; and
a capture/growth/replay test pins the retired-buffer safety claim that
justified tokens-only dispatch.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
…lticast-tail

# Conflicts:
#	python/tokenspeed/runtime/layers/moe/latent.py
#	python/tokenspeed/runtime/models/kimi_k3.py
GPQA isolates a real accuracy cost to the stitch itself: stitched trees
score 173-176 (multimem reduce) and 170 (NCCL reduce) against 180-184 for
main, while GSM8K is unaffected — the up-projection output is rounded to
bf16 before joining the 16-way reduction, and its magnitude dominates the
shared partials it sums with. The multimem tier now reduces both partials
in-switch and keeps the replicated norm+up_proj+add3 tail, numerically
congruent with the fused-lane path; the NCCL stitch tier is gone.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
The stitch removal left dead machinery: the capture-miss re-selection was
provably a constant (now a direct fused-lane call, making _moe_tail
non-reentrant), the multimem tier threaded a lane that is always None, and
the selector kept an unused hidden_size axis. Both AR tiers now share one
_projection_tail so their numeric congruence is structural. New guards:
MULTIMEM_AR is bounded to the measured 17..8192 window (larger batches take
the join's grouped path), the gate refuses width-colliding configs, and the
latent-tail gate matches the multimem gate's dp/cp rank-uniformity
conditions. Truth table extended; stale comments and docs refreshed.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
Buffer-capacity doubling is now clamped at the caller's dispatch ceiling
(ragged prefills could otherwise double past 8192 rows of multicast-mapped
memory per width); the latent-tail init agrees on the non-collective probe
before entering the constructor's rendezvous, closing the one-rank-strands-
peers window the MIN flag alone could not cover; the latent-tail
distributed test skips via a collectively-agreed probe like the multimem
one; and comment/docstring accuracy fixes (the width-collision guard is
correctness, not tuning; staging accepts strided input; direction of the
2x claim).

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
In full-file order the latent buffer was already at capacity when the
graph-replay test staged its growth trigger, so no retirement happened
and the retired-buffer replay was silently untested. The test now resets
its width symmetrically first and asserts the retirement occurred.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
A blind reviewer (no audit history in its prompt) caught what primed
confirmation rounds waved through: _multimem_tail_ok read as the fused
tail's gate (now _multimem_ar_ok, matching its tier); the TAIL_FUSION
dispatch comment claimed a determinism need the eager tests disprove (the
real invariant is tier stability across warmup/capture/replay); the docs
scoped the in-switch tier to no-EP although its gate deliberately admits
EP; a truth-table test was named for a capture-time miss it does not
model; and the max_rows docstring overstated the clamp. Also: an
init-time assert pins the fused-tail capacity below the multimem window,
and the eligibility gate is spelled via tp_ep_size like its sibling.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
The staging buffers are now pre-sized to the dispatch ceiling at init
(collective, lockstep), so serving-time growth — a rendezvous inside a
forward where one rank's allocation failure strands its peers — can no
longer occur, and the symmetric-memory footprint is fixed and visible to
memory planning. The vendored-kernel provenance note stops claiming
'unmodified' and enumerates the local deltas a re-sync must preserve; the
single-mailbox cleanup-ordering hazard inherited from upstream is
documented at the op; tests gain the skinny/dynamic dispatch boundary
(m=5,6) and the width-alignment refusal.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
The tier refactor moved SEPARATE_REDUCE's reduce/norm/up-projection out of
the stream-fork scope, silently serializing work that previously ran
concurrently with the shared-expert branch. The routed side now runs back
inside the fork (only for this tier — the others need raw partials for
their fused collectives), restoring the overlap.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
Verified A/B (per-arm module-path and engage-count self-checks, after a
harness bug had collapsed earlier cross-tree comparisons into one binary):
the fused decode tail holds +12-13% TPOT at c1-c16 and the in-switch
reduces hold -20% TTFT on 8192-token prefills against current main, but at
decode bucket sizes the two staged reduces lose ~4% TPOT to the single
fused-lane AR. The multimem floor moves to 256, above every decode-graph
bucket, which also keeps decode numerics on the main-congruent path.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
A blind review round against the 256-token floor: the latent-tail init
now dies loudly on a mid-constructor failure instead of falling back
locally (a non-uniform failure there strands peers in its collectives,
so the silent path was a hang in disguise); the spec-decode caveat on
the multimem window is documented (bs*q tokens can re-enter it in-graph
— correct but decode-suboptimal; a follow-up should add an is_decode
axis); multimem_prealloc's return now reflects buffer readiness; the
distributed M_VALUES straddle the real 256/8192 window edges; and
stale floor comments, tier shorthand, and the measured -20% TTFT figure
are reconciled. Runtime evidence from the round: both suites 26/26 at
world 8/16, ~20k serving requests across tier-boundary/abort/endurance
storms with zero errors and flat memory.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
A fp64-reference probe shows the fused tail carries a systematic negative
output bias absent from the unfused path (~-2e-5/layer floor, -9e-5 at
m=1 vs +-1e-5 unbiased), a plausible driver of the GPQA drop when the
decode tail dominates: directional error compounds over 61 layers where
random error averages out. The upstream-compatible bf16*bf16 norm square
contributes a third of it (Jensen: squaring rounded values overestimates
the variance, shrinking the output); fp32_internal also lowers the mean
relative error from 3.2e-3 to 2.7e-3. The remaining bias is the mailbox's
double rounding (store bf16, then residual add) — kernel follow-up.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
Brings in the MLA prefill PDL disable (#990), the AMD gfx950 MoE input
projections (#878), H200 Marlin SiTU support (#995), and the MLA 0.2.4 pin.

Conflicts and their resolution:
* layers/moe/latent.py — the K3MoETailTier enum/selector and main's new
  _marlin_moe_available() landed at the same spot; both kept.
* models/kimi_k3.py — #878 inserted methods where this branch initialises
  the tier-0 tail, which a textual merge strands inside
  _latent_input_projections after its return; the init block stays in
  __init__. The SiTU entry takes main's Marlin-aware guard but keeps this
  branch's contract: the selected tail tier owns the combining reduction,
  so no internal all-reduce and no skip_reduce parameter.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
The model mirrored plan fields under second names (use_trtllm_situ_moe,
use_marlin_situ_moe), so every reader had to know both vocabularies and the
H200 merge had to guard twice. One name per gate: the plan's own.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
nperrin-fr and others added 13 commits August 9, 2026 21:02
The try/except only logged and re-raised, which the scheduler already does
for anything that escapes construction. What the reader needs is why the
failure must not be caught at all — the constructor rendezvouses, so a rank
that dies inside it has already stranded its peers — so that is now the
comment. The window assert went with it: the selector tests TAIL_FUSION
before the multimem range, so an overlap would resolve there anyway.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
Eligibility for the two collective tiers was negotiated in six steps split
across the model and kernel layers — a kernel-internal all-reduce for
multimem, a collective prealloc, a local tail probe, a model all-reduce to
agree it, the tail's own rendezvous, and a second model all-reduce to agree
that. Each step was its own way for one rank to strand the others, which is
why each carried a warning comment.

Now both tiers vote locally, one MIN all-reduce agrees both votes, and only
then do the collective allocators run. The staging miss inside the multimem
tier is gone with it: its preconditions are exactly what the vote settled, so
a miss is a contract violation and says so instead of silently re-deciding
the tier that the selector already chose.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
The existing tier test only checks which tier the selector returns, and an
end-to-end eval only exercises the tiers its own shapes select — GPQA at ebs8
never reaches SEPARATE_REDUCE and the decode path never reaches MULTIMEM_AR,
so one of the four had no numerical coverage at all.

Each tier is compared against one fp32 reference, and the tiers are compared
against each other directly: a request's tier depends on batch size, so two
tiers individually inside tolerance but on opposite edges would show up to a
user as the same prompt answering differently under load.

Runs at world 4 (single node, skips the fused tail, which needs tp 8/16) and
at world 8/16 for full coverage: 9 passed at world 8.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
Two review findings from the PR.

The op cache keyed only on the tensor contract, which every MoE layer shares,
so all 61 layers received one mailbox. The gather releases its same-stream
dependents before it rewrites sentinels; inside a layer the next collective's
completion-scoped wait orders that against the following multicast write, but
across layers that edge runs through every kernel in between and nothing
guarantees it. A layer landing its shard in storage the previous layer is
still clearing corrupts the output or leaves the gather spinning. The key now
carries the layer index.

Both tiers also voted on local multicast support alone. On a cross-host group
without fabric or IMEX that reports available and then hangs inside the
symmetric-memory rendezvous rather than falling back, so each now clears
fabric_allocation_supported() when the job is wider than one host.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
All four latent-tail kernels hardcoded use_pdl=True at their launch sites, so
--disable-pdl (which exports TOKENSPEED_DISABLE_PDL) reached everything in the
model except them -- the operator had no kill-switch for exactly the launch
mechanism most likely to be implicated when a PDL bug is suspected.

The kernel package cannot import runtime modules, so the env var is the
channel. Read it once at import into PDL_ENABLED rather than per launch: PDL
is a process-wide launch property, and a per-launch lookup would have to
become part of every compile cache key. Disabling is always safe -- the
in-kernel griddepcontrol waits degenerate to no-ops and plain stream ordering
is strictly stronger.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
The equivalence suite re-derived norm+projection in torch for every tier, so
it agreed with itself no matter what routed_expert_norm,
kimi3_latent_projection_add3, kimi3_join_reduce_moe or the fused kernel's
epilogue actually computed -- production code was never on the path it was
supposed to be covering. The tiers now run through KimiLinearMoE's own
_tail_* methods on an instance built by __new__ with just the attributes
those methods read, which also adds the join tier (FUSED_LANE_AR), until now
untested, and a pure-Python check of the selector boundaries that needs no
GPU.

Three things fell out of putting real code under the test.

The fused tail keyed its mailbox on the layer index, but the NextN draft
layer is built with index 0 and would therefore have been handed base layer
0's mailbox -- the exact aliasing the per-layer key exists to prevent. The key
is now the module's weight prefix, which is unique across models.

The draft's "take the plain reduce path" intent had been inert since those
flags moved onto the execution plan: it wrote _fused_moe_ar on the module,
which nothing reads, so the draft kept using a lane workspace shaped around
the base model. It now updates the execution plan.

PDL_ENABLED could not be read at the launch sites after all -- CuTe's JIT
resolves names off self, not module globals -- so each kernel binds it in
__init__ instead. Fixes a NameError that only surfaced once the fused tail
actually compiled, which needs tp>=8.

Validated at world 8 (cn04-05): 13 passed, and 13 again under
TOKENSPEED_DISABLE_PDL=1. Max relative error against the fp32 reference,
by tier and token count: tail_fusion 4.9-5.9e-3, multimem_ar 4.4-6.7e-3,
fused_lane_ar 5.9-7.6e-3, separate_reduce 6.2-8.5e-3 -- so the collective's
bf16 accumulation in the three unfused tiers costs about 1e-3 against the
fused tail's fp32 one, not a correctness gap.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
Backs the behavioral half of the previous commit out of this branch and
leaves only the note. The draft's "take the plain reduce path" intent has
been dead since those flags moved onto the execution plan -- it writes
attribute names nothing reads -- but making it effective changes which tail
tier the draft selects, and nothing here can run speculative decode to check
that. Reinstating it belongs in its own change, validated against a spec
run, rather than riding along on a perf branch.

The aliasing risk that made this visible is already handled: the tail's
mailbox is keyed on the module prefix, so the draft cannot be handed base
layer 0's mailbox regardless of which tier it picks.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
The note still described the pre-fix world -- one process-wide mailbox whose
sentinel cleanup overlapped the next layer. Mailboxes are per caller now, so
the reason the PDL overlap is safe changed: reuse is a full forward apart and
no rank can drift that far, because every layer's gather blocks on its peers.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
TOKENSPEED_DISABLE_K3_LATENT_TAIL=1 makes latent_tail_supported report False,
so the tier selector sees capacity 0 and every size falls to the ordinary
tiers. The tail replaces the entire tail collective with a multicast mailbox
-- the branch's most invasive component -- and until now taking it out of the
picture meant editing code and rebuilding, which is no way to run an A/B or to
respond to a production suspicion.

Written as an eligibility failure rather than a later skip so that the whole
capability negotiation, allocation and tier map behave exactly as they do on
hardware that cannot run the tail at all -- a configuration already covered by
the tests.

Signed-off-by: Nicolas <nperrin.ai@gmail.com>
Add a decode MoE-tail tier that runs finalize + sum-AR + latent RMSNorm
in one collective launch (flashinfer's mnnvl_cutedsl backend, LL
protocol), consuming the MoE kernel's deferred-finalize outputs. Decode
TPOT 11.31ms -> 10.79ms (-4.5%) on 8xB300 TP8; AIME26 96.67 /
GPQA-diamond 93.94 (no accuracy change). Dormant on flashinfer builds
without the backend (sentinel import + capability vote); activates with
flashinfer > 0.6.17.

Extract kimi_k3_comm.py: the communication sites where K3's
AttnRes/latent-lane semantics bypass the generic CommManager now route
through K3AttnComm/K3MoeTailComm (per-group negotiated states, one
MIN-vote instead of one per MoE layer, tier table and thresholds in one
module). kimi_k3.py states semantics only; behavior unchanged
(same-kernel routing verified by nsys and tier unit tests).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: dongjiyingdjy <87510204+dongjiyingdjy@users.noreply.github.com>
…utedsl

The Kimi-K3 MNNVL CuTe-DSL MoE tail needs the mnnvl_cutedsl backend,
merged upstream 2026-08-11 after the 0.6.17 tag and first shipped in
nightly-v0.6.18-20260811. Direct wheel-URL pin; switch back to a plain
version pin once 0.6.18 is published.

Adapt the CuTe-DSL GEMM tuning config to the 0.6.18 autotuner API:
per-input initializers moved from DynamicTensorSpec's fifth argument to
TuningConfig.tensor_initializers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: dongjiyingdjy <87510204+dongjiyingdjy@users.noreply.github.com>
… key

The packaged MoE tactic tables are keyed by flashinfer version (filename
and embedded metadata), so the 0.6.18 nightly missed them all and fell
back to heuristic tactics. Clone the three B300 tables under the
nightly's key; the tactics themselves are carried over from the 0.6.16
sweep — decode validated unchanged, a fresh sweep on the 0.6.18 cubins
should follow before relying on prefill/large-M shapes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: dongjiyingdjy <87510204+dongjiyingdjy@users.noreply.github.com>
@nperrin-fr

Copy link
Copy Markdown
Collaborator

how about we merge to #957 first

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