Skip to content

dasLLAMA: the bf16 weight tile family, the float GELU, the threaded mel and the decode K/V split - #4366

Merged
borisbat merged 18 commits into
masterfrom
bbatkin/bf16-tower-gemm
Oct 25, 2026
Merged

borisbat merged 18 commits into
masterfrom
bbatkin/bf16-tower-gemm

Conversation

@borisbat

Copy link
Copy Markdown
Collaborator

Behavior change: a bf16 weight plane multiplies as bf16 times bf16 where a box stamps the new family - the activations rounded to bf16 into an AMX bf16 tile - so a tower or gemma-E projection served off a bf16 plane on such a box lands outputs within the bf16 envelope of the f32 walk's, not its bits. Elsewhere the bf16 plane takes the fp32 tile walk (the f32 walk's bits over the widened plane). The MoE router's prefill logits go back to the GEMV's bits (the row nest), so a prefill routes a token as decode would. The erf GELU, the qwen3a mel and the flash-decode unit order change no bits.

Why. After the fp32 tile the Xeon's Qwen3-ASR encode still spent 194 ms of 2924 in a double-precision GELU, its mel ran on one lane, and its bf16 planes (the gemma-E per-layer projection, the vision patch GEMMs) ran a dot-a-cell nest at 91 GFLOP/s where the tile walk reads 959 and the AMX unit 3740.

