Skip to content

Commit 53d639d

Browse files
committed
[SparseMLA] Propagate benchmark failures
Let compile and runtime exceptions propagate from table and single benchmarks in both forward and decode paths. Reserve skip/NaN behavior for optional providers that are genuinely unavailable, and reject non-finite measured timings.
1 parent 56a69a0 commit 53d639d

2 files changed

Lines changed: 128 additions & 22 deletions

File tree

python/test/regression/test_sparse_mla_autotune_configs.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import inspect
22
import importlib.util
3+
import math
34
from pathlib import Path
45

6+
import pytest
7+
58

69
def _load_sparse_mla_module():
710
path = (Path(__file__).resolve().parents[2] / "tutorials" / "tle" / "deepseek_v32" / "02-sparse-mla.py")
@@ -74,3 +77,78 @@ def test_sparse_mla_bench_seed_is_explicit_and_shared():
7477
assert inspect.signature(module.run_bench_table).parameters["seed"].default == module.BENCH_DEFAULT_SEED
7578
assert inspect.signature(module.bench_sparse_mla_fwd).parameters["seed"].default == module.BENCH_DEFAULT_SEED
7679
assert "seed" in inspect.signature(module.benchmark_sparse_mla_fwd.fn).parameters
80+
81+
82+
def _run_forward_benchmark_callback(module, provider):
83+
return module.benchmark_sparse_mla_fwd.fn(
84+
B=1,
85+
S=1,
86+
SKV=1,
87+
H=1,
88+
HKV=1,
89+
DQK=1,
90+
DV=1,
91+
topk=1,
92+
provider=provider,
93+
warmup=1,
94+
rep=1,
95+
tilelang_block_I=1,
96+
tilelang_num_stages=1,
97+
tilelang_threads=32,
98+
input_mode="flashmla",
99+
seed=1,
100+
)
101+
102+
103+
def _stub_forward_benchmark_inputs(monkeypatch, module):
104+
monkeypatch.setattr(module, "_get_bench_sparse_mla_inputs", lambda *args, **kwargs: (None, None, None, None))
105+
106+
107+
def _benchmark_failure(message):
108+
def fail(*args, **kwargs):
109+
raise RuntimeError(message)
110+
111+
return fail
112+
113+
114+
@pytest.mark.parametrize("provider", ["tle-flashmla-prefill", "tilelang"])
115+
def test_sparse_mla_benchmark_propagates_supported_provider_failure(monkeypatch, provider):
116+
module = _load_sparse_mla_module()
117+
_stub_forward_benchmark_inputs(monkeypatch, module)
118+
monkeypatch.setattr(module, "_HAVE_TILELANG", True)
119+
monkeypatch.setattr(module.triton.testing, "do_bench", _benchmark_failure("compile failed"))
120+
121+
with pytest.raises(RuntimeError, match="compile failed"):
122+
_run_forward_benchmark_callback(module, provider)
123+
124+
125+
def test_sparse_mla_benchmark_skips_unavailable_optional_provider(monkeypatch):
126+
module = _load_sparse_mla_module()
127+
_stub_forward_benchmark_inputs(monkeypatch, module)
128+
monkeypatch.setattr(module, "_HAVE_TILELANG", False)
129+
monkeypatch.setattr(module.triton.testing, "do_bench", _benchmark_failure("unavailable provider was executed"))
130+
131+
result = _run_forward_benchmark_callback(module, "tilelang")
132+
133+
assert all(math.isnan(value) for value in result)
134+
135+
136+
def test_sparse_mla_single_benchmark_propagates_provider_failure(monkeypatch):
137+
module = _load_sparse_mla_module()
138+
_stub_forward_benchmark_inputs(monkeypatch, module)
139+
monkeypatch.setattr(module, "triton_sparse_mla_fwd_interface", lambda *args, **kwargs: (None, None))
140+
monkeypatch.setattr(module, "tle_sparse_mla_fwd_interface", _benchmark_failure("TLE compile failed"))
141+
monkeypatch.setattr(module, "_bench_ms", lambda *args, **kwargs: 1.0)
142+
monkeypatch.setattr(module, "_sparse_mla_tflops_from_topk_length", lambda *args, **kwargs: 1.0)
143+
144+
with pytest.raises(RuntimeError, match="TLE compile failed"):
145+
module.bench_sparse_mla_fwd(B=1, S=1, SKV=1, H=1, HKV=1, DQK=1, DV=1, topk=1, check_outputs=False)
146+
147+
148+
def test_sparse_mla_benchmark_rejects_non_finite_timings(monkeypatch):
149+
module = _load_sparse_mla_module()
150+
_stub_forward_benchmark_inputs(monkeypatch, module)
151+
monkeypatch.setattr(module.triton.testing, "do_bench", lambda *args, **kwargs: (float("nan"), 1.0, 2.0))
152+
153+
with pytest.raises(RuntimeError, match="non-finite timings"):
154+
_run_forward_benchmark_callback(module, "triton")

