moe_b12x_next.py 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800
  1. """Routed MoE through b12x main (package ``b12x_next``) instead of FlashInfer CUTLASS. Default OFF.
  2. Gate: ``DSV41_MOE_B12X_NEXT=1``. Purpose: EP_SIZE=1 at TP4 (every rank holds a 576-wide slice of all
  3. 384 routed experts), which FlashInfer's SM120 CUTLASS MXFP4 path cannot run (intermediate % 128, and
  4. ``block_scale_interleave`` pads 18 scale columns). The same adapter runs EP_SIZE=2 (N=1152) for A/B.
  5. Microbenchmark (diagnostics/dsv41-b12x-moe, 2026-09-24): per-rank MoE -8 % vs FI CUTLASS at equal
  6. experts; at EP1 the rank streams all ~17 experts of a c1 verify step at half width, so there is no
  7. EP-group straggler.
  8. What it patches (all refuse to boot if the engine symbol drifted):
  9. * ``Mxfp4FlashinferCutlassMoEMethod.create_weights``: the ``% 128`` check is lifted (576 needs
  10. ``% 64``); the checkpoint-layout tensors are created exactly as the stock method does
  11. (``Fp8MoEMethod.create_weights`` with E8M0 scales). The FusedMoE loader narrows w1/w3 rows by
  12. ``2304 // moe_tp_size`` and w2 columns / scales by the same factor, and with
  13. ``load_up_proj_weight_first`` stacks w13 as [w3 (up); w1 (gate)], which is b12x ``W13Layout.W13``
  14. (verified numerically against an fp32 reference built from the checkpoint slices).
  15. * ``...process_weights_after_loading``: no FlashInfer interleave; the checkpoint bytes are repacked
  16. in place into b12x W4A8 (MXFP4 weights, in-kernel MXFP8 activations) ``PreparedExperts``, one
  17. shared ``WeightPlan`` per geometry.
  18. * ``FusedOpPool[("none", "flashinfer_mxfp4")]``: replaced by ``_fused_b12x_next``. A layer that
  19. reaches it without having been converted refuses to run: the patched ``process_weights_after_loading``
  20. left its weights in checkpoint layout, which the stock FlashInfer kernel would read as garbage.
  21. Execution plans are per geometry (experts, K, N, top-k, EP rank, swiglu limit), prepared once at
  22. load on the first layer and shared by every layer of that geometry (the binding carries each layer's
  23. own prepared experts; see ``_Geometry._run``). Capacities: every exact decode/verify M of the CUDA
  24. graph list (verify rows B+1 and draft rows B per request, B = DSPARK_BLOCK_SIZE) plus a bounded
  25. ladder (128 .. max(4096, CHUNKED_PREFILL_SIZE)); a batch uses the smallest capacity >= M, larger
  26. batches run in chunks of the top capacity. A capacity above b12x's per-launch token limit for the
  27. geometry is dropped (warning), so the chunk is always a prepared capacity one launch can run.
  28. Scratch: one arena per geometry sized for the largest plan. EP: a Triton kernel maps global top-k
  29. ids to local ids in-graph; slots owned by another EP group and CUDA-graph padding ids (-1) get
  30. weight 0 and point at an expert the batch already reads.
  31. Autotune: the exact-M plans of the primary row count are raced at load (b12x PreparationSession),
  32. the rest use b12x's heuristic. Selections persist in ``$B12X_NEXT_COMPILE_CACHE_DIR/preparation``
  33. (default /state/b12x-next-compile), separate from the SG17 b12x cache RoCEnante uses. Tuning is
  34. rank-local (no collectives); ranks may pick different tactics, and every rank prepares the same set
  35. of plans, so the M -> plan mapping is rank-invariant. Race buffers are released after preparation.
  36. Knobs: DSV41_MOE_B12X_NEXT_TUNE (1), _TUNE_ROWS ("6:6,3:5" top-k:rows raced), _GRAPH_BS
  37. ("1,2,3,4,5,6,7,8,10,12,14,16"), _LADDER ("128,256,512,1024,2048,4096"), _CACHE_ONLY (0),
  38. _WARM (1: run every plan once at load), _DETERMINISTIC (0; EP1 only, b12x rejects it at N=1152;
  39. the <= 8 row plan then uses the internal route planner, the Triton one refuses deterministic output,
  40. and nothing is raced: b12x's race cannot compile the deterministic top-k sum kernel),
  41. _MEMSTATS (0: 1 logs load-time peak transients, resetting torch's peak counters),
  42. _SMALL_PLAN ("triton:48:16": route planner, max active clusters, tile rows of the dynamic plan pinned
  43. at <= 8 rows for compact N64), _PLAN_TABLE ("1-8=<_SMALL_PLAN>": per-capacity compact-N64 plans,
  44. ``lo-hi[@k<top-k>]=<planner>:<mac|none>:<tile>`` or ``=heur``, first match wins; replaces the whole
  45. table, unlisted capacities run b12x's heuristic), _M64_MIN_CAP (2048: compact-N64 ladder capacities >= this run the
  46. M64 tile; 0 = off; needs the runtime patch scripts/b12x_next-compact-n64-m64.patch, else M16 with a
  47. warning),
  48. _DIRECT_IDS (1: at EP_SIZE=1 the router's int32 ids / fp32 weights go straight to b12x, no remap
  49. kernel; b12x skips ids outside [0, E), so CUDA-graph padding rows (-1) contribute nothing and their
  50. output rows are 0. Off, or at EP>1, or with other dtypes / _DETERMINISTIC, the remap kernel runs).
  51. """
  52. import bisect
  53. import dataclasses
  54. import inspect
  55. import logging
  56. import os
  57. import sys
  58. import time
  59. import torch
  60. logger = logging.getLogger(__name__)
  61. ENABLED = os.environ.get("DSV41_MOE_B12X_NEXT", "0").strip() not in ("0", "", "off", "false")
  62. PINNED_COMMIT = "a7d7d29b2ef8869086e0ceaa787321f17544e3c9"
  63. _FUSED_KEY = ("none", "flashinfer_mxfp4")
  64. _TAG = "[moe_b12x_next]"
  65. def _env(name, default):
  66. return os.environ.get(name, default).strip()
  67. def _ints(text):
  68. return [int(v) for v in text.replace(" ", "").split(",") if v]
  69. TUNE = _env("DSV41_MOE_B12X_NEXT_TUNE", "1") not in ("0", "off", "false", "")
  70. CACHE_ONLY = _env("DSV41_MOE_B12X_NEXT_CACHE_ONLY", "0") not in ("0", "off", "false", "")
  71. WARM = _env("DSV41_MOE_B12X_NEXT_WARM", "1") not in ("0", "off", "false", "")
  72. # 1 = b12x's deterministic reduction (per-slot route buffer + top-k sum) instead of atomics: bit-stable
  73. # run to run; the atomic default differs by bf16 ulps between runs.
  74. DETERMINISTIC = _env("DSV41_MOE_B12X_NEXT_DETERMINISTIC", "0") not in ("0", "off", "false", "")
  75. # 1 = measure load-time peaks with torch's peak counters (resets them); off in serving by default.
  76. MEMSTATS = _env("DSV41_MOE_B12X_NEXT_MEMSTATS", "0") not in ("0", "off", "false", "")
  77. # 1 = EP1 skips the ep_remap launch (3 us/layer): b12x's dynamic/micro kernels and the triton route
  78. # planner all bounds-check expert ids, so -1 padding needs no rewrite (verified: numerics_noremap.py).
  79. DIRECT_IDS = _env("DSV41_MOE_B12X_NEXT_DIRECT_IDS", "1") not in ("0", "off", "false", "")
  80. def _peak_begin(dev):
  81. torch.cuda.synchronize(dev)
  82. base = torch.cuda.memory_allocated(dev)
  83. if MEMSTATS:
  84. torch.cuda.reset_peak_memory_stats(dev)
  85. return base
  86. def _peak_mb(dev, base):
  87. torch.cuda.synchronize(dev)
  88. return round((torch.cuda.max_memory_allocated(dev) - base) / 2**20, 1) if MEMSTATS else None
  89. GRAPH_BS = _ints(_env("DSV41_MOE_B12X_NEXT_GRAPH_BS", "1,2,3,4,5,6,7,8,10,12,14,16"))
  90. _MAX_BS = int(_env("CUDA_GRAPH_MAX_BS_DECODE", "16") or 16)
  91. GRAPH_BS = [b for b in GRAPH_BS if b <= _MAX_BS] or [1]
  92. BLOCK = int(_env("DSPARK_BLOCK_SIZE", "5") or 5)
  93. LADDER = _ints(_env("DSV41_MOE_B12X_NEXT_LADDER", "128,256,512,1024,2048,4096"))
  94. # Prefill capacities of the compact N64 geometry (EP1, N=576) on the M64 tile instead of b12x's M16 pin.
  95. M64_MIN_CAP = int(_env("DSV41_MOE_B12X_NEXT_M64_MIN_CAP", "2048") or 0)
  96. # Decode plan pinned for compact N64 at <= 8 rows: planner:max_active_clusters:tile_m (dynamic, grouped).
  97. _SMALL_SPEC = _env("DSV41_MOE_B12X_NEXT_SMALL_PLAN", "triton:48:16")
  98. _SMALL = _SMALL_SPEC.split(":")
  99. SMALL_PLANNER, SMALL_MAC, SMALL_TILE = _SMALL[0], (int(_SMALL[1]) if _SMALL[1] != "none" else None), int(_SMALL[2])
  100. if DETERMINISTIC and SMALL_PLANNER == "triton":
  101. # b12x's Triton route planner refuses deterministic compact queries (_tuning validation)
  102. SMALL_PLANNER = "internal"
  103. def parse_plan_table(text, deterministic):
  104. """``lo-hi[@k<top-k>]=<planner>:<mac|none>:<tile>`` or ``...=heur``, comma-separated; first match wins.
  105. Returns [(lo, hi, top-k or None, (planner, mac, tile) or None)]. ``heur`` = no override (b12x's
  106. heuristic plan). Under determinism a ``triton`` planner becomes ``internal`` (b12x refuses it)."""
  107. table = []
  108. for item in text.replace(" ", "").split(","):
  109. if not item:
  110. continue
  111. try:
  112. rng, spec = item.split("=")
  113. topk = None
  114. if "@k" in rng:
  115. rng, k = rng.split("@k")
  116. topk = int(k)
  117. lo, hi = (int(v) for v in rng.split("-")) if "-" in rng else (int(rng), int(rng))
  118. if spec == "heur":
  119. plan = None
  120. else:
  121. planner, mac, tile = spec.split(":")
  122. if planner not in ("internal", "triton"):
  123. raise ValueError(planner)
  124. if deterministic and planner == "triton":
  125. planner = "internal"
  126. plan = (planner, None if mac == "none" else int(mac), int(tile))
  127. except ValueError as exc:
  128. raise RuntimeError(f"DSV41_MOE_B12X_NEXT_PLAN_TABLE: bad entry {item!r} ({exc})") from exc
  129. if lo < 1 or hi < lo:
  130. raise RuntimeError(f"DSV41_MOE_B12X_NEXT_PLAN_TABLE: bad range in {item!r}")
  131. table.append((lo, hi, topk, plan))
  132. return table
  133. # Per-capacity decode plans of the compact N64 geometry (EP1, N=576). The default is the <= 8 row pin
  134. # above; every other capacity runs b12x's heuristic (dynamic, internal planner, mac none, M16, grouped).
  135. # Measured 2026-09-25 on the engine's path under determinism (diagnostics/dsv41-moe-plan-table): at
  136. # M = 10..96 (target top-6) and 10..80 (draft top-3) no max_active_clusters / tile choice beat the
  137. # heuristic beyond noise; every candidate was bit-identical to it; the calls run at the ~214 GB/s MoE
  138. # read ceiling, so the per-call cost is set by the distinct experts' bytes, not the plan.
  139. PLAN_TABLE = parse_plan_table(_env("DSV41_MOE_B12X_NEXT_PLAN_TABLE", f"1-8={_SMALL_SPEC}"), DETERMINISTIC)
  140. def table_plan(cap, topk):
  141. """(planner, mac, tile) pinned for this capacity / top-k, or None (b12x heuristic)."""
  142. for lo, hi, k, plan in PLAN_TABLE:
  143. if lo <= cap <= hi and (k is None or k == topk):
  144. return plan
  145. return None
  146. _CHUNK_ENV = int(_env("CHUNKED_PREFILL_SIZE", "0") or 0)
  147. if _CHUNK_ENV > max(LADDER):
  148. LADDER.append(_CHUNK_ENV)
  149. TUNE_ROWS = {int(k): int(v) for k, v in (p.split(":") for p in
  150. _env("DSV41_MOE_B12X_NEXT_TUNE_ROWS", "6:6,3:5").split(",") if p)}
  151. EXACT_MAX = 96 if not GRAPH_BS else max(96, (BLOCK + 1) * max(GRAPH_BS))
  152. _state = {"method_installed": False, "runner_installed": False, "orig_fused": None, "b12x_ready": False,
  153. "ep_logged": False}
  154. _LAYERS = {} # w13_weight.data_ptr() -> _LayerState
  155. _GEOMS = {} # geometry key -> _Geometry
  156. _SESSION = [None]
  157. _PREP_PEAK_MB = [] # per-layer peak transient of prepare_weights
  158. _B = {} # b12x_next modules, filled only by _b12x() after the pin/drift checks
  159. _ENG = {} # engine helpers of the fused function (install_runner)
  160. def _die(msg):
  161. raise RuntimeError(f"DSV41_MOE_B12X_NEXT: {msg} -- refusing to boot (unset DSV41_MOE_B12X_NEXT "
  162. f"to run the stock FlashInfer CUTLASS path)")
  163. # --------------------------------------------------------------------------------------------
  164. # b12x_next import and drift checks
  165. # --------------------------------------------------------------------------------------------
  166. def _b12x():
  167. if _state["b12x_ready"]:
  168. return _B
  169. if not os.environ.get("B12X_NEXT_COMPILE_CACHE_DIR"):
  170. state = os.environ.get("STATE_PATH", "/state")
  171. root = os.path.join(state, "b12x-next-compile")
  172. try:
  173. os.makedirs(root, exist_ok=True)
  174. os.environ["B12X_NEXT_COMPILE_CACHE_DIR"] = root
  175. except OSError:
  176. pass
  177. if os.environ.get("B12X_NEXT_COMPILE_CACHE_DIR") == os.environ.get("B12X_COMPILE_CACHE_DIR"):
  178. _die("B12X_NEXT_COMPILE_CACHE_DIR must differ from the SG17 B12X_COMPILE_CACHE_DIR")
  179. try:
  180. import b12x_next
  181. from b12x_next import preparation as prep
  182. from b12x_next.moe import fused_moe as fm
  183. from b12x_next.moe.fused_moe import _preparation as fprep
  184. from b12x_next.moe.fused_moe import api as fapi
  185. except Exception as exc:
  186. _die(f"cannot import b12x_next ({exc!r}); put runtime/b12x_next on PYTHONPATH")
  187. commit_file = os.path.join(os.path.dirname(b12x_next.__file__), "SOURCE_COMMIT")
  188. try:
  189. commit = open(commit_file).read().strip()
  190. except OSError:
  191. commit = "unknown"
  192. if commit != PINNED_COMMIT:
  193. _die(f"b12x_next is built from {commit}, the adapter is pinned to {PINNED_COMMIT}")
  194. src = inspect.getsource(fprep._FusedMoeState.bind)
  195. for needle in ('kwargs["experts"] = self.experts._impl', "self.scratch.bind(**kwargs)",
  196. "compact_launches=self.compact_launches", "unit_scale_contract",
  197. "_w4a16_launches"):
  198. if needle not in src:
  199. _die(f"b12x_next _FusedMoeState.bind drifted (missing {needle!r})")
  200. if "replace(state.bind(**kwargs), plan=plan)" not in inspect.getsource(fapi.bind):
  201. _die("b12x_next fused_moe.bind drifted")
  202. _B.update(fm=fm, prep=prep, pkg=b12x_next)
  203. _state["b12x_ready"] = True
  204. return _B
  205. # --------------------------------------------------------------------------------------------
  206. # EP remap kernel: global top-k ids -> local ids; foreign / padding slots -> weight 0 on an
  207. # expert the batch already reads (the row's lowest local expert, else the batch's lowest).
  208. # --------------------------------------------------------------------------------------------
  209. _REMAP = [None]
  210. def _remap_kernel():
  211. if _REMAP[0] is None:
  212. import triton
  213. import triton.language as tl
  214. # Input strides are runtime arguments (no specialization, so a strided view never JITs a
  215. # new variant inside graph capture); the outputs are contiguous [M, K].
  216. @triton.jit(do_not_specialize=["M", "OFFSET", "NUM_LOCAL", "SI0", "SI1", "SW0", "SW1"])
  217. def kernel(IDS, W, OUT_IDS, OUT_W, M, OFFSET, NUM_LOCAL, SI0, SI1, SW0, SW1,
  218. K: tl.constexpr, KP: tl.constexpr, BR: tl.constexpr):
  219. cols = tl.arange(0, KP)
  220. cmask = cols < K
  221. best = tl.full((), 2147483647, tl.int32)
  222. for r0 in range(0, M, BR):
  223. rows = r0 + tl.arange(0, BR)
  224. m = (rows[:, None] < M) & cmask[None, :]
  225. lid = tl.load(IDS + rows[:, None] * SI0 + cols[None, :] * SI1, mask=m, other=-1).to(tl.int32) - OFFSET
  226. ok = m & (lid >= 0) & (lid < NUM_LOCAL)
  227. best = tl.minimum(best, tl.min(tl.min(tl.where(ok, lid, 2147483647), axis=1), axis=0))
  228. fb = tl.where(best < NUM_LOCAL, best, 0)
  229. for r0 in range(0, M, BR):
  230. rows = r0 + tl.arange(0, BR)
  231. m = (rows[:, None] < M) & cmask[None, :]
  232. offs = rows[:, None] * K + cols[None, :]
  233. lid = tl.load(IDS + rows[:, None] * SI0 + cols[None, :] * SI1, mask=m, other=-1).to(tl.int32) - OFFSET
  234. w = tl.load(W + rows[:, None] * SW0 + cols[None, :] * SW1, mask=m, other=0.0).to(tl.float32)
  235. ok = m & (lid >= 0) & (lid < NUM_LOCAL)
  236. row_min = tl.min(tl.where(ok, lid, 2147483647), axis=1)
  237. fill = tl.where(row_min < NUM_LOCAL, row_min, fb)
  238. tl.store(OUT_IDS + offs, tl.where(ok, lid, fill[:, None]), mask=m)
  239. tl.store(OUT_W + offs, tl.where(ok, w, 0.0), mask=m)
  240. _REMAP[0] = (kernel, triton.next_power_of_2)
  241. return _REMAP[0]
  242. def ep_remap(topk_ids, topk_weights, out_ids, out_w, offset, num_local):
  243. """Writes out_ids (int32) / out_w (fp32), contiguous [M, K]; one CTA, no host sync, graph-capturable.
  244. ``topk_ids`` / ``topk_weights`` may be any strided [M, K] views (each read by its own strides)."""
  245. kernel, np2 = _remap_kernel()
  246. m, k = topk_ids.shape
  247. if m == 0:
  248. return
  249. if tuple(topk_weights.shape) != (m, k) or not (out_ids.is_contiguous() and out_w.is_contiguous()) \
  250. or out_ids.shape[0] < m or out_w.shape[0] < m:
  251. raise RuntimeError(f"DSV41_MOE_B12X_NEXT: ep_remap shapes ids {tuple(topk_ids.shape)} weights "
  252. f"{tuple(topk_weights.shape)} out {tuple(out_ids.shape)}/{tuple(out_w.shape)}")
  253. kernel[(1,)](topk_ids, topk_weights, out_ids, out_w, m, offset, num_local,
  254. topk_ids.stride(0), topk_ids.stride(1), topk_weights.stride(0), topk_weights.stride(1),
  255. K=k, KP=np2(k), BR=32, num_warps=4)
  256. def ep_remap_reference(topk_ids, topk_weights, offset, num_local):
  257. """torch version of ep_remap (tests)."""
  258. lid = topk_ids.to(torch.int64) - offset
  259. ok = (lid >= 0) & (lid < num_local)
  260. big = torch.full_like(lid, 2**31 - 1)
  261. best = torch.where(ok, lid, big).min()
  262. fb = best if int(best) < num_local else torch.zeros_like(best)
  263. row_min = torch.where(ok, lid, big).min(dim=1).values
  264. fill = torch.where(row_min < num_local, row_min, fb)
  265. ids = torch.where(ok, lid, fill[:, None].expand_as(lid)).to(torch.int32)
  266. w = torch.where(ok, topk_weights.float(), torch.zeros_like(topk_weights, dtype=torch.float32))
  267. return ids, w
  268. # --------------------------------------------------------------------------------------------
  269. # per-geometry plans
  270. # --------------------------------------------------------------------------------------------
  271. def _session():
  272. if _SESSION[0] is None:
  273. B = _b12x()
  274. _SESSION[0] = B["prep"].PreparationSession(
  275. device=torch.device("cuda", torch.cuda.current_device()), autotune=TUNE,
  276. compile_workers=0, cache_only=CACHE_ONLY)
  277. return _SESSION[0]
  278. @dataclasses.dataclass
  279. class _PlanEntry:
  280. cap: int
  281. plan: object
  282. state: object
  283. specs: tuple
  284. views: tuple = ()
  285. tuned: bool = False
  286. source: str = ""
  287. config: str = ""
  288. max_per_launch: int = 0
  289. class _Geometry:
  290. def __init__(self, key, num_experts, hidden, inter, topk, ep_rank, limit, device, ep_size=1):
  291. B = _b12x()
  292. fm = B["fm"]
  293. self.key = key
  294. self.E, self.K, self.N, self.topk = num_experts, hidden, inter, topk
  295. self.offset = ep_rank * num_experts
  296. self.direct = DIRECT_IDS and int(ep_size) == 1 and not DETERMINISTIC
  297. self.device = device
  298. self.limit = limit
  299. self.weight_plan = fm.plan_weights(
  300. source=fm.PackedSource(format=fm.PackedSourceFormat.MXFP4_E8M0_K32, w13_layout=fm.W13Layout.W13),
  301. activation=fm.ActivationSpec(mode=fm.ActivationMode.A8, nonlinearity="silu",
  302. io_dtype=torch.bfloat16, swiglu_limit=limit),
  303. geometry=fm.MoEGeometry(num_experts=num_experts, hidden_size=hidden, intermediate_size=inter))
  304. self.plans = {}
  305. self.caps = []
  306. self.table = []
  307. self.chunk = 0
  308. self.arena = None
  309. self.ids_buf = None
  310. self.w_buf = None
  311. self.ready = False
  312. self.report = {}
  313. def capacities(self):
  314. rows = sorted({r * b for r in (BLOCK, BLOCK + 1) for b in GRAPH_BS})
  315. exact = [m for m in rows if m <= EXACT_MAX]
  316. return sorted(set(exact) | {c for c in LADDER if c > max(exact)})
  317. def tuned_caps(self):
  318. # DETERMINISTIC: no race. b12x does not declare the deterministic top-k sum kernel among a
  319. # plan's programs, so its race refuses to compile it ("unplanned CuTe program"); the
  320. # heuristic plans compile it in _warm instead.
  321. if not TUNE or DETERMINISTIC:
  322. return set()
  323. r = TUNE_ROWS.get(self.topk)
  324. if r is None:
  325. return set()
  326. return {r * b for b in GRAPH_BS}
  327. def build(self, experts):
  328. """Prepare every capacity on the first layer's experts; allocate the shared arena."""
  329. B = _b12x()
  330. fm, prep = B["fm"], B["prep"]
  331. dev = self.device
  332. base = _peak_begin(dev)
  333. t0 = time.time()
  334. session = _session()
  335. tuned = self.tuned_caps()
  336. def noop(state):
  337. return prep.PreparedCall(run=lambda: None)
  338. for cap in self.capacities():
  339. routing = fm.RoutingSpec(deterministic_output=True) if DETERMINISTIC else None
  340. kw = {}
  341. pinned = table_plan(cap, self.topk) if self.N % 128 == 64 else None
  342. if pinned is not None:
  343. # <= 8 rows (default table): b12x's heuristic (and a race on uniform routing) picks the
  344. # `micro` plan, which streams one expert slice per (token, top-k slot): 36 at a c1
  345. # verify step, where `dynamic` streams each distinct expert once (~16 in real decode,
  346. # fewer with dead verify rows). Measured on the engine's path: 523 -> 349 us per call
  347. # at EP1, M=6. Other capacities: DSV41_MOE_B12X_NEXT_PLAN_TABLE.
  348. planner, mac, tile = pinned
  349. kw["override"] = fm.MoeDecodeConfig(
  350. backend="dynamic", route_planner=planner, max_active_clusters=mac,
  351. dynamic_tile_m=tile, dynamic_route_mode="grouped")
  352. elif M64_MIN_CAP and cap >= M64_MIN_CAP and cap > EXACT_MAX and self.N % 128 == 64 \
  353. and _m64_admitted():
  354. # b12x pins compact N64 to M16 tiles at every capacity: each 16-row tile re-stages the
  355. # expert's weight slice, 4x the M64 traffic. Prefill caps run M64 (runtime patch admits
  356. # it; M32 is wrong on n64 and stays rejected). Numerics equal the M16 path (rel-L2 vs
  357. # fp32 4.67 % both). Measured on the engine's path, EP1 N=576, per call, M16 -> M64:
  358. # 6 experts x M rows: -34 % at 2048, -28 % at 4096; spread routing -1 % / -4 %, but
  359. # +0.5..3 % at caps <= 1024, hence the 2048 floor.
  360. kw["override"] = fm.MoeDecodeConfig(
  361. backend="dynamic", route_planner="internal", max_active_clusters=None,
  362. dynamic_tile_m=64, dynamic_route_mode="grouped")
  363. plan = fm.plan_execution(experts=experts, routing=routing,
  364. capacity=fm.ExecutionCapacity(max_tokens=cap, top_k=self.topk), **kw)
  365. race = self._race_call(cap) if cap in tuned and not kw else None
  366. req = plan.request(name=f"dsv41-moe-E{self.E}-N{self.N}-k{self.topk}-M{cap}",
  367. prepare_call=noop, benchmark_call=race)
  368. session.prepare((req,), autotune=race is not None and TUNE)
  369. state = plan.prepared.state
  370. sel = plan.prepared.selection
  371. lp = state.scratch.launch_plan
  372. self.plans[cap] = _PlanEntry(
  373. cap=cap, plan=plan, state=state, specs=tuple(plan.scratch_specs()), tuned=race is not None,
  374. source=str(getattr(sel, "source", "")), config=str(getattr(sel, "config", "")),
  375. max_per_launch=int(getattr(lp, "max_tokens_per_launch", cap) or cap))
  376. self.chunk, self.caps, dropped = select_chunk({c: e.max_per_launch for c, e in self.plans.items()})
  377. if dropped:
  378. limit = min(self.plans[c].max_per_launch for c in dropped)
  379. print(f"{_TAG} WARNING: E={self.E} K={self.K} N={self.N} top-k {self.topk}: capacities {dropped} "
  380. f"exceed b12x's per-launch limit of {limit} tokens and are dropped; larger batches run in "
  381. f"chunks of {self.chunk} (set CHUNKED_PREFILL_SIZE <= {limit} to prepare a larger plan)",
  382. flush=True)
  383. for c in dropped:
  384. del self.plans[c]
  385. self.table = [None] + [self._lookup(m) for m in range(1, EXACT_MAX + 1)]
  386. # one arena per geometry, each plan's specs carved from its start (plans never overlap in time)
  387. need = max(sum(_align(s.nbytes) for s in self.plans[c].specs) for c in self.caps)
  388. self.arena = torch.empty(max(need, 256), dtype=torch.uint8, device=dev)
  389. for c in self.caps:
  390. off, views = 0, []
  391. for s in self.plans[c].specs:
  392. nb = s.nbytes
  393. views.append(self.arena[off:off + nb].view(s.dtype).view(tuple(s.shape)))
  394. off += _align(nb)
  395. self.plans[c].views = tuple(views)
  396. self.ids_buf = torch.empty(self.chunk, self.topk, dtype=torch.int32, device=dev)
  397. self.w_buf = torch.empty(self.chunk, self.topk, dtype=torch.float32, device=dev)
  398. self.ready = True
  399. t_prep = time.time() - t0
  400. if WARM:
  401. self._warm(experts)
  402. peak = _peak_mb(dev, base)
  403. torch.cuda.empty_cache()
  404. persistent = self.arena.numel() + self.ids_buf.numel() * 8
  405. self.report = {
  406. "geometry": dict(E=self.E, K=self.K, N=self.N, topk=self.topk, offset=self.offset),
  407. "capacities": self.caps, "chunk": self.chunk, "direct_ids": self.direct,
  408. "tuned": sorted(c for c in self.caps if self.plans[c].tuned),
  409. "sources": {c: self.plans[c].source for c in self.caps},
  410. "prepare_s": round(t_prep, 1), "total_s": round(time.time() - t0, 1),
  411. "peak_transient_mb": peak, "persistent_mb": round(persistent / 2**20, 1),
  412. }
  413. print(f"{_TAG} geometry ready {self.report}", flush=True)
  414. def _race_call(self, cap):
  415. B = _b12x()
  416. prep = B["prep"]
  417. dev, K, E, topk = self.device, self.K, self.E, self.topk
  418. def race(state):
  419. g = torch.Generator(device=dev)
  420. g.manual_seed(1234 + cap)
  421. sc = tuple(torch.empty(tuple(s.shape), dtype=s.dtype, device=dev) for s in state.scratch.scratch_specs())
  422. x = torch.randn(cap, K, device=dev, generator=g).to(torch.bfloat16)
  423. src = x.clone()
  424. ids = torch.rand(cap, E, device=dev, generator=g).argsort(dim=1)[:, :topk].to(torch.int32).contiguous()
  425. w = torch.softmax(torch.randn(cap, topk, device=dev, generator=g), dim=1).float()
  426. out = torch.empty(cap, K, dtype=torch.bfloat16, device=dev)
  427. b = state.bind(scratch=sc, a=x, topk_ids=ids, topk_weights=w, output=out)
  428. return prep.PreparedCall(run=lambda: state.run(b), output=out, produce=lambda: x.copy_(src),
  429. owners=(sc, x, src, ids, w, out, b))
  430. return race
  431. def _lookup(self, m):
  432. i = bisect.bisect_left(self.caps, m)
  433. return self.caps[i] if i < len(self.caps) else self.caps[-1]
  434. def cap_for(self, m):
  435. return self.table[m] if m <= EXACT_MAX else self._lookup(m)
  436. def _warm(self, experts):
  437. x = torch.zeros(self.chunk, self.K, dtype=torch.bfloat16, device=self.device)
  438. out = torch.empty_like(x)
  439. ids = torch.zeros(self.chunk, self.topk, dtype=torch.int32, device=self.device)
  440. w = torch.zeros(self.chunk, self.topk, dtype=torch.float32, device=self.device)
  441. for c in self.caps:
  442. m = min(c, self.chunk)
  443. self._run(c, x[:m], ids[:m], w[:m], out[:m], experts._impl)
  444. ep_remap(ids[:m], w[:m], self.ids_buf[:m], self.w_buf[:m], 0, self.E)
  445. torch.cuda.synchronize(self.device)
  446. del x, out, ids, w
  447. def _run(self, cap, x, ids, w, out, impl):
  448. if x.shape[0] > cap:
  449. raise RuntimeError(f"DSV41_MOE_B12X_NEXT: {x.shape[0]} rows on the capacity-{cap} plan "
  450. f"(chunk {self.chunk}, capacities {self.caps})")
  451. e = self.plans[cap]
  452. st = e.state
  453. kw = dict(scratch=e.views, a=x, topk_ids=ids, topk_weights=w, output=out,
  454. fast_math=st.scratch.caps.w4a16_fast_math, experts=impl, unit_scale_contract=False)
  455. if st.w4a16_launches is not None:
  456. kw["_w4a16_launches"] = st.w4a16_launches
  457. b = dataclasses.replace(st.scratch.bind(**kw), compact_launches=st.compact_launches, plan=e.plan)
  458. _B["fm"].run(binding=b)
  459. def forward(self, impl, x, topk_ids, topk_weights, out):
  460. m_all = x.shape[0]
  461. # EP1: every expert is local, the ids need no translation, and b12x ignores ids outside
  462. # [0, E) (padding -1). Row slices of the router's contiguous [M, top-k] buffers stay
  463. # contiguous. Any other dtype / layout takes the remap kernel (it also casts).
  464. direct = (self.direct and topk_ids.dtype == torch.int32 and topk_weights.dtype == torch.float32
  465. and topk_ids.is_contiguous() and topk_weights.is_contiguous())
  466. s = 0
  467. while s < m_all:
  468. e = min(m_all, s + self.chunk)
  469. m = e - s
  470. if direct:
  471. ids, w = topk_ids[s:e], topk_weights[s:e]
  472. else:
  473. ids = self.ids_buf[:m]
  474. w = self.w_buf[:m]
  475. ep_remap(topk_ids[s:e], topk_weights[s:e], ids, w, self.offset, self.E)
  476. self._run(self.cap_for(m), x[s:e], ids, w, out[s:e], impl)
  477. s = e
  478. return out
  479. def select_chunk(limits):
  480. """``limits``: {prepared capacity: that plan's max tokens per launch}.
  481. Returns ``(chunk, kept capacities, dropped capacities)``. A capacity is kept only if its plan
  482. runs it in one launch (capacity <= its launch limit), and the chunk is the largest kept one, so
  483. every chunk ``forward`` issues has a prepared plan whose scratch holds it.
  484. """
  485. kept = sorted(c for c, lim in limits.items() if c <= lim)
  486. if not kept:
  487. _die(f"no prepared capacity fits b12x's per-launch limit ({limits})")
  488. return kept[-1], kept, sorted(set(limits) - set(kept))
  489. _M64_STATE = []
  490. def _m64_admitted():
  491. """True when the b12x_next runtime carries the compact-N64 M64 admission patch."""
  492. if not _M64_STATE:
  493. try:
  494. from b12x_next.moe.fused_moe import _tuning
  495. ok = hasattr(_tuning, "_compact_n64_tiles") and 64 in _tuning._compact_n64_tiles(
  496. type("Q", (), {"num_tokens": 1 << 20})())
  497. except Exception: # noqa: BLE001
  498. ok = False
  499. if not ok:
  500. print(f"{_TAG} WARNING: b12x_next lacks the compact-N64 M64 patch; prefill stays on M16",
  501. flush=True)
  502. _M64_STATE.append(ok)
  503. return _M64_STATE[0]
  504. def _align(n, a=256):
  505. return (n + a - 1) // a * a
  506. @dataclasses.dataclass
  507. class _LayerState:
  508. geom: _Geometry
  509. experts: object # PreparedExperts (owns the repacked checkpoint storage)
  510. impl: object # experts._impl, what the binding consumes
  511. hidden: int
  512. # --------------------------------------------------------------------------------------------
  513. # engine hooks
  514. # --------------------------------------------------------------------------------------------
  515. def _check_loader():
  516. """The FusedMoE loader must narrow by moe_tp_size (576 at TP4/EP1) and stack [up; gate]."""
  517. mod = sys.modules.get("sglang.srt.layers.moe.fused_moe_triton.layer")
  518. if mod is None:
  519. import importlib
  520. mod = importlib.import_module("sglang.srt.layers.moe.fused_moe_triton.layer")
  521. w13 = inspect.getsource(mod.FusedMoE._load_w13)
  522. w2 = inspect.getsource(mod.FusedMoE._load_w2)
  523. for needle in ('getattr(self.quant_method, "load_up_proj_weight_first", False)',
  524. "loaded_weight.shape[shard_dim] // self.moe_tp_size", "start = shard_size"):
  525. if needle not in w13:
  526. _die(f"FusedMoE._load_w13 drifted (missing {needle!r})")
  527. if "loaded_weight.shape[shard_dim] // self.moe_tp_size" not in w2:
  528. _die("FusedMoE._load_w2 drifted")
  529. def install_method(module):
  530. """sglang.srt.layers.quantization.mxfp4_flashinfer_cutlass_moe"""
  531. if not ENABLED or _state["method_installed"]:
  532. return
  533. for other in ("DSV41_MOE_SM12X", "DSV41_MOE_PAD"):
  534. if _env(other, "0") not in ("0", "", "off", "false"):
  535. _die(f"{other} patches the same method; enable only one")
  536. cls = getattr(module, "Mxfp4FlashinferCutlassMoEMethod", None)
  537. if cls is None:
  538. _die("Mxfp4FlashinferCutlassMoEMethod is gone")
  539. for name in ("create_weights", "process_weights_after_loading", "create_moe_runner", "apply"):
  540. if not callable(getattr(cls, name, None)):
  541. _die(f"Mxfp4FlashinferCutlassMoEMethod.{name} is gone")
  542. cw = inspect.getsource(cls.create_weights)
  543. pw = inspect.getsource(cls.process_weights_after_loading)
  544. if "% 128" not in cw or "self._fp8.create_weights(" not in cw or "fp4_scale_dtype=torch.float8_e8m0fnu" not in cw:
  545. _die("Mxfp4FlashinferCutlassMoEMethod.create_weights drifted")
  546. if "block_scale_interleave" not in pw or "self._fp8.process_weights_after_loading(layer)" not in pw:
  547. _die("Mxfp4FlashinferCutlassMoEMethod.process_weights_after_loading drifted")
  548. if "fused_experts_none_to_flashinfer_mxfp4" not in inspect.getsource(module) and \
  549. "flashinfer_cutlass" not in inspect.getsource(cls.create_moe_runner):
  550. _die("create_moe_runner no longer builds the flashinfer_mxfp4 runner")
  551. _check_loader()
  552. _b12x() # import + pin/drift checks at boot, not at first use
  553. orig_process = cls.process_weights_after_loading
  554. def create_weights(self, layer, num_experts, hidden_size, intermediate_size_per_partition,
  555. params_dtype, **extra_weight_attrs):
  556. n = intermediate_size_per_partition
  557. if hidden_size % 128 != 0 or n % 64 != 0:
  558. raise ValueError(f"DSV41_MOE_B12X_NEXT: unsupported routed-expert shape hidden={hidden_size} "
  559. f"intermediate_per_partition={n} (needs hidden % 128 == 0, n % 64 == 0)")
  560. if not self.load_up_proj_weight_first:
  561. _die("load_up_proj_weight_first is no longer True; w13 layout would be [gate; up]")
  562. self._fp8.create_weights(layer, num_experts, hidden_size, n, params_dtype,
  563. fp4_scale_dtype=torch.float8_e8m0fnu, **extra_weight_attrs)
  564. def process_weights_after_loading(self, layer):
  565. self._fp8.process_weights_after_loading(layer)
  566. if getattr(layer, "_mega_moe_weights_built", False):
  567. return
  568. _convert_layer(self, layer)
  569. cls.create_weights = create_weights
  570. cls.process_weights_after_loading = process_weights_after_loading
  571. cls._dsv41_b12x_next_orig_process = orig_process
  572. _state["method_installed"] = True
  573. print(f"{_TAG} armed: routed MoE on b12x_next {PINNED_COMMIT[:8]} (W4A8, in-place repack); "
  574. f"graph bs {GRAPH_BS}, rows {BLOCK}/{BLOCK + 1}, ladder {LADDER}, tune={TUNE}", flush=True)
  575. if DETERMINISTIC:
  576. print(f"{_TAG} deterministic reduction: plan table {PLAN_TABLE} (triton planner -> internal), no "
  577. f"autotune race (heuristic plans elsewhere)", flush=True)
  578. rows = uncovered_rows()
  579. if rows:
  580. print(f"{_TAG} WARNING: CUDA_GRAPH_MAX_BS_DECODE={_MAX_BS} exceeds the adapter's graph bs list (max "
  581. f"{max(GRAPH_BS)}); decode/verify row counts {rows} (bs {max(GRAPH_BS) + 1}..{_MAX_BS} x "
  582. f"{BLOCK}/{BLOCK + 1}) have no exact plan and run on the next capacity up: correct, but slower. "
  583. f"Set DSV41_MOE_B12X_NEXT_GRAPH_BS to the engine's capture list to cover them.", flush=True)
  584. def uncovered_rows():
  585. """Draft/verify row counts of decode batch sizes above the adapter's graph list, up to
  586. CUDA_GRAPH_MAX_BS_DECODE, that have no exact-M plan (the engine's own capture list is not known
  587. here, so every batch size in that range is named)."""
  588. top = max(GRAPH_BS)
  589. if _MAX_BS <= top:
  590. return []
  591. exact = {r * b for r in (BLOCK, BLOCK + 1) for b in GRAPH_BS if r * b <= EXACT_MAX}
  592. return sorted({r * b for r in (BLOCK, BLOCK + 1) for b in range(top + 1, _MAX_BS + 1)} - exact)
  593. def _convert_layer(method, layer):
  594. B = _b12x()
  595. fm = B["fm"]
  596. w13, w2 = layer.w13_weight, layer.w2_weight
  597. s13, s2 = layer.w13_weight_scale_inv, layer.w2_weight_scale_inv
  598. for name, t in (("w13_weight_scale_inv", s13), ("w2_weight_scale_inv", s2)):
  599. if t.dtype != torch.float8_e8m0fnu:
  600. _die(f"{name} must stay native E8M0, got {t.dtype}")
  601. E, two_n, k_half = w13.shape
  602. n, k = two_n // 2, k_half * 2
  603. if tuple(w2.shape) != (E, k, n // 2) or tuple(s13.shape) != (E, two_n, k // 32) \
  604. or tuple(s2.shape) != (E, k, n // 32):
  605. _die(f"unexpected expert tensor shapes w13 {tuple(w13.shape)} w2 {tuple(w2.shape)} "
  606. f"s13 {tuple(s13.shape)} s2 {tuple(s2.shape)}")
  607. if int(getattr(layer, "num_fused_shared_experts", 0) or 0):
  608. _die("fused shared experts are not supported")
  609. for t in (w13, w2, s13, s2):
  610. if not t.is_contiguous():
  611. _die("expert tensors must be contiguous")
  612. cfg = method.moe_runner_config if hasattr(method, "moe_runner_config") else layer.moe_runner_config
  613. limit = getattr(cfg, "swiglu_limit", None)
  614. if getattr(cfg, "gemm1_clamp_limit", None) is not None or getattr(cfg, "gemm1_alpha", None) is not None:
  615. _die("gemm1 clamp/alpha variants are not supported")
  616. topk = int(layer.top_k)
  617. ep_rank, ep_size = int(layer.moe_ep_rank), int(layer.moe_ep_size)
  618. dev = w13.device
  619. key = (E, k, n, topk, ep_rank, ep_size, limit, dev.index)
  620. geom = _GEOMS.get(key)
  621. new_geom = geom is None
  622. if new_geom:
  623. geom = _Geometry(key, E, k, n, topk, ep_rank, limit, dev, ep_size=ep_size)
  624. _GEOMS[key] = geom
  625. if not _state["ep_logged"]:
  626. _state["ep_logged"] = True
  627. print(f"{_TAG} INFO: routed MoE at EP_SIZE={ep_size} (this rank: EP rank {ep_rank}, {E} experts x "
  628. f"N={n}){'' if ep_size == 1 else '; the production profile is EP_SIZE=1, EP>1 is an A/B setup'}",
  629. flush=True)
  630. base = _peak_begin(dev)
  631. ones = torch.ones(E, dtype=torch.float32, device=dev)
  632. ptrs = tuple(t.untyped_storage().data_ptr() for t in (w13, w2, s13, s2))
  633. experts = fm.prepare_weights(plan=geom.weight_plan, weights=fm.PackedWeights(
  634. w13=w13.data.view(torch.uint8), w2=w2.data.view(torch.uint8),
  635. w13_block_scales=s13.data.view(torch.uint8), w2_block_scales=s2.data.view(torch.uint8),
  636. w13_global_scales=ones, w2_global_scales=ones))
  637. try:
  638. rep = experts._impl.representation_for("w4a8_mx")
  639. now = tuple(t.untyped_storage().data_ptr() for t in (rep.w13_rp, rep.w2_rp, rep.w13_sfb, rep.w2_sfb))
  640. except Exception as exc: # noqa: BLE001
  641. _die(f"cannot inspect the prepared W4A8 representation ({exc!r})")
  642. peak = _peak_mb(dev, base)
  643. if now != ptrs:
  644. # a second allocation next to the checkpoint tensors would double the expert memory per rank
  645. _die(f"b12x_next did not repack E={E} K={k} N={n} in place")
  646. if peak is not None:
  647. _PREP_PEAK_MB.append(peak)
  648. if new_geom:
  649. geom.build(experts)
  650. st = _LayerState(geom=geom, experts=experts, impl=experts._impl, hidden=k)
  651. _LAYERS[w13.data_ptr()] = st
  652. layer._dsv4_mxfp4_backend = "b12x_next"
  653. layer._dsv41_b12x_next = st
  654. torch.cuda.empty_cache()
  655. if new_geom or len(_LAYERS) <= 1:
  656. print(f"{_TAG} layer ready E={E} K={k} N={n} topk={topk} ep={ep_rank}/{ep_size} "
  657. f"in_place=True prepare_peak_mb={peak}", flush=True)
  658. def install_runner(module):
  659. """sglang.srt.layers.moe.moe_runner.flashinfer_cutlass (after its fused funcs registered)."""
  660. if not ENABLED or _state["runner_installed"]:
  661. return
  662. _b12x() # pin/drift checks whichever hook runs first
  663. from sglang.srt.layers.moe.moe_runner.base import FusedOpPool
  664. orig = FusedOpPool._fused_funcs.get(_FUSED_KEY)
  665. if orig is None or getattr(orig, "__name__", "") != "fused_experts_none_to_flashinfer_mxfp4":
  666. _die(f"FusedOpPool{_FUSED_KEY} is {orig!r}, not the stock flashinfer_mxfp4 dispatcher")
  667. try:
  668. from sglang.srt.distributed import get_tp_group
  669. from sglang.srt.distributed.device_communicators.pynccl_allocator import use_symmetric_memory
  670. from sglang.srt.layers.dp_attention import is_allocation_symmetric
  671. from sglang.srt.layers.moe.token_dispatcher.standard import StandardCombineInput
  672. from sglang.srt.layers.moe.topk import TopKOutputChecker
  673. except Exception as exc:
  674. _die(f"engine helper import failed: {exc!r}")
  675. _ENG.update(get_tp_group=get_tp_group, use_symmetric_memory=use_symmetric_memory,
  676. is_allocation_symmetric=is_allocation_symmetric,
  677. StandardCombineInput=StandardCombineInput, TopKOutputChecker=TopKOutputChecker)
  678. _state["orig_fused"] = orig
  679. FusedOpPool._fused_funcs[_FUSED_KEY] = _fused_b12x_next
  680. _state["runner_installed"] = True
  681. print(f"{_TAG} FusedOpPool{_FUSED_KEY} -> b12x_next", flush=True)
  682. def _alloc_out(m, k, dev):
  683. # Same allocation as the stock path: the output feeds the TP all-reduce.
  684. if _ENG["is_allocation_symmetric"]():
  685. with _ENG["use_symmetric_memory"](_ENG["get_tp_group"]()):
  686. return torch.empty(m, k, dtype=torch.bfloat16, device=dev)
  687. return torch.empty(m, k, dtype=torch.bfloat16, device=dev)
  688. def _fused_b12x_next(dispatch_output, quant_info, runner_config):
  689. st = _LAYERS.get(quant_info.w13_weight.data_ptr())
  690. if st is None:
  691. # process_weights_after_loading is patched class-wide, so this layer's weights are in
  692. # checkpoint layout (not FlashInfer-interleaved): the stock kernel would return garbage.
  693. _die(f"a flashinfer_mxfp4 MoE layer reached the fused function without a b12x_next conversion "
  694. f"(w13 {tuple(quant_info.w13_weight.shape)}; e.g. _mega_moe_weights_built skipped it)")
  695. if getattr(quant_info, "padded_hidden", None) not in (None, st.hidden):
  696. raise RuntimeError("DSV41_MOE_B12X_NEXT: padded hidden size is not supported")
  697. x = dispatch_output.hidden_states
  698. topk = dispatch_output.topk_output
  699. if _ENG["TopKOutputChecker"].format_is_bypassed(topk):
  700. topk = topk.to_standard()
  701. out = _alloc_out(x.shape[0], x.shape[1], x.device)
  702. if x.shape[0]:
  703. st.geom.forward(st.impl, x, topk.topk_ids, topk.topk_weights, out)
  704. return _ENG["StandardCombineInput"](hidden_states=out)
  705. def geometry_reports():
  706. return {"geometries": [g.report for g in _GEOMS.values()], "layers": len(_LAYERS),
  707. "prepare_weights_peak_mb_max": max(_PREP_PEAK_MB, default=0.0)}