omeganya nya's lab notes

How fast do small models run on a 4-core CPU? 65 model files measured

I ran 65 GGUF model files from five model makers on a small CPU-only cloud server and measured how fast each one reads a prompt (prefill) and writes an answer (decode). The short version:

The machine and the method

FileMethodPrefill tok/sDecode tok/s
Qwen3-4B Q4_K_Mllama-bench20.05.8
Qwen3-4B Q4_K_Mserver, short tasks19.9–21.47.6
Qwen3.5-0.8B Q8_0llama-bench76–8216.5–18.9
Qwen3.5-0.8B Q8_0server, short tasks74.620.0

Decode: bandwidth ÷ file size

0.1 0.2 0.5 1 2 5 2 5 10 20 50 100 200 model file size (GB) decode, tokens/s 18 GB/s ÷ size LFM2.5-230M-Q4_0: 0.15 GB, 94.0 tok/s LFM2.5-230M-QAD-Q4_0: 0.15 GB, 94.3 tok/s LFM2.5-230M-Q4_K_M: 0.15 GB, 113.0 tok/s LFM2.5-230M-Q5_K_M: 0.17 GB, 81.8 tok/s LFM2.5-230M-Q6_K: 0.19 GB, 99.8 tok/s LFM2.5-350M-Q4_0: 0.22 GB, 77.9 tok/s LFM2.5-350M-QAD-Q4_0: 0.22 GB, 81.0 tok/s LFM2.5-350M-Q4_K_M: 0.23 GB, 79.1 tok/s LFM2.5-230M-Q8_0: 0.25 GB, 85.7 tok/s LFM2.5-350M-Q5_K_M: 0.26 GB, 57.5 tok/s LFM2.5-350M-Q6_K: 0.29 GB, 65.2 tok/s LFM2.5-350M-Q8_0: 0.38 GB, 53.0 tok/s LFM2.5-230M-BF16: 0.46 GB, 45.6 tok/s LFM2.5-230M-F16: 0.46 GB, 50.7 tok/s Qwen3.5-0.8B-Q4_0: 0.56 GB, 25.3 tok/s LFM2.5-1.2B-Instruct-Q4_0: 0.70 GB, 22.9 tok/s LFM2.5-1.2B-Instruct-QAD-Q4_0: 0.70 GB, 25.5 tok/s LFM2.5-350M-BF16: 0.71 GB, 31.8 tok/s LFM2.5-350M-F16: 0.71 GB, 33.5 tok/s LFM2.5-1.2B-Instruct-Q4_K_M: 0.73 GB, 23.1 tok/s Qwen3.5-0.8B-Q8_0: 0.83 GB, 20.0 tok/s LFM2.5-1.2B-Instruct-Q5_K_M: 0.84 GB, 22.7 tok/s LFM2.5-1.2B-Instruct-Q6_K: 0.96 GB, 22.3 tok/s LFM2.5-1.2B-Instruct-Q8_0: 1.25 GB, 17.3 tok/s Qwen3.5-0.8B-BF16: 1.56 GB, 11.9 tok/s LFM2.5-2.6B-Q4_0: 1.59 GB, 9.9 tok/s LFM2.5-2.6B-QAD-Q4_0: 1.59 GB, 10.6 tok/s LFM2.5-2.6B-Q4_K_M: 1.67 GB, 10.6 tok/s granite-4.2-3b-Q3_K_S: 1.68 GB, 5.1 tok/s granite-4.2-3b-Q3_K_M: 1.84 GB, 8.3 tok/s LFM2.5-2.6B-Q5_K_M: 1.94 GB, 8.5 tok/s granite-4.2-3b-Q3_K_L: 1.98 GB, 7.5 tok/s granite-4.2-3b-Q4_0: 2.13 GB, 9.1 tok/s granite-4.2-3b-Q4_K_S: 2.14 GB, 9.1 tok/s Ministral-3-3B-Instruct-2512-Q4_K_M: 2.15 GB, 8.5 tok/s LFM2.5-2.6B-Q6_K: 2.22 GB, 9.1 tok/s granite-4.2-3b-Q4_K_M: 2.24 GB, 6.1 tok/s granite-4.2-3b-Q4_1: 2.34 GB, 6.9 tok/s LFM2.5-1.2B-Instruct-BF16: 2.34 GB, 10.3 tok/s LFM2.5-1.2B-Instruct-F16: 2.34 GB, 9.4 tok/s Ministral-3-3B-Instruct-2512-Q5_K_M: 2.47 GB, 7.1 tok/s Qwen_Qwen3-4B-GGUF--Qwen3-4B-Q4_K_M: 2.50 GB, 7.6 tok/s ggml-org_Qwen3-4B-GGUF--Qwen3-4B-Q4_K_M: 2.50 GB, 7.6 tok/s granite-4.2-3b-Q5_0: 2.55 GB, 4.6 tok/s granite-4.2-3b-Q5_K_S: 2.55 GB, 7.1 tok/s granite-4.2-3b-Q5_K_M: 2.61 GB, 6.8 tok/s granite-4.2-3b-Q5_1: 2.77 GB, 5.4 tok/s Qwen3-4B-Q5_0: 2.82 GB, 5.4 tok/s gemma-4-E2B-it-Q4_0: 2.84 GB, 11.7 tok/s LFM2.5-2.6B-Q8_0: 2.88 GB, 7.5 tok/s Qwen3-4B-Q5_K_M: 2.89 GB, 6.5 tok/s granite-4.2-3b-Q6_K: 3.01 GB, 7.0 tok/s Qwen3-4B-Q6_K: 3.31 GB, 6.2 tok/s gemma-4-E2B_q4_0-it: 3.35 GB, 12.5 tok/s Ministral-3-3B-Instruct-2512-Q8_0: 3.65 GB, 6.2 tok/s granite-4.2-3b-Q8_0: 3.89 GB, 5.3 tok/s Qwen_Qwen3-4B-GGUF--Qwen3-4B-Q8_0: 4.28 GB, 5.2 tok/s ggml-org_Qwen3-4B-GGUF--Qwen3-4B-Q8_0: 4.28 GB, 5.3 tok/s gemma-4-E4B-it-Q4_0: 4.59 GB, 6.8 tok/s LFM2.5-8B-A1B-Q4_0: 4.84 GB, 14.4 tok/s gemma-4-E2B-it-Q8_0: 4.97 GB, 9.1 tok/s gemma-4-E4B_q4_0-it: 5.16 GB, 7.0 tok/s LFM2.5-8B-A1B-Q4_K_M: 5.16 GB, 17.6 tok/s LFM2.5-2.6B-BF16: 5.40 GB, 3.4 tok/s LFM2.5-2.6B-F16: 5.40 GB, 4.7 tok/s LFM2.5-8B-A1B (MoE) Gemma 4 E2B LFM2.5-230M Qwen3-4B Q4_K_M
Decode speed of all 65 files against file size (log scales). dense models, Gemma 4 E models, mixture-of-experts. The dashed line is 18 GB/s ÷ file size. Hover a dot for the file.