python/tutorials/tle/deepseek_v32/02-sparse-mla.py

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@
2626
from tilelang import language as T
2727

2828
_HAVE_TILELANG = True
29-
except Exception: # pragma: no cover - optional dependency
29+
except ModuleNotFoundError as exc: # pragma: no cover - optional dependency
30+
if exc.name != "tilelang":
31+
raise
3032
tilelang = None
3133
T = None
3234
_HAVE_TILELANG = False
@@ -35,7 +37,9 @@
3537
import flash_mla
3638

3739
_HAVE_FLASHMLA = True
38-
except Exception: # pragma: no cover - optional dependency
40+
except ModuleNotFoundError as exc: # pragma: no cover - optional dependency
41+
if exc.name != "flash_mla":
42+
raise
3943
flash_mla = None
4044
_HAVE_FLASHMLA = False
4145

@@ -3103,7 +3107,10 @@ def _sparse_mla_tflops_from_topk_length(topk_length, H, DQK, DV, ms):
31033107

31043108
def _bench_ms(fn, warmup=BENCH_DEFAULT_WARMUP_MS, rep=BENCH_DEFAULT_REP_MS):
31053109
ms = triton.testing.do_bench(fn, warmup=warmup, rep=rep)
3106-
return float(ms if not isinstance(ms, tuple) else ms[0])
3110+
ms = float(ms if not isinstance(ms, tuple) else ms[0])
3111+
if not math.isfinite(ms):
3112+
raise RuntimeError(f"Benchmark returned a non-finite timing: {ms}")
3113+
return ms
31073114

31083115

31093116
_DECODE_BENCH_PROVIDERS = (["triton", "tle", "tle-pipe-pipelined"] +
@@ -3356,9 +3363,13 @@ def run():
33563363
)
33573364
except Exception as exc: # pragma: no cover - depends on runtime/resource limits
33583365
print(f"[bench:{provider}] failed for "
3359-
f"(B={B}, S={S}, SKV={SKV}, H={H}, HKV={HKV}, DQK={DQK}, DV={DV}, topk={topk}): {exc}")
3360-
return float("nan"), float("nan"), float("nan")
3361-
return ms, max_ms, min_ms
3366+
f"(B={B}, S={S}, SKV={SKV}, H={H}, HKV={HKV}, DQK={DQK}, DV={DV}, topk={topk}): {exc}",
3367+
flush=True)
3368+
raise
3369+
result = (ms, max_ms, min_ms)
3370+
if not all(math.isfinite(float(value)) for value in result):
3371+
raise RuntimeError(f"Benchmark provider {provider!r} returned non-finite timings: {result}")
3372+
return result
33623373

33633374

33643375
@triton.testing.perf_report(
@@ -3530,9 +3541,13 @@ def run():
35303541
)
35313542
except Exception as exc: # pragma: no cover - depends on runtime/resource limits
35323543
print(f"[decode-bench:{provider}] failed for "
3533-
f"(B={B}, S={S}, SKV={SKV}, H={H}, HKV={HKV}, DQK={DQK}, DV={DV}, topk={topk}): {exc}")
3534-
return float("nan"), float("nan"), float("nan")
3535-
return ms, max_ms, min_ms
3544+
f"(B={B}, S={S}, SKV={SKV}, H={H}, HKV={HKV}, DQK={DQK}, DV={DV}, topk={topk}): {exc}",
3545+
flush=True)
3546+
raise
3547+
result = (ms, max_ms, min_ms)
3548+
if not all(math.isfinite(float(value)) for value in result):
3549+
raise RuntimeError(f"Decode benchmark provider {provider!r} returned non-finite timings: {result}")
3550+
return result
35363551

35373552

