Repository navigation
dasLLAMA: the bf16 weight tile family, the float GELU, the threaded mel and the decode K/V split - #4366
Conversation
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>
There was a problem hiding this comment.
🔵 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_genindasllama_gemm_gen.das/dasllama_math_gen.das, reached via theg_bf16_batch_genseam), and makesmatmul_batch_core/batch_tile_block/batch_dot_rowsgeneric over the f32 and bf16 weight lattices (bf16_batch_tile). - Float GELU + threaded mel + decode split —
gelu_erfbecomes a vectorizable[tuned]float kernel (moved fromdasllama_tower.dastodasllama_math.das);log_mel_qwen3asplits 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 intest_matmul_batch.das, thetest_prefill_fp32nest/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
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_erfis a tuned loop kernel on the float lattice: the NR erfc fit over exp4's polynomial, every op arithmetic, so it vectorizes.matmul_bf16_batchtakes the fp32 tile walk:matmul_batch_coreandbatch_tile_blockare generic over the weight lattice,bf16_batch_tilewidens 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_buildpacks 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_bf16emitter runs over them through the engine'sbf16_walk, every tail takes the widen walk over the same rounded activations.matmul_bf16_batch_atreaches it throughset_bf16_batch_gen;bf16w_batch_servesis 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 candidatemr16elsewhere) sodaspkg release --fatships it. The generator probe gates and races it; the tuner racesgelu_erfandbf16_batch_tile.log_mel_qwen3asplits 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).mm_fblob_rowsovermatmul_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_parityunderDASLLAMA_PARITY_FULL=1, red on master, green here).test_matmul_batchholds 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.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.mddefines 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.Observable behavior (
debug-jit,direction-grade;PERF_LEDGER.md's 2026-10-25 entry has every command).enc.ffn.gelu194 -> 41 ms.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-jitscript at 2d7d99f). The rows stay in the ledger; rows 240 and 242 own the release re-mint.attn_chain8.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.g_bf16_batch_genis armed bydasllama_math_gen's[init]in every context; no forked context callsmatmul_bf16_batchwithntok > 1(the callers are the PLE projection and the tower'smm_bf16_b, both on the serving thread).Where to look.
bf16w_batchandbf16w_walkindasllama_math_gen.daswithARCHITECTURE_CPU_KERNELS.md#bf16-weight-tile-family;gelu_erf_template,batch_tile_blockandmatmul_batch_rowsindasllama_math.das;log_mel_qwen3aindasllama_qwen3a.das; the stage-2 unit inattention_chain_decode(dasllama_blocks.das);harness/cpu_asr_race.das.Validation, races, claims, ledger
Validation (every run
-jit, no--exclude)test_facade_docsred on master, the four Vulkan files - Vulkan is off on this Mac);--area audio11 files,test_vulkan_tower_kernelsthe one red;--suite image --arm gemma4aand--arm qwen3a0 failed after the word-wise compare;--area tts17 files 0 failed;--suite image --arm mtower52 of 52;--suite decode --arm arm11passed;--area llmunderDASLLAMA_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_paritykilled (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_drafter38/38,test_prefill6/6;test_matmul_batch18/18 (the bf16 cells' oracle rounds its activations wherebf16w_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_decode13 passed 1 skipped,test_qwen3a_mel_lanes, the GELU cells oftest_tower_asr_kernelsandtest_audio,test_qwen3a_tower; the generator probeDAS_TUNE_MODE=testOK on the M5 (the AMX rows decline) and on gnr (every row ok under the bf16 envelope); the AMX-bf16 rows oftest_matmul_batchand the probe ran on gnr (x86-amx class, Granite Rapids).close_tol's absolute floor before the envelope bar; the transcript cells' one-word-short control.daspkg release --fat arm-i8mmfrom 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 notune gate:line.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 --full21 passed, 4 skipped, 1 red:docs/sphinx-html, the box's PATHsphinx-build(homebrew Sphinx 9.2 withoutsphinx_sitemap); the control,~/Library/Python/3.11/bin/sphinx-build -W -q -b html doc/source, exits 0 on this tree.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 5at cbfe4d6,-jit -no-module-cache, the box's rig sidecar asDAS_TUNE_MANIFEST, one process a box, the GELU arm a second run)gnr (Granite Rapids, 8 cores)
epyc9r14 (Zen 4, 16 cores)
graviton4 (Neoverse V2, 16 cores)
M5 Max (18 lanes)
Claims - stated, not tested
kpassrows) and the chain did not move.Not done
vdpbf16pson Zen4,bfdoton Graviton) - row 240; those boxes run the widen walk.matmul_bf16_batch_at's decode path (ntok 1) keeps thedot_bf16GEMV shaper.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.