To write one token, a dense model has to read all of its weights from memory once. On a CPU, that read is the bottleneck, so the speed is set by how many bytes the file has, not by how the bytes are packed. Across the 58 dense files, decode × size had a median of 18 GB/s, and 53 of them fell between 14 and 24 GB/s. The rest were three Granite files (8.6–13.7) and two at 24–25; with answers of only ~10 tokens and noisy neighbours, single files scatter.

That has a simple consequence for choosing a file: **a quantization only makes decode faster by making the file smaller.** BF16 and F16 files are twice the size of Q8_0 and write at half the speed (Qwen3.5-0.8B: 11.9 vs 20.0 tokens/s).

Mixture-of-experts breaks the rule. LFM2.5-8B-A1B has about 8B parameters but uses only about 1B for each token, so it reads only a slice of its 5.2 GB file per token. It wrote 17.6 tokens/s; the dense rule predicts about 3.5. The catch for this particular model: it always thinks before answering, even with thinking switched off. It used 66 tokens to say "OK", so per answer it is slower than its speed suggests.

Gemma 4 E2B and E4B are also faster than their size (31–45 GB/s "effective"). The "E" stands for effective parameters: a large part of the file is per-layer embedding tables, of which only a few rows are needed per token. That is my reading of the architecture, not something I measured directly.

Prefill: compute, not bandwidth

Reading the prompt works on many tokens at once, so it is limited by arithmetic, not memory. Here the model's size in parameters matters much more than the file:

Model (file)File GBPrefill tok/sDecode tok/s
LFM2.5-230M Q6_K0.1935199.8
LFM2.5-350M Q4_K_M0.2327479.1
Qwen3.5-0.8B Q8_00.837520.0
LFM2.5-1.2B-Instruct Q4_K_M0.737223.1
LFM2.5-2.6B Q4_K_M1.673110.6
Gemma 4 E2B (Google QAT q4_0)3.353212.5
Ministral 3 3B Q4_K_M2.15238.5
Granite 4.2 3B Q4_K_S2.14269.1
Qwen3-4B Q4_K_M2.50207.6
Gemma 4 E4B (Google QAT q4_0)5.16167.0
LFM2.5-8B-A1B Q4_K_M (MoE)5.163817.6

For an agent on a CPU, prefill is usually the bigger cost: a tool list, a few instructions and the conversation so far easily reach 1,000 tokens. On a 4B model that is close to a minute per turn before the first word. Two things help: short prompts, and a prompt whose beginning never changes, because llama-server can reuse the part it has already read. (One more open question: the LiquidAI models reused none of it in my runs; the Qwen models did.)

The slow quantization types

For two families I had many quantization types of the same model. The "legacy" types Q5_0, Q5_1 and Q4_1 read prompts far slower than the rest:

FilePrefill tok/s
Granite 4.2 3B Q4_K_S25.6
Granite 4.2 3B Q4_022.3
Granite 4.2 3B Q5_012.0
Granite 4.2 3B Q4_110.3
Granite 4.2 3B Q5_17.5
Qwen3-4B Q4_K_M19.9
Qwen3-4B Q5_09.6

Qwen3-4B Q5_0 was slow in all 8 samples of two separate benchmarks, so this is not noise. Q4_0 is not affected. My guess is that llama.cpp has a re-packed fast path for Q4_0 and the K-quants on AVX2 but not for these types; I have not checked the source. Either way: on a CPU like this one, pick Q4_K_M (or Q4_0) and avoid Q5_0, Q5_1 and Q4_1.

More things worth knowing

The data

All 65 rows (file, size, prefill, decode, decode × size, tokens generated, stolen CPU time) are in 2026-10-28-cpu-speed.csv. One machine, one llama.cpp version: other CPUs, especially ones with more memory channels or AVX-512, will give different numbers, but the bandwidth rule should carry over.