Skip to content

engine: notice when a tensor's format silently disables the fused Metal decode path - #827

Merged
JustVugg merged 3 commits into
JustVugg:devfrom
monotophic:kvb/fmt-gate-notice-r3
Aug 16, 2026
Merged

engine: notice when a tensor's format silently disables the fused Metal decode path#827
JustVugg merged 3 commits into
JustVugg:devfrom
monotophic:kvb/fmt-gate-notice-r3

Conversation

@monotophic

Copy link
Copy Markdown
Contributor

Authored by Fable 5 in Claude Code, analysis in partnership with @monotophic.

A container can mint any fused-bound tensor at a format the fused Metal decode
kernels don't accept β€” and today that silently pushes the affected layers'
decode attention onto the CPU path with no signal anywhere. We measured the
kv_b_proj case on an M5 Max at +22% end-to-end once cured. This PR makes the
condition visible at load, and makes it impossible for the diagnostic to drift
out of sync with the gates it describes:

  • One shared per-layer predicate (metal_fused_layer_fmt_miss, a pure
    bitmask over the 8 fused-bound tensor kinds) now backs BOTH fused-gate call
    sites (attention_rows, layer_forward_rows) and a new one-line-per-kind
    [METAL] stderr notice at model_init. Gate behavior is bit-identical β€”
    see the matrix below. The notice names the tensor kind, the offending fmt,
    the affected-layer count, the fmt 1/2/3/4 allowlist requirement (kv_b:
    fmt=2 exactly, with the --kvb-bits 4 remedy), and stays silent on clean
    containers and non-Metal builds. sh_* kinds count over the sparse-layer
    population (the only layers that load them); the MTP head is excluded by
    design (commonly INT8, never fused).
  • Notice-only: no gate or behavior change. The notice reports a FORMAT
    obstacle; it does not claim the fused path would otherwise engage (the
    gates' dims/batch/config preconditions are deliberately not duplicated).
  • docs/FORMATS.md gains a short "Format consumers" note recording these
    requirements with anchors to the predicate, both gates, and the notice.
Requirement Decisive evidence
Gates decide exactly as before Exhaustive equivalence sweep, all 86,093,442 fmtΓ—sparse configurations, old conditions vs shipped predicate: 0 mismatches (independently rebuilt twice; harness proven non-vacuous by seeded mutation)
Real-model behavior unchanged Old-vs-new binary on a real 358 GB GLM-5.2 int4 container, temp-0: generated text byte-identical, hit rates identical, zero notice lines (clean container)
Every notice behavior is pinned and the pins bite 10-part test (test_kvb_notice.c), incl. per-bit gate-mask membership; 7-mutation battery β€” every mutation caught, incl. a single mask bit dropped
No regressions make check green at every commit; METAL=1 build zero warnings vs baseline
Commit structure, verification detail, and observations

Commits by origin:

  1. 2078199 β€” the original kv_b-only notice, mechanically rebased onto
    current dev. Only resolution of note: the hand-maintained TEST_BINS
    addition was dropped β€” dev now auto-derives test binaries from build rules,
    which removes that whole conflict class.
  2. 988223d β€” the widening (all 8 fused-bound kinds) + the shared-predicate
    consolidation (replaces 11 scattered allowlist call sites with 7 inside one
    helper; the gates' comment blocks updated to match).
  3. 9fe7894 β€” review round: sh_* denominators (sparse-layer population),
    per-bit mask-membership test (a dropped mask bit previously passed the
    whole suite), mixed dense/sparse test shape, format-only semantics
    documented in the notice's comment.
  4. 353f5ea β€” the FORMATS.md consumer-requirements note.

Verification: the equivalence sweep enumerated fmt ∈ {0..8} per tensor Γ—
sparse ∈ {0,1} (all values outside {1,2,3,4} are one behavioral class, so the
domain covers every class with margin) and compared the old gate expressions,
transcribed verbatim from the base revision, against the shipped predicate at
-O3 and -O0. Compiler output at -O3 confirms the helper inlines into both
gates, the attention gate's masked-away sh_* reads are dead-code-eliminated,
and the remaining check vectorizes β€” it is not slower than the chain it
replaces. Dense layers never load sh_* tensors, so those kinds are checked on
sparse layers only (a literal all-layers check would false-positive on every
real GLM load). Test suite: kv_b miss Β· each allowlist kind Β· multi-kind
bounded output (≀8 lines) Β· all-pass silence Β· Metal-off silence Β· MTP
exclusion Β· dense-exemption Β· predicate truth table Β· mixed dense/sparse
counts Β· per-bit mask membership.

Observations for maintainers (nothing here is changed by this PR):

  • make metal-test does not compile on current dev in either
    COLI_METAL_RESSET state: quant.h:483 fp8_nblk (returns int64_t)
    collides with tests/test_backend_metal.mm:99's local static int fp8_nblk. Pre-exists this branch (verified at the untouched base). Happy
    to send the trivial fix separately.
  • The metal_fused_fmt_ok comment block said "fmt 1/2/4" while the predicate
    includes fmt==3; the consolidated comment now just names the allowlist.
  • attention_rows gained the (S<=4 || g_metal_prefill) prefill scope while
    layer_forward_rows did not β€” the two gates have diverged on batch scope
    (flagging only; format conditions are what this PR unifies).
  • If a future kernel binds a new tensor kind, the predicate, both masks, and
    the notice's kind arrays must move together β€” the per-bit membership test
    now enforces the mask half of that lockstep.

@michael-denyer

Copy link
Copy Markdown
Contributor

Second Apple datapoint for this, from the other side of the same wall.

I hit this exact path last week converting a GLM-5.2 REAP-504B container to fmt=6 on an M5
Pro. The routed experts were fmt=6, but the converter defaulted the dense and attention
tensors to grouped int4 (fmt=4), and with no fused Metal fmt=4 attention kernel (#587) the
whole attention path fell to the CPU with no signal. In a 147 s decode that was ~66 s of
attention on the CPU, and it looked like the format itself was slow. It was not. It was this
silent fallback.

Curing it (rebuilding the container per-row so dense matches, --group-size 0) is what let
the real fmt=6 number appear: +24% end-to-end vs int4 on the same box, warmed and quiet
(full run on #732). So your +22% on M5 Max and my +24% on M5 Pro are the same fix measured
on two machines.

The load-time notice would have saved me a full reconversion of diagnosis. Worth having.
One thing that composes with it: the trap has two ends, the engine (this PR, the fused gate)
and the converter (which mints the fmt in the first place). A matching one-line warning at
convert time, "these dense/attention tensors are fmt=4 and the Metal fused path needs fmt=2,
pass --group-size 0", would catch it before the container even exists.

@JustVugg JustVugg added enhancement New feature or request metal Backend Metal/Apple labels Aug 7, 2026
…e gates' predicate

The load-time format notice covered kv_b_proj only, and had already drifted
from the gates it describes: both fused Metal decode gates carry
(kv_b.fmt==2 || (kv_b.fmt==4 && !g_moe_exact)), but the notice tested
fmt!=2 && fmt!=4 -- so under COLI_METAL_MOE_EXACT=1 a grouped-int4 (fmt=4)
kv_b closed both gates while the notice stayed silent: exactly the silent
CPU-fallback trap the notice exists to kill.

Type the per-layer format condition ONCE, in a shared predicate:

- metal_fused_layer_fmt_miss(l) returns a bitmask (METAL_FUSED_*) of the
  8 fused-bound weight tensors whose format blocks the fused path: kv_b on
  the gates' own two-format+mode term, q_a/q_b/kv_a/o and (sparse layers
  only) sh_gate/sh_up/sh_down on the metal_fused_fmt_ok {1,2,3,4} allowlist.
- Both gates now consult it against the mask of tensors their kernel binds
  (METAL_FUSED_ATTN_TENSORS / METAL_FUSED_LAYER_TENSORS). No behavior
  change: the masked test is the same boolean the inline conditions computed.
- kvb_fmt_gate_notice becomes metal_fmt_gate_notice: one line per offending
  tensor KIND (bounded at 8 lines, never per layer), sh_* counted over the
  sparse-layer population, MTP head excluded, silent without Metal. Because
  the notice consumes the gates' predicate, the two cannot drift apart again.
- g_moe_exact moves next to g_metal_enabled, outside #ifdef COLI_METAL (the
  same hoist JustVugg#587 did for g_metal_enabled): the predicate compiles on every
  platform's test build; the env parse stays Metal-only, so the flag stays 0
  elsewhere, which is correct there.

test_kvb_notice.c grows to a superset of the previous scenarios: per-kind
misses, multi-kind bounded output, all-pass/Metal-off/MTP silences, dense
sh_* exemption, predicate truth table and per-bit gate-mask membership in
both g_moe_exact states, mixed dense/sparse denominators, and the new
MOE-exact cases (fmt=4 kv_b notices under the mode, stays silent outside
it). test_fp8_load.c Part F re-pins the source-text wiring at the new shape:
7 metal_fused_fmt_ok(l->...) sites (all inside the helper) plus both gates'
predicate consultation. docs/FORMATS.md gains the format-consumer note for
the fused Metal decode path with anchors at this tree.
…rdening

Review fixes on the widened fmt-gate notice:

- The kv_b line's remedy was circular under COLI_METAL_MOE_EXACT: the
  converter's --group-size defaults to 64, so the suggested --kvb-bits 4
  mints grouped int4 (fmt=4) -- exactly what the mode keeps off the fused
  path. The remedy clause is now selected on g_moe_exact: the plain
  suggestion outside the mode (unchanged), and under the mode the two real
  cures -- an ungrouped requant (--kvb-bits 4 --group-size 0 -> fmt=2) or,
  for a kv_b already at fmt=4, unsetting COLI_METAL_MOE_EXACT. Tests pin
  both variants (positive pins under the mode, a negative --group-size pin
  outside it).
- The notice header claimed the fused gates never see the MTP head; false --
  attention_rows evaluates the MTP row and its INT8 kv_b closes the gate
  there (carried, correct CPU fallback). Comment corrected to the actual
  rationale (main-layers-only by decision; a line about the INT8-by-design
  MTP head would be noise on every load). Comment-only: no gate change.
- New accepted-behavior test case: runtime-quant dense configs (qt_alloc
  fmt=0 at bits>=16, fmt=3 at 3-bit) produce bounded, accurate output --
  8 lines all naming fmt=0, and exactly one kv_b line at fmt=3 -- so the
  behavior is claimed and pinned rather than accidental.
- The test's stderr-capture seam now aborts loudly if dup/freopen fails
  instead of limping on with an undefined stderr.

FORMATS.md anchors recomputed for the shifted lines.
@monotophic
monotophic force-pushed the kvb/fmt-gate-notice-r3 branch from 353f5ea to 574aac1 Compare August 14, 2026 04:33
@monotophic

Copy link
Copy Markdown
Contributor Author

Authored by Fable 5 in Claude Code, analysis in partnership with @monotophic.

Rebased and re-derived onto current dev (base 1658b1f) β€” head is now 574aac1. Since #587's rebase already carried the narrow kv_b notice onto dev (thanks @RDouglasSharp for preserving authorship), this PR is now exactly the widening that dev still lacks, re-derived rather than merged. Changes sorted by origin:

1. Caused by dev moving. The kv_b gate condition on dev is now two formats with a mode term β€” fmt==2 || (fmt==4 && !g_moe_exact) β€” and the notice follows it exactly. The old Makefile hunk is dropped (dev auto-derives TEST_BINS now). docs/FORMATS.md line anchors recomputed. test_fp8_load.c Part F re-pinned (11 β†’ 7 predicate call sites after the refactor). Message text re-derived so the current test's retired-string pins keep passing.

2. A pre-existing defect, found during the re-derive β€” with run evidence. The narrow notice now on dev has already drifted from the gates it describes: its condition omits the !g_moe_exact term. Concretely β€” a user who sets COLI_METAL_MOE_EXACT=1 (choosing exactness) with a grouped-int4 (fmt=4) kv_b loses the fused path on every layer and gets no message about it, which is the silent fallback this notice exists to prevent. We demonstrated it on an untouched dev tree (loader-seam test: both gates report closed, notice emits zero bytes), then fixed it structurally: the format condition is now typed once, in a shared predicate that both gates and the notice consume. It cannot drift again, because there is no second copy to go stale.

3. The original widening. One per-layer format-miss bitmask covering kv_b plus the seven allowlist tensors (q_a, q_b, kv_a, o, sh_gate, sh_up, sh_down at fmt {1,2,3,4}; the sh_* trio checked on sparse layers only). Output is one line per offending tensor kind, at most 8 lines total, never per-layer spam. FORMAT-ONLY semantics stated in code (a line names a format obstacle; it does not claim the fused path would otherwise engage). Plus the FORMATS.md consumer note.

The four promises this change makes:

  1. Notice-only β€” zero behavior change outside stderr.
  2. The format condition exists in exactly one place.
  3. Every miss the gates act on is named, with accurate remedy text in both modes. (The old advice β€” "requantize with --kvb-bits 4" β€” was circular under MOE-exact: the converter's default --group-size 64 mints grouped int4, which is exactly what the mode keeps off the fused path. The message now says so instead of suggesting it.)
  4. Silent when Metal is off or all layers pass; MTP head excluded by design.

Capstone matrix β€” the single decisive check per promise, at 574aac1:

promise the check that would catch us
notice-only same prompt, old vs new binary, real 358 GB container, temp-0: generated text md5 identical, zero notice lines both arms, identical expert hit rate (run at the pre-rebase pair; carried across the final rebase because the replayed patch is content-identical and the intervening commits touch disjoint regions)
single-source condition Part F pins the predicate's 7 call sites + per-gate consultation; re-inlining any gate condition fails it
dev's drift defect is real loader-seam demo on untouched dev: gates closed + notice silent under MOE-exact + fmt=4
the new coverage has teeth 55 of the new test's assertions fail when run against dev's current code
mask integrity per-bit membership tests for both gate masks; dropping any single bit fails by name
bounded output mixed 61-layer and 2000-layer fixtures: ≀8 lines, each kind named exactly once
Full requirement β†’ instrument β†’ result matrix
  • Notice-only β†’ differential matrix (above) + logical-equivalence review of both gate rewrites β†’ pass
  • Sanitizers β†’ ASan+UBSan on both changed tests β†’ pass, zero reports
  • Single-source condition β†’ grep enumeration + Part F pins β†’ pass
  • kv_b mode term exact β†’ truth-table tests (fmt 2/4 Γ— mode on/off); dropping !g_moe_exact fails 10 assertions β†’ pass
  • Superset of dev's current test β†’ every dev scenario preserved, including its negative string pins β†’ pass
  • Per-kind coverage β†’ 7 single-kind fixtures + bounded multi-kind case β†’ pass
  • sh_* sparse-only, sparse denominators β†’ dense-exemption + denominator pins; inverting the exemption fails 27 assertions β†’ pass
  • Remedy accuracy in both modes β†’ exact-phrase pins mode-on and mode-off; collapsing the mode-aware text fails 2/1 assertions β†’ pass
  • Mechanical β†’ make check Β· METAL build zero warnings Β· metal-test both COLI_METAL_RESSET states Β· unused-function sweep Β· POSIX-clean tests β†’ all exit 0

Durable vs current-state. The shared-predicate architecture and the tests are durable. Calibrations, checkable at 574aac1 (macOS/Metal, 2026-08-13): the FORMATS.md line anchors; today's fused tensor set and format allowlist; the kv_b mode term mirroring #587's gates. If a future change adds a fused tensor kind or admits a new format, predicate + masks + notice arrays must move together β€” the per-bit tests enforce the mask half of that lockstep.

Observations, not changes (pre-existing, disclosed so they're on the record): backend_metal.mm parses COLI_METAL_MOE_EXACT separately with its own static β€” the same duplicated-condition shape one level down, a plausible follow-up; a near-duplicate mode term exists at the GEMM-eligibility check (c/colibri.c:913), outside this PR's scope, so our single-source claim is scoped to the fused gates + notice; the fused attention gate also evaluates the MTP head's tensors (its INT8 kv_b closes it β€” carried, correct CPU fallback); and runtime-quantized dense paths (fmt 0) produce accurate per-kind lines, now pinned as accepted behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request metal Backend Metal/Apple

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants