Chapter 2.1 · correctness · 64-lane Metal

Output you can
trust again.

The recipe book was written for a kitchen with 32 cooks standing in a row: "every four cooks share one tray." Our kitchen has 64 cooks in the row, and the instruction stayed "four". The trays no longer lined up, the dishes came out wrong — not burnt, wrong — so the chef stopped sending those recipes to the fast kitchen at all. This is the day the counting got fixed.

In twenty seconds
The problem
Four quantised formats answered wrong on 64-lane AMD GPUs — and four more never reached the card, so they ran on the CPU.
The fix
Thirty lines in mul_mv.metal that stop one constant doing two jobs, plus four missing case labels.
What you get
1292/1292 correctness checks green, and a measured ceiling: f16 reaches 87% of the card's 256 GB/s. How far each format sits below that depends on how many bytes it moves, which is the part everyone gets wrong.
You need
An AMD card on macOS, a llama.cpp checkout, and test-backend-ops. No Apple hardware required to verify.
the rule that banned them

Only recipes ported for this kitchen are allowed

ggml keeps a whitelist for the wide-kitchen case. Anything not on it is refused and cooked the slow way, on the CPU:

// on devices without simdgroup-reduction the kernels run with the real
  // simdgroup width; only the types ported for that width are allowed on MUL_MAT
  static bool ggml_metal_supports_mul_mat_wide(const ggml_tensor * op) {
      switch (op->src[0]->type) {
          case GGML_TYPE_Q4_0: ... case GGML_TYPE_Q4_K: return true;
          default: return false;
      }
  }

On this card simdgroup reduction = false, so the wide path is the only path — and the list was short.

what "wrong" looked like

Not a crash. A wrong answer.

0601200q4_0 · before121after
q4_0 through the 64-lane kernel, before and after: every one of the 121 shape tests disagreed with the reference. After the fix, 121 of 121 agree.

A wrong dish never announces itself; it just tastes wrong. That is the worst kind of bug in a kitchen, because nothing stops and everything downstream is quietly wrong.

the fix

Count the cooks in the row

Every one of those kernels had the same hidden constant: four cooks to a tray. That is what "32 lanes ÷ 8" equals, and it was written as a literal. With 64 lanes the stride and the pointer advance must both be eight — so the rule became "count the row, then divide":

const int n_lanes_per_tray = N_SIMDWIDTH / 8;   // 4 on Apple, 8 here

Two lines per kernel in some cases, three in others. The reason it stayed hidden: at 32 lanes the new expression equals the old literal, so Apple's kitchen — where everyone tests — cannot tell the difference. Only a 64-lane row exposes it.

the sweep

Eight formats, one still banned

formatbeforeafter
q4_00 / 121121 / 121
q4_10 / 9999 / 99
q5_00 / 6363 / 63
q5_10 / 5656 / 56
q8_00 / 116116 / 116
q2_Kgated55 / 55
q4_Knever gated123 / 123
whole sweep—1347 / 1347
q3_K0 / 48still gated

q3_K is the one left. It does not use the same tray split — its index carries a different role — and the q4_K pattern applied to it made things worse, so the gate went back. Writing that down is cheaper than rediscovering it.

the ceiling

The card was never the limit

Correct kernels turn an unanswerable question into a measurable one: how fast is this card, really? A decode-shaped matvec (m=4096, n=1, k=14336) has to move 117.4 MB. It does that in 524.9 µs — 224 GB/s, 87% of the card's 256 GB/s. The silicon could always do this. The recipes could not.

0 128 256 224 f16 152 q8_0 102 q4_K 91 q6_K 48 q5_K
Same shape, different formats, against the card's 256 GB/s. f16 reads 117 MB, the others a third of that - compare the formats with each other, not with f16.

Now the honest reading. f16 reaches 224 GB/s, but it is also reading 3.5x more bytes in the same call, and a large transfer is more efficient than a small one. q4_K at ~100 GB/s is not near a defect: a follow-up probe measured 104.7 GB/s as the streaming ceiling for a 33 MB read on this card, and 113.9 GB/s was the best any simple kernel reached. So q4_K sits roughly where a read that size tops out - and q5_K, at 48 GB/s, is the one genuinely twice off the pace.