35383553
def run_bench_table(warmup=BENCH_DEFAULT_WARMUP_MS, rep=BENCH_DEFAULT_REP_MS, show_plots=False, tilelang_block_I=64,
@@ -3987,7 +4002,8 @@ def run_tle():
39874002
tle_tflops = _sparse_mla_tflops_from_topk_length(topk_length, H, DQK, DV, tle_ms)
39884003
results.append(("tle", tle_ms, tle_tflops))
39894004
except Exception as exc: # pragma: no cover - depends on tle/runtime constraints
3990-
print(f"TLE bench skipped due to compile/runtime error: {exc}")
4005+
print(f"TLE bench failed due to compile/runtime error: {exc}", flush=True)
4006+
raise
39914007

39924008
def run_tle_pipe():
39934009
return tle_pipe_sparse_mla_fwd_interface(q, kv, indices, topk_length=topk_length, sm_scale=sm_scale, d_v=DV,
@@ -3999,7 +4015,8 @@ def run_tle_pipe():
39994015
tle_pipe_tflops = _sparse_mla_tflops_from_topk_length(topk_length, H, DQK, DV, tle_pipe_ms)
40004016
results.append(("tle-pipe-pipelined", tle_pipe_ms, tle_pipe_tflops))
40014017
except Exception as exc: # pragma: no cover - depends on tle/runtime constraints
4002-
print(f"TLE pipe-pipelined bench skipped due to compile/runtime error: {exc}")
4018+
print(f"TLE pipe-pipelined bench failed due to compile/runtime error: {exc}", flush=True)
4019+
raise
40034020

40044021
def run_tle_flashmla_prefill():
40054022
return tle_flashmla_prefill_interface(q, kv, indices, topk_length=topk_length, sm_scale=sm_scale, d_v=DV,
@@ -4012,7 +4029,8 @@ def run_tle_flashmla_prefill():
40124029
tle_flashmla_prefill_ms)
40134030
results.append(("tle-flashmla-prefill", tle_flashmla_prefill_ms, tle_flashmla_prefill_tflops))
40144031
except Exception as exc: # pragma: no cover - depends on tle/runtime constraints
4015-
print(f"TLE FlashMLA-prefill bench skipped due to compile/runtime error: {exc}")
4032+
print(f"TLE FlashMLA-prefill bench failed due to compile/runtime error: {exc}", flush=True)
4033+
raise
40164034

40174035
if _HAVE_TILELANG:
40184036
resolved_block_i = _resolve_tilelang_block_i(topk, tilelang_block_I)
@@ -4040,7 +4058,8 @@ def run_tilelang():
40404058
tilelang_tflops = _sparse_mla_tflops_from_topk_length(topk_length, H, DQK, DV, tilelang_ms)
40414059
results.append(("tilelang", tilelang_ms, tilelang_tflops))
40424060
except Exception as exc: # pragma: no cover - depends on tilelang/runtime constraints
4043-
print(f"TileLang bench skipped due to compile/runtime error: {exc}")
4061+
print(f"TileLang bench failed due to compile/runtime error: {exc}", flush=True)
4062+
raise
40444063
else:
40454064
print("TileLang is not installed, skip TileLang bench.")
40464065

@@ -4067,7 +4086,8 @@ def run_tilelang_pipelined():
40674086
tilelang_pipelined_ms)
40684087
results.append(("tilelang-pipelined", tilelang_pipelined_ms, tilelang_pipelined_tflops))
40694088
except Exception as exc: # pragma: no cover - depends on tilelang/runtime constraints
4070-
print(f"Pipelined TileLang bench skipped due to compile/runtime error: {exc}")
4089+
print(f"Pipelined TileLang bench failed due to compile/runtime error: {exc}", flush=True)
4090+
raise
40714091

40724092
def run_tilelang_seesaw():
40734093
return tilelang_sparse_mla_fwd_seesaw_interface(
@@ -4089,7 +4109,8 @@ def run_tilelang_seesaw():
40894109
tilelang_seesaw_tflops = _sparse_mla_tflops_from_topk_length(topk_length, H, DQK, DV, tilelang_seesaw_ms)
40904110
results.append(("tilelang-seesaw", tilelang_seesaw_ms, tilelang_seesaw_tflops))
40914111
except Exception as exc: # pragma: no cover - depends on tilelang/runtime constraints
4092-
print(f"Seesaw TileLang bench skipped due to compile/runtime error: {exc}")
4112+
print(f"Seesaw TileLang bench failed due to compile/runtime error: {exc}", flush=True)
4113+
raise
40934114

40944115
if _HAVE_FLASHMLA:
40954116
try:
@@ -4111,7 +4132,8 @@ def run_flashmla():
41114132
flashmla_tflops = _sparse_mla_tflops_from_topk_length(topk_length, H, DQK, DV, flashmla_ms)
41124133
results.append(("flashmla", flashmla_ms, flashmla_tflops))
41134134
except Exception as exc: # pragma: no cover - depends on flashmla/runtime constraints
4114-
print(f"FlashMLA bench skipped due to compile/runtime error: {exc}")
4135+
print(f"FlashMLA bench failed due to compile/runtime error: {exc}", flush=True)
4136+
raise
41154137
else:
41164138
print("FlashMLA is not installed, skip FlashMLA bench.")
41174139

@@ -4254,7 +4276,8 @@ def run_tle():
42544276
tle_tflops = _sparse_mla_tflops_from_topk_length(inputs["topk_length_flat"], H, DQK, DV, tle_ms)
42554277
results.append(("tle", tle_ms, tle_tflops))
42564278
except Exception as exc: # pragma: no cover - depends on tle/runtime constraints
4257-
print(f"TLE decode bench skipped due to compile/runtime error: {exc}")
4279+
print(f"TLE decode bench failed due to compile/runtime error: {exc}", flush=True)
4280+
raise
42584281

42594282
def run_tle_pipe():
42604283
return tle_pipe_sparse_mla_fwd_interface(
@@ -4274,7 +4297,8 @@ def run_tle_pipe():
42744297
tle_pipe_tflops = _sparse_mla_tflops_from_topk_length(inputs["topk_length_flat"], H, DQK, DV, tle_pipe_ms)
42754298
results.append(("tle-pipe-pipelined", tle_pipe_ms, tle_pipe_tflops))
42764299
except Exception as exc: # pragma: no cover - depends on tle/runtime constraints
4277-
print(f"TLE pipe-pipelined decode bench skipped due to compile/runtime error: {exc}")
4300+
print(f"TLE pipe-pipelined decode bench failed due to compile/runtime error: {exc}", flush=True)
4301+
raise
42784302

42794303
if _HAVE_TILELANG:
42804304
resolved_block_i = _resolve_tilelang_block_i(topk, tilelang_block_I)
@@ -4300,7 +4324,8 @@ def run_tilelang():
43004324
tilelang_tflops = _sparse_mla_tflops_from_topk_length(inputs["topk_length_flat"], H, DQK, DV, tilelang_ms)
43014325
results.append(("tilelang", tilelang_ms, tilelang_tflops))
43024326
except Exception as exc: # pragma: no cover - depends on tilelang/runtime constraints
4303-
print(f"TileLang decode bench skipped due to compile/runtime error: {exc}")
4327+
print(f"TileLang decode bench failed due to compile/runtime error: {exc}", flush=True)
4328+
raise
43044329

43054330
def run_tilelang_pipelined():
43064331
return tilelang_sparse_mla_fwd_pipelined_interface(
@@ -4324,7 +4349,8 @@ def run_tilelang_pipelined():
43244349
tilelang_pipelined_ms)
43254350
results.append(("tilelang-pipelined", tilelang_pipelined_ms, tilelang_pipelined_tflops))
43264351
except Exception as exc: # pragma: no cover - depends on tilelang/runtime constraints
4327-
print(f"Pipelined TileLang decode bench skipped due to compile/runtime error: {exc}")
4352+
print(f"Pipelined TileLang decode bench failed due to compile/runtime error: {exc}", flush=True)
4353+
raise
43284354

43294355
def run_tilelang_seesaw():
43304356
return tilelang_sparse_mla_fwd_seesaw_interface(
@@ -4348,7 +4374,8 @@ def run_tilelang_seesaw():
43484374
tilelang_seesaw_ms)
43494375
results.append(("tilelang-seesaw", tilelang_seesaw_ms, tilelang_seesaw_tflops))
43504376
except Exception as exc: # pragma: no cover - depends on tilelang/runtime constraints
4351-
print(f"Seesaw TileLang decode bench skipped due to compile/runtime error: {exc}")
4377+
print(f"Seesaw TileLang decode bench failed due to compile/runtime error: {exc}", flush=True)
4378+
raise
43524379
else:
43534380
print("TileLang is not installed, skip TileLang decode bench.")
43544381

@@ -4372,7 +4399,8 @@ def run_flashmla():
43724399
flashmla_tflops = _sparse_mla_tflops_from_topk_length(inputs["topk_length_flat"], H, DQK, DV, flashmla_ms)
43734400
results.append(("flashmla", flashmla_ms, flashmla_tflops))
43744401
except Exception as exc: # pragma: no cover - depends on flashmla/runtime constraints
4375-
print(f"FlashMLA decode bench skipped due to compile/runtime error: {exc}")
4402+
print(f"FlashMLA decode bench failed due to compile/runtime error: {exc}", flush=True)
4403+
raise
43764404
else:
43774405
print("FlashMLA is not installed, skip FlashMLA decode bench.")
43784406

0 commit comments

Comments
 (0)