What changes.

  • gelu_erf is a tuned loop kernel on the float lattice: the NR erfc fit over exp4's polynomial, every op arithmetic, so it vectorizes.
  • matmul_bf16_batch takes the fp32 tile walk: matmul_batch_core and batch_tile_block are generic over the weight lattice, bf16_batch_tile widens each halfword by the exact shift; decode keeps the GEMV shaper.
  • bf16w_tile_gen (dasllama_math_gen.das): a [tune] family for the bf16-weight batch GEMM - bf16w_panel_build packs sixteen rows as the TMUL B layout, xbf16_build (now generic over its source) rounds the activations to bf16 once per call, the quant families' amx_bf16 emitter runs over them through the engine's bf16_walk, every tail takes the widen walk over the same rounded activations. matmul_bf16_batch_at reaches it through set_bf16_batch_gen; bf16w_batch_serves is the gate the test asks too. The family has a seat in all six class profiles (the Granite Rapids mint on x86-amx, the one candidate mr16 elsewhere) so daspkg release --fat ships it. The generator probe gates and races it; the tuner races gelu_erf and bf16_batch_tile.
  • log_mel_qwen3a splits its DFT GEMM on whole 4-row tiles and its mel fold over frames; the lanes' image is the one-lane image element for element (test_qwen3a_mel_lanes).
  • A flash-decode unit is one slice over every kv head, so each K/V row streams once; the partials are the old ones bit for bit.
  • The MoE router's prefill GEMM takes the row nest (mm_fblob_rows over matmul_batch_rows, the nest as its own entry under no knob): dasLLAMA: the fp32 batch GEMM tile, the Qwen3-ASR conv front across lanes, the Granite Rapids diagnosis #4365's fp32 tile had rounded the router's logits in its lanes, a near-tie top-k parted from decode's, and gemma-4-26B-A4B Q4_0's CPU counting walk fell off its pinned tokens from the fourth (test_parity under DASLLAMA_PARITY_FULL=1, red on master, green here). test_matmul_batch holds the entry to the per-token matmul bit for bit at the router's shape, the tile apart as the control.
  • test_prefill_fp32 (red on master since dasLLAMA: the fp32 batch GEMM tile, the Qwen3-ASR conv front across lanes, the Granite Rapids diagnosis #4365) pins the nest for its bit-exact cells, as the Q8 cell pins the portable backend, and holds the shipped tile's last-position logits within 1e-4 of Nx forward (measured 1e-5 on logits to 20), the two apart bit for bit as the control. The drafter's depth-knob cell (red on master) allows the last round the 32-token budget clips: 23 drafts over 8 rounds at depth 3.
  • harness/cpu_asr_race.das: the bf16 plane's routes, the GELU bodies, the mel lanes and the K-pass orders raced on _race_fixture, every compared arm held to a reference.
  • Docs: ARCHITECTURE_CPU_KERNELS.md#bf16-weight-tile-family, the lattice section, the math_gen and math charters, the hot-path coverage model (the qwen3a mel sanctioned uncovered), tests/CLAUDE.md; REVIEW_MEASUREMENT.md defines the board box, the release re-mint and the held entry and routes the changed-cell and re-minted-row rules to the re-mint (the rule pass ruled after dasLLAMA: the fp32 batch GEMM tile, the Qwen3-ASR conv front across lanes, the Granite Rapids diagnosis #4365, bundled here); the review round's self-review batches on nine more checklists.
  • Ledger: the 2026-10-25 entry; row 240 rewritten to the measured state (the conv weights are F16, the family has only its AMX leg), row 242 new (the ASR decoder's K/V codec on CPU).

Observable behavior (debug-jit, direction-grade; PERF_LEDGER.md's 2026-10-25 entry has every command).

  • Qwen3-ASR gb1 encode on the Xeon: 2924 -> 2451 ms at the GELU and bf16-walk commits; enc.ffn.gelu 194 -> 41 ms.
  • The bf16 plane at the E4B projection's pp512 shape on the Xeon: 91 (the nest) -> 959 (the walk) -> 3740 GFLOP/s (the AMX family); gemma-4-E4B Q8_0 pp512 284.7 (cv 6.4 %) -> 359.8 -> 368.8 tok/s, the frozen fixture's opening tokens matching on all three.
  • The author's board boxes - m5, gnr, epyc9r14, graviton4 - re-ran the Qwen3-ASR CPU cell with their rig exes (das / llama-mtmd-cli, total / encode ms): gnr 13807 / 2007 against 20857 / 7481 (was 15797 / 2917), epyc9r14 11694 / 2499 against 15916 / 8009 (was 12784 / 3071), graviton4 8406 / 2462 against 67900 / 64309 (was 9209 / 3168), m5 8675 / 2475 against 46465 / 42396 (the release-17 board 13092 / 6460). The gemma-4-E4B CPU rows on gnr (pp512 375 +/- 25, void; tg128 17.9) and the m5 (pp512 207.1, tg128 53.1, image-chat encode 420 ms - against the board's 375, a gap master already carries: 427 ms under the -jit script at 2d7d99f). The rows stay in the ledger; rows 240 and 242 own the release re-mint.
  • Decode: 11.1 s over 451 steps under f16 K/V, attn_chain 8.8 s of it; the unit reorder leaves it within noise. Under the q8_0 K/V codec 6.3 s - row 242 asks for the ruling.
  • The seam g_bf16_batch_gen is armed by dasllama_math_gen's [init] in every context; no forked context calls matmul_bf16_batch with ntok > 1 (the callers are the PLE projection and the tower's mm_bf16_b, both on the serving thread).

Where to look. bf16w_batch and bf16w_walk in dasllama_math_gen.das with ARCHITECTURE_CPU_KERNELS.md#bf16-weight-tile-family; gelu_erf_template, batch_tile_block and matmul_batch_rows in dasllama_math.das; log_mel_qwen3a in dasllama_qwen3a.das; the stage-2 unit in attention_chain_decode (dasllama_blocks.das); harness/cpu_asr_race.das.

Validation, races, claims, ledger

Validation (every run -jit, no --exclude)

  • M5: model-free suite 92 files, the five known reds (test_facade_docs red on master, the four Vulkan files - Vulkan is off on this Mac); --area audio 11 files, test_vulkan_tower_kernels the one red; --suite image --arm gemma4a and --arm qwen3a 0 failed after the word-wise compare; --area tts 17 files 0 failed; --suite image --arm mtower 52 of 52; --suite decode --arm arm11 passed; --area llm under DASLLAMA_PARITY_FULL=1 (the gpt-oss fused-chain cell the flash-decode reorder reaches): 142 files, 7 red - the four Vulkan-device files (test_vulkan_dec_tail, test_vulkan_kernels, test_vulkan_tier, test_gpu_slot_swap: Vulkan is off on this Mac), test_parity killed (exit 137) loading the 89 GB Flash-Next split image after 31 large-tier cells had passed (the spec rows after it did not run on this box), and the three master reds above - the gemma-4-26B Q4_0 cell, test_prefill_fp32, the drafter's depth knob - each reproduced with origin/master's engine files on this binary, bisected to dasLLAMA: the fp32 batch GEMM tile, the Qwen3-ASR conv front across lanes, the Granite Rapids diagnosis #4365's tile commit (the drafter's predates both legs), and green after the fix: the 26B cell counts 24..33, test_mtp_gemma_drafter 38/38, test_prefill 6/6; test_matmul_batch 18/18 (the bf16 cells' oracle rounds its activations where bf16w_batch_serves; the nest entry at the router's shape), test_parity's small tier 46 passed 43 skipped on the fixed engine, test_fused_decode 13 passed 1 skipped, test_qwen3a_mel_lanes, the GELU cells of test_tower_asr_kernels and test_audio, test_qwen3a_tower; the generator probe DAS_TUNE_MODE=test OK on the M5 (the AMX rows decline) and on gnr (every row ok under the bf16 envelope); the AMX-bf16 rows of test_matmul_batch and the probe ran on gnr (x86-amx class, Granite Rapids).
  • Negative controls: the mel cell reds under a row-wise GEMM split (the reason for the 4-row lattice); the bf16 cells' poisoned expectation; the family's test on gnr failed under close_tol's absolute floor before the envelope bar; the transcript cells' one-word-short control.
  • Fat exe (daspkg release --fat arm-i8mm from this tree, the 1B Q8_0 at -r 2): sanity: frozen fixture - 8/8 opening tokens match ", in a small village nestled in the"; sanity (tg128): warmup argmax 315 " of" (logit 7.824408); the run printed no tune gate: line.
  • Preflight (make-pr): sync clean against origin/master, stamp-reach clean (the M5 sidecar archive the ledger commit had carried is dropped - records/ stays as the release left it), jit-smoke skipped (no JIT surface); preflight --full 21 passed, 4 skipped, 1 red: docs/sphinx-html, the box's PATH sphinx-build (homebrew Sphinx 9.2 without sphinx_sitemap); the control, ~/Library/Python/3.11/bin/sphinx-build -W -q -b html doc/source, exits 0 on this tree.
  • Codex round: one on the diff before the review round, no findings.
  • Review round: dragon x2 on REVIEW_MEASUREMENT.md, tdd, dupe, and the module, tests, measurement, gates, hot-path, memory, placement, benchmarks, audio, vision, kq-formats, docs and upstream checklists - every finding folded; the structural rule splits each auditor proposed are left for a rule-doc round.

The race lines (harness/cpu_asr_race.das -- --arm all --reps 5 at cbfe4d6, -jit -no-module-cache, the box's rig sidecar as DAS_TUNE_MANIFEST, one process a box, the GELU arm a second run)

gnr (Granite Rapids, 8 cores)
bf16 n=2560 d=10752 ntok=512 f32 plane, the tile walk: 35.515 ms (793.6287023621715 GFLOP/s; median 35.544 ms, cv 0.094024114) within 0.00023726377 of the double dot on 512 sampled elements (largest difference 6.67572e-06)
bf16 n=2560 d=10752 ntok=512 bf16 plane, the stamped family: 7.537 ms (3739.6473675886614 GFLOP/s; median 7.711 ms, cv 1.3087463) within 0.23726377 of the double dot on 512 sampled elements (largest difference 0.03965491)
bf16 n=2560 d=10752 ntok=512 bf16 plane, the widen walk: 29.398 ms (958.7632557456421 GFLOP/s; median 29.663 ms, cv 0.4044041) within 0.00023726377 of the double dot on 512 sampled elements (largest difference 6.67572e-06)
bf16 n=2560 d=10752 ntok=512 bf16 plane, the row nest: 309.489 ms (91.07180428020924 GFLOP/s; median 309.534 ms, cv 0.021532) within 0.00023726377 of the double dot on 512 sampled elements (largest difference 5.722046e-06)
bf16 n=4320 d=480 ntok=800 f32 plane, the tile walk: 3.276 ms (1012.7472456715676 GFLOP/s; median 3.354 ms, cv 1.6733203) within 0.00033061218 of the double dot on 512 sampled elements (largest difference 1.04904175e-05)
bf16 n=4320 d=480 ntok=800 bf16 plane, the stamped family: 1.593 ms (2082.711793336448 GFLOP/s; median 1.697 ms, cv 2.846108) within 0.33061218 of the double dot on 512 sampled elements (largest difference 0.042419195)
bf16 n=4320 d=480 ntok=800 bf16 plane, the widen walk: 3.386 ms (979.8464501958293 GFLOP/s; median 3.436 ms, cv 1.032394) within 0.00033061218 of the double dot on 512 sampled elements (largest difference 1.04904175e-05)
bf16 n=4320 d=480 ntok=800 bf16 plane, the row nest: 37.048 ms (89.55301149691344 GFLOP/s; median 37.127 ms, cv 0.16585337) within 0.00033061218 of the double dot on 512 sampled elements (largest difference 7.6293945e-06)
bf16 n=1152 d=1152 ntok=256 f32 plane, the tile walk: 0.652 ms (1042.143002399413 GFLOP/s; median 0.655 ms, cv 1.0172166) within 0.00015252455 of the double dot on 512 sampled elements (largest difference 2.3841858e-06)
bf16 n=1152 d=1152 ntok=256 bf16 plane, the stamped family: 0.235 ms (2891.3925520144862 GFLOP/s; median 0.24 ms, cv 1.9184765) within 0.15252456 of the double dot on 512 sampled elements (largest difference 0.025390625)
bf16 n=1152 d=1152 ntok=256 bf16 plane, the widen walk: 0.781 ms (870.0092602248345 GFLOP/s; median 0.782 ms, cv 0.18774816) within 0.00015252455 of the double dot on 512 sampled elements (largest difference 2.3841858e-06)
bf16 n=1152 d=1152 ntok=256 bf16 plane, the row nest: 2.106 ms (322.6387774125212 GFLOP/s; median 2.12 ms, cv 0.5268444) within 0.00015252455 of the double dot on 512 sampled elements (largest difference 1.9073486e-06)
mel 60 s x 128 one lane: 99.439 ms (8 lanes on the box; median 99.599 ms, cv 0.08989994) timing-only
mel 60 s x 128 the lanes: 17.124 ms (8 lanes on the box; median 17.186 ms, cv 0.68198687) timing-only
kpass 172.032 MB of f16 keys a step (kv head, slice) units, one lane: 49.989 ms (3.4413972166116875 GB/s, 1.7853214 ms a layer; median 51.476 ms, cv 1.5631758) within 0.0003053708 of the double dot on 512 sampled elements (largest difference 3.8146973e-06)
kpass 172.032 MB of f16 keys a step (kv head, slice) units, 256 units on the lanes: 6.461 ms (26.6262189930566 GB/s, 0.23075 ms a layer; median 6.612 ms, cv 1.2875725) bit-exact vs (kv head, slice) units, one lane on 512 sampled elements
kpass 172.032 MB of f16 keys a step a slice over every kv head, one lane: 18.762 ms (9.169172155148516 GB/s, 0.6700714 ms a layer; median 19.255 ms, cv 1.8258786) bit-exact vs (kv head, slice) units, one lane on 512 sampled elements
kpass 172.032 MB of f16 keys a step a slice over every kv head, 32 units on the lanes: 3.165 ms (54.354503024789814 GB/s, 0.113035716 ms a layer; median 3.168 ms, cv 0.4500486) bit-exact vs (kv head, slice) units, one lane on 512 sampled elements
gelu_erf 4194304 elements the double body: 37.984 ms (9.056091 ns an element; median 37.996 ms, cv 0.021893969) within 3.9872934e-06 of the erf series on 512 sampled elements (largest difference 2.3841858e-07)
gelu_erf 4194304 elements the float kernel: 3.276 ms (0.78105927 ns an element; median 3.351 ms, cv 2.0024886) within 3.9872935e-05 of the erf series on 512 sampled elements (largest difference 2.3841858e-07)
epyc9r14 (Zen 4, 16 cores)
bf16 n=2560 d=10752 ntok=512 f32 plane, the tile walk: 19.782 ms (1424.8166751090073 GFLOP/s; median 20.206 ms, cv 2.3823152) within 0.00023726377 of the double dot on 512 sampled elements (largest difference 8.583069e-06)
bf16 n=2560 d=10752 ntok=512 bf16 plane, the widen walk: 18.167 ms (1551.4792295967598 GFLOP/s; median 19.878 ms, cv 5.261381) within 0.00023726377 of the double dot on 512 sampled elements (largest difference 6.67572e-06)
bf16 n=2560 d=10752 ntok=512 bf16 plane, the row nest: 63.723 ms (442.31632328951747 GFLOP/s; median 64.85 ms, cv 1.3377079) within 0.00023726377 of the double dot on 512 sampled elements (largest difference 5.722046e-06)
bf16 n=4320 d=480 ntok=800 f32 plane, the tile walk: 2.348 ms (1413.015302353947 GFLOP/s; median 2.394 ms, cv 4.2522097) within 0.00033061218 of the double dot on 512 sampled elements (largest difference 1.4066696e-05)
bf16 n=4320 d=480 ntok=800 bf16 plane, the widen walk: 2.312 ms (1435.0172785447724 GFLOP/s; median 2.401 ms, cv 2.419392) within 0.00033061218 of the double dot on 512 sampled elements (largest difference 1.04904175e-05)
bf16 n=4320 d=480 ntok=800 bf16 plane, the row nest: 6.498 ms (510.5817060613795 GFLOP/s; median 6.598 ms, cv 1.2130764) within 0.00033061218 of the double dot on 512 sampled elements (largest difference 7.6293945e-06)
bf16 n=1152 d=1152 ntok=256 f32 plane, the tile walk: 0.469 ms (1448.7787442955807 GFLOP/s; median 0.492 ms, cv 2.6780832) within 0.00015252455 of the double dot on 512 sampled elements (largest difference 4.053116e-06)
bf16 n=1152 d=1152 ntok=256 bf16 plane, the widen walk: 0.502 ms (1353.5404040888277 GFLOP/s; median 0.52 ms, cv 3.3574977) within 0.00015252455 of the double dot on 512 sampled elements (largest difference 2.3841858e-06)
bf16 n=1152 d=1152 ntok=256 bf16 plane, the row nest: 1.291 ms (526.3185464621005 GFLOP/s; median 1.387 ms, cv 3.9103634) within 0.00015252455 of the double dot on 512 sampled elements (largest difference 1.9073486e-06)
mel 60 s x 128 one lane: 105.443 ms (16 lanes on the box; median 109.353 ms, cv 1.7719462) timing-only
mel 60 s x 128 the lanes: 11.855 ms (16 lanes on the box; median 12.443 ms, cv 4.177875) timing-only
kpass 172.032 MB of f16 keys a step (kv head, slice) units, one lane: 66.934 ms (2.5701736765022187 GB/s, 2.3904998 ms a layer; median 69.835 ms, cv 4.250948) within 0.0003053708 of the double dot on 512 sampled elements (largest difference 3.8146973e-06)
kpass 172.032 MB of f16 keys a step (kv head, slice) units, 256 units on the lanes: 5.588 ms (30.785970923342965 GB/s, 0.19957142 ms a layer; median 5.839 ms, cv 5.556181) bit-exact vs (kv head, slice) units, one lane on 512 sampled elements
kpass 172.032 MB of f16 keys a step a slice over every kv head, one lane: 13.975 ms (12.309981774891924 GB/s, 0.49910715 ms a layer; median 14.299 ms, cv 1.1911157) bit-exact vs (kv head, slice) units, one lane on 512 sampled elements
kpass 172.032 MB of f16 keys a step a slice over every kv head, 32 units on the lanes: 2.432 ms (70.7368443798161 GB/s, 0.08685714 ms a layer; median 2.472 ms, cv 1.9922676) bit-exact vs (kv head, slice) units, one lane on 512 sampled elements
gelu_erf 4194304 elements the double body: 22.679 ms (5.407095 ns an element; median 22.842 ms, cv 0.86032337) within 3.9872934e-06 of the erf series on 512 sampled elements (largest difference 2.3841858e-07)
gelu_erf 4194304 elements the float kernel: 3.329 ms (0.79369545 ns an element; median 3.337 ms, cv 2.1493893) within 3.9872935e-05 of the erf series on 512 sampled elements (largest difference 2.3841858e-07)
graviton4 (Neoverse V2, 16 cores)
bf16 n=2560 d=10752 ntok=512 f32 plane, the tile walk: 47.163 ms (597.6236447224212 GFLOP/s; median 47.231 ms, cv 0.3051315) within 0.00023726377 of the double dot on 512 sampled elements (largest difference 1.335144e-05)
bf16 n=2560 d=10752 ntok=512 bf16 plane, the widen walk: 42.602 ms (661.605607543462 GFLOP/s; median 42.617 ms, cv 0.3162061) within 0.00023726377 of the double dot on 512 sampled elements (largest difference 1.335144e-05)
bf16 n=2560 d=10752 ntok=512 bf16 plane, the row nest: 146.504 ms (192.38876278278556 GFLOP/s; median 147.312 ms, cv 0.33593467) within 0.00023726377 of the double dot on 512 sampled elements (largest difference 5.722046e-06)
bf16 n=4320 d=480 ntok=800 f32 plane, the tile walk: 5.898 ms (562.5229116722594 GFLOP/s; median 5.92 ms, cv 0.17023568) within 0.00033061218 of the double dot on 512 sampled elements (largest difference 1.9073486e-05)
bf16 n=4320 d=480 ntok=800 bf16 plane, the widen walk: 5.543 ms (598.5494980280466 GFLOP/s; median 5.566 ms, cv 0.19537106) within 0.00033061218 of the double dot on 512 sampled elements (largest difference 1.9073486e-05)
bf16 n=4320 d=480 ntok=800 bf16 plane, the row nest: 21.713 ms (152.80063097023728 GFLOP/s; median 21.737 ms, cv 0.40240344) within 0.00033061218 of the double dot on 512 sampled elements (largest difference 7.6293945e-06)
bf16 n=1152 d=1152 ntok=256 f32 plane, the tile walk: 1.029 ms (660.327715288699 GFLOP/s; median 1.036 ms, cv 0.27745163) within 0.00015252455 of the double dot on 512 sampled elements (largest difference 4.7683716e-06)
bf16 n=1152 d=1152 ntok=256 bf16 plane, the widen walk: 1.023 ms (664.2006321927056 GFLOP/s; median 1.033 ms, cv 0.48030657) within 0.00015252455 of the double dot on 512 sampled elements (largest difference 4.7683716e-06)
bf16 n=1152 d=1152 ntok=256 bf16 plane, the row nest: 2.306 ms (294.6562227606403 GFLOP/s; median 2.315 ms, cv 0.27420813) within 0.00015252455 of the double dot on 512 sampled elements (largest difference 1.9073486e-06)
mel 60 s x 128 one lane: 106.065 ms (16 lanes on the box; median 106.322 ms, cv 0.1130684) timing-only
mel 60 s x 128 the lanes: 13.009 ms (16 lanes on the box; median 13.031 ms, cv 0.19264683) timing-only
kpass 172.032 MB of f16 keys a step (kv head, slice) units, one lane: 21.209 ms (8.111273656015708 GB/s, 0.7574643 ms a layer; median 21.293 ms, cv 0.57917356) within 0.0003053708 of the double dot on 512 sampled elements (largest difference 3.8146973e-06)
kpass 172.032 MB of f16 keys a step (kv head, slice) units, 256 units on the lanes: 2.004 ms (85.84431358325645 GB/s, 0.071571425 ms a layer; median 2.019 ms, cv 0.34492096) bit-exact vs (kv head, slice) units, one lane on 512 sampled elements
kpass 172.032 MB of f16 keys a step a slice over every kv head, one lane: 18.142 ms (9.482526629864715 GB/s, 0.6479286 ms a layer; median 18.165 ms, cv 0.27147952) bit-exact vs (kv head, slice) units, one lane on 512 sampled elements
kpass 172.032 MB of f16 keys a step a slice over every kv head, 32 units on the lanes: 1.699 ms (101.2548557406921 GB/s, 0.06067857 ms a layer; median 1.719 ms, cv 0.52471244) bit-exact vs (kv head, slice) units, one lane on 512 sampled elements
gelu_erf 4194304 elements the double body: 47.331 ms (11.28459 ns an element; median 47.346 ms, cv 0.027132014) within 3.9872934e-06 of the erf series on 512 sampled elements (largest difference 2.3841858e-07)
gelu_erf 4194304 elements the float kernel: 8.908 ms (2.1238327 ns an element; median 8.912 ms, cv 0.025978455) within 3.9872935e-05 of the erf series on 512 sampled elements (largest difference 2.3841858e-07)
M5 Max (18 lanes)
bf16 n=2560 d=10752 ntok=512 f32 plane, the tile walk: 19.125 ms (1473.7632878431373 GFLOP/s; median 19.46 ms, cv 12.328215) within 0.00023726377 of the double dot on 512 sampled elements (largest difference 1.335144e-05)
bf16 n=2560 d=10752 ntok=512 bf16 plane, the widen walk: 20.214 ms (1394.3663748534802 GFLOP/s; median 20.497 ms, cv 1.5357914) within 0.00023726377 of the double dot on 512 sampled elements (largest difference 1.335144e-05)
bf16 n=2560 d=10752 ntok=512 bf16 plane, the row nest: 42.328 ms (665.8883828510141 GFLOP/s; median 43.165 ms, cv 4.3372297) within 0.00023726377 of the double dot on 512 sampled elements (largest difference 5.722046e-06)
bf16 n=4320 d=480 ntok=800 f32 plane, the tile walk: 2.283 ms (1453.2457341600461 GFLOP/s; median 2.333 ms, cv 12.840694) within 0.00033061218 of the double dot on 512 sampled elements (largest difference 1.9073486e-05)
bf16 n=4320 d=480 ntok=800 bf16 plane, the widen walk: 2.613 ms (1269.7130143737302 GFLOP/s; median 2.66 ms, cv 6.876589) within 0.00033061218 of the double dot on 512 sampled elements (largest difference 1.9073486e-05)
bf16 n=4320 d=480 ntok=800 bf16 plane, the row nest: 5.305 ms (625.4024707554099 GFLOP/s; median 6.169 ms, cv 6.4207406) within 0.00033061218 of the double dot on 512 sampled elements (largest difference 7.6293945e-06)
bf16 n=1152 d=1152 ntok=256 f32 plane, the tile walk: 0.436 ms (1558.4340925427161 GFLOP/s; median 0.45 ms, cv 21.760473) within 0.00015252455 of the double dot on 512 sampled elements (largest difference 4.7683716e-06)
bf16 n=1152 d=1152 ntok=256 bf16 plane, the widen walk: 0.507 ms (1340.1917337628279 GFLOP/s; median 1.17 ms, cv 67.728165) within 0.00015252455 of the double dot on 512 sampled elements (largest difference 4.7683716e-06)
bf16 n=1152 d=1152 ntok=256 bf16 plane, the row nest: 1.033 ms (657.7708160875054 GFLOP/s; median 1.047 ms, cv 33.017982) within 0.00015252455 of the double dot on 512 sampled elements (largest difference 1.9073486e-06)
gelu_erf 4194304 elements the double body: 14.008 ms (3.3397675 ns an element; median 14.061 ms, cv 1.3470924) within 3.9872934e-06 of the erf series on 512 sampled elements (largest difference 2.3841858e-07)
gelu_erf 4194304 elements the float kernel: 3.491 ms (0.83231926 ns an element; median 3.513 ms, cv 0.38018703) within 3.9872935e-05 of the erf series on 512 sampled elements (largest difference 2.3841858e-07)
mel 60 s x 128 one lane: 55.999 ms (18 lanes on the box; median 60.665 ms, cv 4.8092966) timing-only
mel 60 s x 128 the lanes: 6.894 ms (18 lanes on the box; median 6.909 ms, cv 4.4420695) timing-only
kpass 172.032 MB of f16 keys a step (kv head, slice) units, one lane: 17.536 ms (9.810219370770708 GB/s, 0.6262857 ms a layer; median 23.067 ms, cv 10.183533) within 0.0003053708 of the double dot on 512 sampled elements (largest difference 3.8146973e-06)
kpass 172.032 MB of f16 keys a step (kv head, slice) units, 256 units on the lanes: 1.398 ms (123.05579382352626 GB/s, 0.049928572 ms a layer; median 1.439 ms, cv 3.251869) bit-exact vs (kv head, slice) units, one lane on 512 sampled elements
kpass 172.032 MB of f16 keys a step a slice over every kv head, one lane: 8.477 ms (20.29397135782091 GB/s, 0.30275002 ms a layer; median 10.739 ms, cv 12.368933) bit-exact vs (kv head, slice) units, one lane on 512 sampled elements
kpass 172.032 MB of f16 keys a step a slice over every kv head, 32 units on the lanes: 0.923 ms (186.38353639028324 GB/s, 0.032964285 ms a layer; median 0.939 ms, cv 1.0210239) bit-exact vs (kv head, slice) units, one lane on 512 sampled elements

Claims - stated, not tested

  • The conv front's 1123 ms on the Xeon is GEMM-bound: 200 chunks of a 3.3 and a 0.86 GFLOP conv are 840 GFLOP at 750 GFLOP/s of f32 tile on 8 cores; the figure is arithmetic over the stage probe and the race, not a profile of the conv alone.
  • The chain's wall is not its K row traffic: the K pass itself doubles under the unit order (the kpass rows) and the chain did not move.

Not done

  • The conv front stays f32: the mmproj's conv weights are F16, so reaching the matrix unit needs an operand ruling (AMX-FP16, Granite Rapids only, or an f16-to-bf16 panel under the f16 precision) - row 240.
  • The family's vector legs (vdpbf16ps on Zen4, bfdot on Graviton) - row 240; those boxes run the widen walk.
  • The ASR session's CPU K/V codec: q8_0 halves the decode's attention wall and moves the transcript - row 242, a ruling.
  • matmul_bf16_batch_at's decode path (ntok 1) keeps the dot_bf16 GEMV shaper.
  • The m5's E4B image encode at 420 against the release-17 board's 375 predates this diff - the release re-mint's.
  • The large-tier parity rows after Flash-Next in model_specs.das (micro-qwen4exp, Qwen3-8B BF16, Qwen3.5-4B/9B, the Qwen3.8-27B quants, Qwen1.5-MoE, Qwen3-30B Q8_0) did not run on this box: the 89 GB image's load is killed on 128 GB. The small tier ran whole.

borisbat and others added 18 commits October 25, 2026 01:25
The fp32 batch tile rounds in its lanes, and the router's top-k over
tile-rounded logits parts from decode's at a near tie: gemma-4-26B-A4B
Q4_0's CPU counting walk fell off its pinned tokens from the fourth.
`matmul_batch_rows` is the nest as its own entry, under no knob and no
override seam; `mm_fblob_rows` takes it at both router sites, so a
prefill routes a token as decode would.

`test_matmul_batch` holds the entry to the per-token matmul bit for bit
at the router's shape, the tile apart as the control. `test_prefill_fp32`
pins the nest for its bit-exact cells, as the Q8 cell pins the portable
backend, and holds the shipped tile's last-position logits within 1e-4
of Nx forward, the two apart bit for bit as the control.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
At depth 3 over a 32-token walk the eighth round drafts two: the budget
has three tokens left. The cell expects every round at the knob's depth
but a shorter last one.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The erf GELU evaluated erfc in double through libm's exp, one element at a time,
8.6 ns an element a lane; the Xeon's Qwen3-ASR conv front spent about 1.3 s of
its 2.9 s encode in it. The kernel now computes the same NR erfc fit over exp4's
polynomial in float, every op arithmetic, so the loop vectorizes: 0.85 ns an
element a lane on the M5, the fp64-series cells within their 1e-6 bars. The
tuner races it as the 27th tuned kernel.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
matmul_bf16_batch ran a dot_bf16 nest, one output a dot at two loads a FMA - the
gemma-E per-layer projection and the bf16 tower planes paid it on every CPU
prefill. The tile walk is now generic over the weight lattice: the same row-tile
dispatch, token blocks and tails, with bf16_batch_tile widening each halfword by
the exact shift inside the sixteen-accumulator loop, so the bf16 plane lands the
f32 plane's rate (1146 against 1073 GFLOP/s at the E4B projection's pp512 shape
on the M5) at half the weight bytes. Decode keeps the GEMV chunk shaper. The
tuner races the tile as the 28th kernel; the GEMM test holds three bf16 shapes
to the plain oracle over the widened weights.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
log_mel_qwen3a ran its [frames x 402] DFT GEMM and the double-accumulated mel
fold on one lane - 400 ms of the Xeon's Qwen3-ASR encode on gb1. Both loops now
split over frames, the GEMM on whole 4-row tiles so gemm_f32's scalar strip sees
only the global tail; every frame's arithmetic is the one-lane run's, so the mel
lands the same bits at any lane count (6.5x on the M5 over a 60 s clip).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
bf16w_tile_gen packs sixteen rows of a native bf16 plane as the TMUL B layout
(k-pair rows, bf16w_panel_build), rounds the f32 activations to bf16 once per
call (the reference encoders' arithmetic) and runs the quant families' AMX bf16
tile emitter over them; every tail - a short group, the token tail, the row tail
- takes the widen walk over the same rounded activations, so one call's outputs
share their activation bits. matmul_bf16_batch reaches it through a seam
dasllama_math_gen registers; where the family declines (no sidecar entry, no
AMX, n off the 32 lattice) the widen walk serves as before. On the Granite
Rapids box the stamped tile reads 3886 GFLOP/s at the E4B projection's pp512
shape against the f32 walk's 775, 2931 against 946 at the Qwen3-ASR conv's. The
GEMM test's bf16 cells round their oracle's activations where the family serves
and hold every tail shape.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
bf16w_tile_gen joins the probe's two rails: test mode holds every variant - the
reference row through the widen walk, a tile-form row through its panel and
tokstep walk - to a double oracle over the bf16-rounded activations on a shape
with every tail and the Qwen3-ASR conv's shape; tune mode times the tile-form
rows and the widen walk on the gemma-E projection's pp512 shape and writes the
fastest as the family's sidecar entry (the sticky margin applies).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
ARCHITECTURE_CPU_KERNELS.md gains the family's section, cited from bf16w_batch
and routed from ARCHITECTURE.md; tests/CLAUDE.md carries test_matmul_batch's
entry. The probe holds a tile-form row to the bf16 envelope of the largest
output, as the quant families' bf16 rows are held: the TMUL sums its pairs in
another order than the double oracle, and the fixture's small outputs sat under
close_tol's absolute floor on the Granite Rapids box.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The sliced decode attention dispatched a unit per (kv head, slice), so the eight
kv heads' units read each K/V row's 2 KB in eight 256-byte pieces at eight
different times. A unit is now one slice over every kv head: each row streams
once, whole. The per-(head, slice) partials are computed as before, so the
outputs are bit for bit the old ones (the fused-decode cells hold). In a K-pass
emulation the order halves the Granite Rapids box's time a layer (220 to 112 us
at 3000 keys over 8 lanes) and lifts the M5's a third; the box's full chain did
not move (8.7 against 8.9 s over 451 steps), so the chain's wall sits elsewhere
- its measured split is in the ledger.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Two rules still had a between-release diff write das rows into the record
stores, against the release boundary the board carries: a changed board cell now
withdraws its rows and writes its new figures into a dated ledger entry beside
the old ones, naming the followup row the release re-mint owes, and the
re-minted row rule binds the release re-mint.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
REVIEW_MEASUREMENT.md: the between-release rule and the changed-cell rule write
their figures from every board box of the author's and ban every diff but the
release re-mint from the record stores; the release re-mint is its own rule
(defined at first use), the new-code cell rule adds its cell to the records rig
and names the owing row, the fallback rule's trigger is a cell no box of the
author's can run or a ledger figure none can measure, the architecture list is
the companion glob. ARCHITECTURE_CPU_KERNELS.md: the bf16 family section in
short sentences with the full decline list and the probe's envelope bar named;
the lattice section covers the bf16 plane the walk now takes. REVIEW.das
re-stamps the generator hash - the new keys emit nothing for an existing perm.
harness/cpu_asr_race.das races the bf16 plane against the f32 plane, the mel's
lane split and the decode K pass's unit orders in-tree, the ledger's instrument
for those figures.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The tune pass timed every row of the grid; on a box without AMX the two amx_bf16
rows decline to the base row's widen walk, tie it, and one of them was written
as the Zen4 sidecar's entry. Only tile-form rows and the base row mr16 race now.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The 2026-10-25 entry carries the three boards' re-measured Qwen3-ASR rows at
3f7134f beside the previous ones, the Xeon's stage split, every in-tree race
with its command (harness/cpu_asr_race.das's bf16, mel and kpass arms on the
four boxes), the E4B pp512 trio and the decode under f16 and q8_0 K/V. Row 240
states what the family reaches (the conv weights are F16, the family has its AMX
leg only) and what it owes; row 242 asks for the ASR session's CPU K/V codec
ruling.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The gemma4a cell held the two rails to the same text; the f32 rail now runs the
bf16 plane through the tile walk, whose rounding splits a comma on a near-tie
token, so both ASR cells read their transcripts through transcript_words, as the
Metal cell already does.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The cold re-read's batch: the three terms move to the definitions block, the
fallback rule names the defined "can mint", the new-code rule writes its figures
into the ledger like its siblings, the per-box re-mint reads as it runs, and the
withdrawn-row rule folds into the changed-cell rule it repeated.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The review round's folds: the family's two companions were byte copies of the kq
tileform and q8q8 tokstep keys, so they name those; bf16w_batch and the probe
walk one bf16w_walk over the engine's bf16_walk; xbf16_build is generic over its
source and builds the f32 plane too, the widened copy a widen_bf16 pass;
bf16_bits is the module's rounding, the harness copies gone; bf16w_batch_serves
is the gate the test asks instead of restating it. The tuner's two tile benches
and its two in-place unary benches fold into one each, the GELU oracle's erf
series lives once in _compares. cpu_asr_race rides _race_fixture, gains the GELU
arm (the double body raced as its own arm) and the bf16 plane's row nest and
widen walk as candidates. The transcribe cells' word compare has a control and
logs both lists; the one-lane mel cell holds the threaded mel to its image; the
probe's bf16w bar is the envelope on every row, the reference row's tails
running the box's f32 tile perm. The three checklists carry their self-review
batches; the two tests' comments on the GELU say what the kernel is now.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The race script names its baselines and compare regions, holds every compared
arm to a reference or to its baseline with the bound on the row, prints the tune
manifest on every row, drops one warmup round and says so, runs the mel as an
attribution sweep with timing-only rows, and exits non-zero when it reports
nothing; the shared fill reserves before it sizes. The probe's bf16w tune rounds
run in turn across the candidates, its rows name the envelope. The six class
profiles carry the bf16w seat - the Granite Rapids mint's AMX perm on x86-amx,
the one candidate elsewhere - so a fat release ships the family as a profile
clone. The qwen3a mel is sanctioned uncovered in the hot-path coverage model, as
the tokenizer is; the gates, hot-path, memory and placement checklists carry
their self-review batches; the math_gen charter names the two new operand
builders; rows 240 and 242 tag their -jit figures and cite the board.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The 2026-10-25 entry carries every board box's race rows (the compares within
their bounds), the Qwen3-ASR and gemma-4-E4B CPU rows the rig exes minted into a
scratch store beside the release-17 board figures, the image encode's open gap
traced to master, and the byte formulas of the buffers the bf16 plane's calls
now fill; rows 240 and 242 name the re-mint run and the entry each figure comes
from; the charter bullets the rewrap had flattened are back. The audio, vision,
kq-formats and upstream checklists carry their self-review fixes, and the
architecture section states the bf16 mechanism in our terms.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 25, 2026 08:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It rewrites core multi-tier CPU GEMM kernels, the flash-decode attention dispatch, and MoE prefill routing with bit-exactness and numerical-envelope guarantees that can only be fully validated by the author's board-box runs and human review.

