Skip to content

Commit 88aef5f

Browse files
committed
[KMCompiler][Test] Check an override against the reference, not the generic kernel
1 parent 40ede34 commit 88aef5f

1 file changed

Lines changed: 30 additions & 29 deletions

File tree

tests/test_fused_deepseek_v4_qnorm_rope_kv_rope_quant_insert.py

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -641,9 +641,23 @@ def test_combined_q_and_kv(num_tokens: int, n_heads: int, block_size: int):
641641
k_cache_compare(k_cache, k_cache_ref, block_size, rtol=1e-2, atol=1e-2)
642642

643643

644-
# ── Test 5: a backend override must not change results ───────────────────────
645-
# A vendor override is a performance change. It runs only where one is
644+
# ── Test 5: a backend override must still satisfy the contract ───────────────
645+
# A vendor override is a performance change, so it is worth checking on shapes
646+
# the tests above do not cover -- in particular ones that are not multiples of
647+
# whatever tiling the override uses. It runs only where an override is
646648
# registered, so nothing below executes on the generic path.
649+
#
650+
# It compares against the torch reference, not against the generic kernel. An
651+
# earlier version asserted the two Triton implementations agreed byte for byte,
652+
# which is stricter than anything the operator promises and is not even stable:
653+
# on Hygon BW1000 they are bit-identical under torch 2.10.0 / FlagTree
654+
# 0.6.1a1+hcu3.6, while under the combination backends.yaml pins for that card
655+
# (torch 2.9.0 / FlagTree 0.5.1+hcu3.1) q differs on 5 of 16744448 elements by up
656+
# to 2 bf16 ULP at 511 tokens and one FP8 cache byte differs at 1000 tokens. A
657+
# 2-D tile assigns lanes differently than a 1-D block, so `variance` rounds
658+
# differently and how that lowers depends on the compiler. The contract each
659+
# implementation owes is agreement with the reference, at the tolerances the
660+
# tests above use, and that is what this asserts.
647661
_OVERRIDE_ACTIVE = (
648662
flag_gems.fused_deepseek_v4_qnorm_rope_kv_rope_quant_insert is not _generic_impl
649663
)
@@ -661,7 +675,7 @@ def test_combined_q_and_kv(num_tokens: int, n_heads: int, block_size: int):
661675
)
662676
@pytest.mark.parametrize("n_heads", [64, 128])
663677
@pytest.mark.parametrize("block_size", [16, 64])
664-
def test_backend_override_matches_generic(
678+
def test_backend_override_matches_reference(
665679
num_tokens: int, n_heads: int, block_size: int
666680
):
667681
torch.manual_seed(3)
@@ -679,32 +693,19 @@ def test_backend_override_matches_generic(
679693
positions = torch.arange(num_tokens, dtype=torch.int64, device=device)
680694
cos_sin_cache = make_cos_sin_cache(max_pos, ROPE_DIM, torch.float32, device)
681695

682-
q_gen, k_cache_gen = q.clone(), k_cache.clone()
683-
_generic_impl(
684-
q_gen, kv, k_cache_gen, slot_mapping, positions, cos_sin_cache, eps, block_size
696+
q_ref, kv_ref = q.clone(), kv.clone()
697+
k_cache_ref = k_cache.clone()
698+
ref_impl_chunked(
699+
q_ref,
700+
kv_ref,
701+
k_cache_ref,
702+
slot_mapping.clone(),
703+
positions.clone(),
704+
cos_sin_cache.clone(),
705+
eps,
706+
block_size,
685707
)
686708
fused_impl(q, kv, k_cache, slot_mapping, positions, cos_sin_cache, eps, block_size)
687709

688-
# The cache is derived from kv through per-64-element reductions, identical
689-
# in any sane decomposition, so it must match byte for byte -- an override
690-
# that quantizes differently has changed behaviour.
691-
assert torch.equal(k_cache, k_cache_gen), (
692-
f"override wrote a different FP8 cache at num_tokens={num_tokens}, "
693-
f"n_heads={n_heads}, block_size={block_size}: "
694-
f"{int((k_cache != k_cache_gen).sum().item())} of {k_cache.numel()} "
695-
"bytes differ"
696-
)
697-
# q goes through a 512-element RMSNorm reduction whose tree may legitimately
698-
# differ between decompositions: a 2-D [TPP, 512] tile assigns lanes
699-
# differently than a 1-D 512 block, so `variance` rounds differently, and
700-
# that propagates through rsqrt into the stored bf16. Measured on a Hygon
701-
# BW1000 at num_tokens=511: 5 of 16744448 elements differ, by up to 2 bf16
702-
# ULP (7.8e-3 absolute, 7.8e-3 relative).
703-
#
704-
# The tolerance is the operator's own -- the same rtol/atol the accuracy
705-
# tests above use against the torch reference. Asserting that an override
706-
# tracks the generic kernel more closely than either tracks the reference
707-
# would be asserting something the operator never promised. (It is in fact
708-
# bit-identical on MetaX C550, but that is a property of one backend's lane
709-
# assignment, not a contract.)
710-
torch.testing.assert_close(q, q_gen, rtol=1e-2, atol=1e-2)
710+
k_cache_compare(k_cache, k_cache_ref, block_size, rtol=1e-2, atol=1e-2)
711+
assert_close_chunked(q, q_ref, rtol=1e-2, atol=1e-2)

0 commit comments

Comments
 (0)