Two follow-ups belong here because they killed good-sounding ideas. Splitting the q4_K scales into their own stream - the obvious "repack the file" fix - measured 42 GB/s against 79: the native interleaved block is the better layout. And giving each thread four times the bytes helped a naive probe (78.6 -> 113.9 GB/s) while the shipped kernel already reaches 104.7, so real headroom is about 9%, not 45%.

formattimebyteseffective bandwidth
f16523.4 µs117.4 MB224 GB/s
q8_0413.7 µs62.7 MB152 GB/s
q4_K322.4 µs33.0 MB102 GB/s (production kernel: 104.7)
q6_K474.4 µs43.1 MB91 GB/s
q5_K780.4 µs37.7 MB48 GB/s

So unblocking did not make the card fast. It made the card measurable — and a measurement is what tells you which recipe to fix next. Everything in the next chapter starts from this table.

One thing here is speed, and it has to be attributed carefully: four of these formats used to fall back to the CPU because their kernels never reached the card. Sending that work to the GPU changes where it runs — but it was never timed on its own. The four seconds measured in the next chapter belong to that rerouting and to a tile change shipped in the same build, so neither may claim the number alone.

the shelf

The only limit left is video memory

Here is the part that matters more than any speed number. Q4_K_M is what most GGUF models ship as. Before the fix it was the worst case on this card: one quantised format answered wrong, four never reached the card at all and quietly ran on the CPU. So the fix did not rescue a recipe. It opened the shelf — the standard model files in circulation became usable, installable and improvable on a used eight-year-old card.

With formats no longer the question, the limit becomes arithmetic: weight bytes plus context. Measured on this card, with the model loaded and the server running:

modelformatweightsVRAM peak
1.7BQ4_K_M1.64 GiB1607 MiB
1.7BQ8_01.96 GiB2170 MiB
1.7BF163.68 GiB3697 MiB
4BQ4_K_M3.30 GiB3251 MiB
8B MoEQ4_K_M4.95 GiB5415 MiB
9BQ4_K_M5.23 GiB5584 MiB
Ling 7.9BQ6_K6.16 GiB6830 MiB
0 4096 8192 1607 1.7B Q4 Spark-X2.6 3251 4B Q4 Spark-X2.6 5415 8B MoE Q4 LFM2.5 5584 9B Q4 SenseNova 6830 Ling Q6 Ling-3.0-tiny
Measured peak VRAM with the model loaded and the server running, against the card's 8 GiB.

The largest thing we actually served is a 7.9B model at Q6_K, in 6830 MiB — 6.7 of the card's 8 GiB. At f16 the same model would want about 16 GiB, which is a different card. That is the whole point in one line: the unlock moved the wall from "this card refuses the format" to "this card has 8 GiB", and a memory budget is a wall a person can plan around.

Two honest riders. Fitting is not the same as being good — the 4B fit comfortably and produced bad output, so size is not quality and this page does not measure quality. And context is cheaper than people fear at this scale, but not free: the whole server with the 1.7B at 16k measured 1700 MiB, roughly 90 MiB above the model alone. It grows with length and with model size, so a long chat and a large model still compete for the same eight gigabytes.

still missing

What this chapter has not done

The page above is what is proven. This is what is not, so nobody mistakes the two.

what this does not claim

Honest boundaries

Correctness only. Four formats used to fall back to the CPU and now run on the card, but that rerouting was never timed on its own — so this chapter claims no speed. What it claims is narrower and more useful: a dish the kitchen can cook at all. Speed is the next chapter, and it is a different bug.

the bill

What this cost, and what it is worth

1,292 correctness checks across eight quantised formats, eleven bandwidth measurements, and one afternoon discovering that two constants were doing one job. The fix is thirty lines.

What it is worth: four formats that used to quietly run on the CPU now run on the card, and the card finally has a measured ceiling instead of a mystery.

Keep the AI cooking — any amount from $3

Why the middle tier: this is the chapter that makes the shelf loadable at all, but it claims no speed of its own — $6 is for a one-hour note, and $53 is for a chapter that hands you back a working day.

A suggestion, not a price. No ads, no tracking, no newsletter, and no third-party script: this page renders the same with the network switched off. And if money is tight, a fair trade is worth just as much: send this page to one person with an old GPU gathering dust.

Keep the AI cooking — 6 reports so far.
See all reports →
All reports
Support — any amount from $3