No open issues 🎉

What changed in this PR

This PR extends the dasLLAMA CPU kernel set with four largely independent optimizations for the Qwen3-ASR / gemma-E serving paths, plus the supporting tests, tune/race harnesses, and the module's review/architecture docs.

Changes:

  • bf16 weight tile family — adds a native bf16×bf16 matrix-unit GEMM (bf16w_tile_gen in dasllama_gemm_gen.das/dasllama_math_gen.das, reached via the g_bf16_batch_gen seam), and makes matmul_batch_core/batch_tile_block/batch_dot_rows generic over the f32 and bf16 weight lattices (bf16_batch_tile).
  • Float GELU + threaded mel + decode split — gelu_erf becomes a vectorizable [tuned] float kernel (moved from dasllama_tower.das to dasllama_math.das); log_mel_qwen3a splits its DFT GEMM on whole 4-row tiles and its mel fold over frames; the flash-decode stage-2 unit becomes one slice over every kv head; the MoE router's prefill GEMM switches to the row nest (mm_fblob_rows) so prefill routing matches decode bit-for-bit.
  • Tests, harnesses, docs — new harness/cpu_asr_race.das, bf16 cells in test_matmul_batch.das, the test_prefill_fp32 nest/tile pins, and extensive REVIEW/ARCHITECTURE/ledger prose updates.
