Skip to content

Commit 299531d

Browse files
committed
fix(path-c): gate redundant CUDA-prologue Simplify -> fused kernel compile 18min->13s
The fused mamba3 backward (b0) chain kernel cold-compiled in ~18-23 min on CUDA, stuck in arith RewriteSimplifier. Root cause (faulthandler-profiled): an ungated tilelang.transform.Simplify() in the CUDA backend prologue (tilelang backend cuda pipeline) that ignores the tl.fusion.disable_tir_simplify attr the rest of the engine honors via _maybe_simplify. Add _path_c_cuda_prologue_simplify_gate (path_c_fusion.py): a context manager wrapping _compile_tilelang_prim_func that, on the CUDA target when the prim_func carries tl.fusion.disable_tir_simplify, temporarily swaps the prologue Simplify for an identity pass -- exactly the skip the attr already requests elsewhere. No tilelang patching (travels in cppmega). Semantically neutral (Simplify is an optimization; skipping a pass the attr already disables cannot change results). gb10 sm_121: b0 cold compile (empty cache) 18-23min -> 13.06s (>100x); compile_ok, valid cooperative artifact. CUDA-target-gated -> Metal codegen byte-for-byte unchanged. Unblocks fast iteration + autotuning (configs were infeasible at 18min each).
1 parent 9781f64 commit 299531d

1 file changed

Lines changed: 92 additions & 15 deletions

File tree

cppmega_mlx/runtime/path_c_fusion.py

Lines changed: 92 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from __future__ import annotations
1010

11-
from contextlib import redirect_stderr, redirect_stdout
11+
from contextlib import contextmanager, redirect_stderr, redirect_stdout
1212
from dataclasses import asdict, dataclass, field, replace
1313
from enum import Enum
1414
from hashlib import sha256
@@ -2842,6 +2842,83 @@ def _single_entry_prim_func(func_or_mod: Any) -> Any:
28422842
return prim_func
28432843

28442844

2845+
def _path_c_prim_func_disables_tir_simplify(prim_func: Any) -> bool:
2846+
"""True iff ``prim_func`` carries ``tl.fusion.disable_tir_simplify``.
2847+
2848+
The descriptor scheduler sets this attr on every row-phased kernel (forward
2849+
and backward) to opt out of the heavy TVM arithmetic simplifier — its
2850+
deeply-nested per-lane strided guards make ``RewriteSimplifier::TryCompare``
2851+
blow up. TileLang's ``engine/phase.py`` already honours the attr in its
2852+
gated ``_maybe_simplify`` sites, but the CUDA backend pipeline prologue
2853+
(``tilelang/backend/cuda/pipeline.py``) calls a RAW, UNGATED
2854+
``tilelang.transform.Simplify()`` that ignores the attr. That ungated
2855+
Simplify is the entire ~18-23 min cold-compile blow-up of the fused mamba3
2856+
backward ``b0`` kernel (profiled: it is the single hot frame; bypassing it
2857+
lowers the kernel in ~10-13 s). See
2858+
``_path_c_cuda_prologue_simplify_gate``.
2859+
"""
2860+
2861+
for attrs in (
2862+
getattr(prim_func, "attrs", None),
2863+
None,
2864+
):
2865+
if attrs is None:
2866+
continue
2867+
try:
2868+
if bool(attrs.get("tl.fusion.disable_tir_simplify", False)):
2869+
return True
2870+
except Exception: # noqa: BLE001
2871+
try:
2872+
if bool(attrs["tl.fusion.disable_tir_simplify"]):
2873+
return True
2874+
except Exception: # noqa: BLE001
2875+
pass
2876+
return False
2877+
2878+
2879+
@contextmanager
2880+
def _path_c_cuda_prologue_simplify_gate(prim_func: Any, *, target: str) -> Any:
2881+
"""Honour ``tl.fusion.disable_tir_simplify`` for the UNGATED CUDA-prologue
2882+
``Simplify`` pass by temporarily replacing it with an identity pass.
2883+
2884+
TileLang's ``engine/phase.py`` skips ``Simplify`` for these kernels, but the
2885+
CUDA backend prologue (``backend/cuda/pipeline.py``) re-runs a raw
2886+
``tilelang.transform.Simplify()`` that does NOT consult the attr — and that
2887+
one pass is the whole multi-minute compile blow-up for the fused row-phased
2888+
mamba3 backward. When the kernel opts out of simplification AND we target
2889+
CUDA, we swap ``tilelang.transform.Simplify`` for an identity-returning pass
2890+
for the lifetime of this compile only, then restore it. This is exactly the
2891+
behaviour the ``disable_tir_simplify`` attr already requests everywhere else,
2892+
so it preserves the established (correctness-safe) lowering of this kernel
2893+
class — the kernel still lowers and runs identically, just without the
2894+
redundant, pathologically-slow simplifier sweep. A strict no-op on Metal /
2895+
any kernel that does not set the attr.
2896+
"""
2897+
2898+
if "cuda" not in str(target) or not _path_c_prim_func_disables_tir_simplify(
2899+
prim_func
2900+
):
2901+
yield
2902+
return
2903+
2904+
import tilelang.transform as _tl_transform
2905+
2906+
original_simplify = _tl_transform.Simplify
2907+
2908+
class _IdentityPass:
2909+
def __call__(self, mod: Any) -> Any:
2910+
return mod
2911+
2912+
def _identity_simplify(*_args: Any, **_kwargs: Any) -> Any:
2913+
return _IdentityPass()
2914+
2915+
_tl_transform.Simplify = _identity_simplify # type: ignore[assignment]
2916+
try:
2917+
yield
2918+
finally:
2919+
_tl_transform.Simplify = original_simplify # type: ignore[assignment]
2920+
2921+
28452922
def _compile_tilelang_prim_func(
28462923
prim_func: Any,
28472924
*,
@@ -2851,22 +2928,22 @@ def _compile_tilelang_prim_func(
28512928
) -> Any:
28522929
import tilelang
28532930

2854-
if not pass_configs:
2855-
return tilelang.compile(
2856-
prim_func,
2857-
target=target,
2858-
execution_backend=execution_backend,
2859-
)
2931+
with _path_c_cuda_prologue_simplify_gate(prim_func, target=target):
2932+
if not pass_configs:
2933+
return tilelang.compile(
2934+
prim_func,
2935+
target=target,
2936+
execution_backend=execution_backend,
2937+
)
28602938

2861-
from tilelang import tvm
2862-
2863-
with tvm.transform.PassContext(opt_level=3, config=dict(pass_configs)):
2864-
return tilelang.compile(
2865-
prim_func,
2866-
target=target,
2867-
execution_backend=execution_backend,
2868-
)
2939+
from tilelang import tvm
28692940

2941+
with tvm.transform.PassContext(opt_level=3, config=dict(pass_configs)):
2942+
return tilelang.compile(
2943+
prim_func,
2944+
target=target,
2945+
execution_backend=execution_backend,
2946+
)
28702947

28712948
def _tilelang_compile_plan_for(
28722949
region: PathCFusionRegion,

0 commit comments

Comments
 (0)