File Description
dasllama/​dasllama_math.das Generic f32/bf16 batch tile + batch_tile_block/batch_dot_rows, matmul_batch_rows, g_bf16_batch_gen seam, float gelu_erf template
dasllama/​dasllama_math_gen.das New bf16w_batch family, xbf16_build_f32, panel build, bf16_bits/xbf16_build made public/generic
dasllama/​dasllama_gemm_gen.das bf16w_tile_gen generator reusing the AMX bf16 emitter, registration
dasllama/​dasllama_blocks.das Flash-decode stage-2 reorder (slice-over-every-kv-head) + router → mm_fblob_rows
dasllama/​dasllama_ple.das gemma4 MoE prefill router → mm_fblob_rows
dasllama/​dasllama_common.das New mm_fblob_rows wrapper
dasllama/​dasllama_qwen3a.das Threaded log-mel (DFT GEMM tiles, mel fold over frames)
dasllama/​dasllama_tower.das gelu_erf pointer body/erf_nr removed (kernel now in math)
dasllama/​dasllama_convert.das (dep) widen_bf16 now required by math_gen
harness/​cpu_asr_race.das New one-process race for bf16/gelu/mel/kpass arms
harness/​gen_tune_probe.das bf16w tune/test family + gate counts
harness/​tune_kernels.das bench_unary_inplace/bench_batch_tile refactor, bf16/gelu benches, count→28
harness/​_race_fixture.das reserve before resize in race_fill
tests/​*.das, REVIEW*.md, ARCHITECTURE*.md, PERF_LEDGER.md, followup_general.md, REVIEW.das, performance/​defaults/​*.json Tests, gate hash bump, tune defaults, and doc/ledger updates

I verified the highest-risk areas: the flash-decode stage-2 reorder preserves per-(head, slice) partial-slot writes and keeps lanes disjoint (parallelism drops to nsl, a deliberate measured tradeoff); gelu_erf/erf_series are equivalent to the removed forms and pinned by test_audio exact values; the mel split is row-lattice-aligned and element-pinned; matmul_bf16_batch_at, xbf16_build null handling, the generic batch_* dispatch, and g_bf16_batch_gen placement are internally consistent; the dasllama_convert require introduces no cycle; and the GEMM_GEN_STAMP_HASH re-stamp matches the generator edit. I found no concrete defects to flag.

Review effort: Balanced

@borisbat
borisbat merged commit 747ffc0 into master Oct 25, 2026
28 checks passed
@borisbat
borisbat deleted the bbatkin/bf16-tower-gemm branch October 25, 2026 13:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants