Back to Mistral Rs

mistral.rs v0.9.0 CPU Benchmark Report

releases/v0.9.0/report.md

0.9.014.0 KB
Original Source

mistral.rs v0.9.0 CPU Benchmark Report

CPU-only comparison of mistral.rs against llama.cpp on two architectures: GB10 (aarch64, 10x Cortex-X925) and a c7i.8xlarge Xeon (Sapphire Rapids, AVX512/VNNI/AMX). Values are tokens per second; speedups are mistral.rs divided by llama.cpp at the same prompt length or decode depth, with each engine at its best measured configuration.

Decode is at or ahead of llama.cpp at every measured depth on both architectures, and the lead grows with context: 1.81x (x86) and 1.79x (ARM) at 16K depth. The mechanism, in one line: decode attention streams the KV cache at memory bandwidth with the output accumulators held in registers, so per-token cost approaches the hardware's memory floor while llama.cpp's kernel carries per-position overhead that compounds with depth. A detailed writeup of the kernel design is forthcoming.

Headline results

GB10 (aarch64), mean speedup across context lengths 128-8192/16384:

ModelQuantPrefill meanDecode mean
gemma4-e4bQ4_K2.75x1.31x
gemma4-e4bQ6_K2.80x1.21x
gemma4-e4bQ8_02.18x1.20x
qwen3-4bQ4_K1.45x1.35x
qwen3-4bQ6_K1.49x1.14x
qwen3-4bQ8_01.15x1.13x
lfm2.5-230mQ4_K1.05x1.02x
lfm2.5-230mQ6_K1.05x1.06x
lfm2.5-230mQ8_01.07x0.96x
lfm2.5-8b-a1b (MoE)Q4_K0.98x1.02x

x86 (Sapphire Rapids), qwen3-4b, per-point ratios:

q4k1285122048819216384
prefill0.42x0.69x0.79x0.86x-
decode1.06x1.07x1.12x1.53x1.81x
q8_012851220488192
prefill0.79x0.66x0.72x0.81x
decode0.84x0.84x0.92x1.33x

Known gaps, stated plainly: x86 prefill trails llama.cpp's mature AMX path (a feature most of the x86 fleet lacks; a non-AMX comparison point is planned); MoE prefill at 8192 is 0.87x; q8_0 shallow x86 decode is 0.84x. Causes are understood and fixes are scoped for the next release.

Method

  • Workloads: prompt lengths and decode depths of 128, 512, 2048, 4096, 8192 (and 16384 for qwen3-4b Q4_K); 256 generated tokens per decode depth; 1 warmup, 2-3 measured iterations.
  • CPU-only builds: mistral.rs without GPU features, run with --cpu; llama.cpp with GGML_CUDA=OFF GGML_NATIVE=ON (Release), pinned commit below.
  • Quantization: mistral.rs ISQ q4k/q6k/q8_0 (benchmarked from prequantized UQFF, numerically identical to --isq) versus llama.cpp GGUF Q4_K_M/Q6_K/Q8_0. Q8_0 is the same scheme on both engines; ISQ q4k is uniform while GGUF Q4_K_M mixes Q4_K/Q6_K per tensor, so the 4-bit tiers are close but not bit-identical.
  • Affinity (GB10 big.LITTLE): both engines pinned to the 10 big cores for decode, each at its best measured configuration - mistral.rs CANDLE_CPU_MASK=5-9,15-19; llama.cpp decode taskset -c 5-9,15-19 -t 10, prefill at its faster stock -t 20. An affinity study (raw/results_affinity.jsonl) verified pinning mechanism does not matter (engine mask vs OS taskset within noise) and that unpinned llama.cpp decode loses >2x to little-core stragglers, while unpinned mistral.rs does not (its default thread sizing avoids the little cores).
  • llama.cpp fairness: on x86 its flash-attention CPU kernel inverts at depth (fa=1 wins through ~2k, fa=0 wins beyond: 8.8 vs 6.3 t/s at d16384), so every reported llama.cpp number is its best configuration at that point, mixing fa settings as needed. Raw data includes both.
  • The box was otherwise idle; contended runs were discarded and rerun.

Reproduction

bash
# full sweep at best-per-engine affinity (GB10)
python3 releases/v0.9.0/scripts/bench_cpu_sweep.py --phase full \
  --mrs-mode mask --lcpp-mode default --lcpp-decode-mode taskset \
  --iters 2 --warmup 1 --gen-len 256 --lengths 128,512,2048,4096,8192

Engine command shapes:

bash
# mistral.rs (ISQ from BF16 safetensors; or --from-uqff a file made by `mistralrs quantize`)
CANDLE_CPU_MASK=5-9,15-19 target/release/mistralrs bench --cpu \
  --prompt-len 128,512,2048,4096,8192 --depth 128,512,2048,4096,8192 \
  --gen-len 256 --iterations 2 --warmup 1 -m Qwen/Qwen3-4B --isq q4k

# llama.cpp prefill / decode
llama-bench -m Qwen3-4B-Q4_K_M.gguf -p 128,...,8192 -n 0 -r 2 -o json -t 20
taskset -c 5-9,15-19 llama-bench -m Qwen3-4B-Q4_K_M.gguf \
  -p 0 -n 256 -d 128,...,8192 -r 2 -o json -t 10
  • scripts/bench_cpu_sweep.py - sweep orchestrator; one JSON row per measurement appended to raw/results_full.jsonl (later rows supersede earlier ones for the same point), raw engine stdout under raw/raw_full/.
  • raw/results_x86.jsonl + raw/x86_sweep.log - the x86 sweep (includes both fa configs).
  • scripts/capture_metadata.sh - host/commit/model metadata (raw/metadata.txt).

Model artifacts

ArtifactHF repo idUse
Qwen3 4B BF16Qwen/Qwen3-4Bmistral.rs --isq source
Gemma 4 E4B BF16google/gemma-4-E4B-itmistral.rs --isq source
LFM2.5 230M BF16LiquidAI/LFM2.5-230Mmistral.rs --isq source
LFM2.5 8B A1B BF16LiquidAI/LFM2.5-8B-A1Bmistral.rs --isq source
Qwen3 4B GGUFQwen/Qwen3-4B-GGUFllama.cpp Q4_K_M / Q6_K / Q8_0
Gemma 4 E4B GGUFunsloth/gemma-4-E4B-it-GGUFllama.cpp Q4_K_M / Q6_K / Q8_0
LFM2.5 230M GGUFLiquidAI/LFM2.5-230M-GGUFllama.cpp Q4_K_M / Q6_K / Q8_0
LFM2.5 8B A1B GGUFLiquidAI/LFM2.5-8B-A1B-GGUFllama.cpp Q4_K_M

Versions and hosts

ComponentCommit or version
mistral.rsv0.9.0 (cpu_parity)
candleaarch64_repack_kernels branch (pinned by mistral.rs Cargo.lock)
llama.cpp2d973636e292ee6f75fadcf08d29cb33511f509f
rustc1.96.1

Hosts: GB10 (Linux 6.17, 10x Cortex-X925 3.9 GHz + 10x Cortex-A725, 1 NUMA node; full details in raw/metadata.txt); AWS c7i.8xlarge (Xeon Platinum 8488C, 16 physical cores, avx512f/avx512_vnni/amx_int8).

Build notes

All benchmarks are source builds of both engines on the same machine (llama.cpp with GGML_NATIVE=ON, mistral.rs with target-cpu=native), which is what the reproducer scripts do. Prebuilt installer binaries are portable (runtime-dispatched kernels) and land within ~8% of source-built throughput on both architectures; build from source to reproduce the tables exactly. Two aarch64 assets ship: the default assumes ARMv8.2 (Graviton2+, Pi 5, 2018+ ARM) and a v8.0 compat build covers A72-class boards (Pi 4); the installer picks by cpuinfo probe.

Appendix: Full Tables

All values are tokens per second; speedup is mistral.rs divided by llama.cpp in the same row.

qwen3-4b (GB10)

Q4_K Prefill
Lengthmistral.rs ISQ q4_kllama.cpp GGUF Q4_K_Mmistral.rs speedup
128148.690.01.652x
512160.190.61.768x
2048142.383.61.702x
4096100.376.01.320x
819274.964.21.167x
1638453.648.91.097x
Q4_K Decode
Depthmistral.rs ISQ q4_kllama.cpp GGUF Q4_K_Mmistral.rs speedup
12840.336.91.092x
51238.934.41.132x
204834.127.61.234x
409629.422.01.333x
819223.315.61.498x
1638416.69.31.785x
Q6_K Prefill
Lengthmistral.rs ISQ q6_kllama.cpp GGUF Q6_Kmistral.rs speedup
12898.569.11.425x
512123.470.31.755x
2048105.066.01.592x
409688.761.41.445x
819266.953.31.255x
Q6_K Decode
Depthmistral.rs ISQ q6_kllama.cpp GGUF Q6_Kmistral.rs speedup
12829.729.21.018x
51228.828.01.027x
204826.023.21.123x
409622.919.11.200x
819218.814.11.334x
Q8_0 Prefill
Lengthmistral.rs ISQ q8_0llama.cpp GGUF Q8_0mistral.rs speedup
12887.189.40.974x
512113.691.61.240x
2048107.583.71.284x
409689.876.51.173x
819269.464.41.078x
Q8_0 Decode
Depthmistral.rs ISQ q8_0llama.cpp GGUF Q8_0mistral.rs speedup
12824.724.11.024x
51223.923.21.032x
204822.119.81.116x
409619.916.61.199x
819216.713.01.281x

qwen3-4b (x86, Sapphire Rapids)

llama.cpp values are its best fa configuration per point (fa=1 shallow, fa=0 deep).

Q4_K Decode
Depthmistral.rs ISQ q4_kllama.cpp GGUF Q4_K_Mmistral.rs speedup
12833.932.01.06x
51232.430.31.07x
204829.226.11.12x
819221.514.11.53x
1638415.98.81.81x
Q8_0 Decode
Depthmistral.rs ISQ q8_0llama.cpp GGUF Q8_0mistral.rs speedup
12820.624.50.84x
51219.923.70.84x
204818.620.20.92x
819216.712.61.33x

Full x86 rows (including prefill and both fa configs): raw/results_x86.jsonl.

gemma4-e4b (GB10)

Q4_K Prefill
Lengthmistral.rs ISQ q4_kllama.cpp GGUF Q4_K_Mmistral.rs speedup
128195.272.42.697x
512243.975.23.244x
2048211.272.32.921x
4096176.770.52.505x
8192159.267.12.374x
Q4_K Decode
Depthmistral.rs ISQ q4_kllama.cpp GGUF Q4_K_Mmistral.rs speedup
12832.925.11.311x
51231.824.31.311x
204830.023.41.284x
409629.322.61.295x
819226.119.71.325x
Q6_K Prefill
Lengthmistral.rs ISQ q6_kllama.cpp GGUF Q6_Kmistral.rs speedup
128146.757.22.563x
512179.659.73.009x
2048171.358.42.931x
4096147.657.22.581x
8192160.155.22.898x
Q6_K Decode
Depthmistral.rs ISQ q6_kllama.cpp GGUF Q6_Kmistral.rs speedup
12824.220.41.185x
51223.720.11.176x
204823.219.51.192x
409622.718.91.203x
819221.416.71.280x
Q8_0 Prefill
Lengthmistral.rs ISQ q8_0llama.cpp GGUF Q8_0mistral.rs speedup
128125.472.21.737x
512158.675.62.099x
2048173.273.22.365x
4096156.471.52.188x
8192171.068.52.497x
Q8_0 Decode
Depthmistral.rs ISQ q8_0llama.cpp GGUF Q8_0mistral.rs speedup
12820.517.51.172x
51220.217.21.176x
204819.816.81.182x
409619.316.21.188x
819218.514.61.266x

lfm2.5-230m (GB10)

Q4_K Prefill
Lengthmistral.rs ISQ q4_kllama.cpp GGUF Q4_K_Mmistral.rs speedup
1281328.21255.51.058x
5121796.51624.31.106x
20481721.81484.51.160x
40961427.31359.51.050x
81921013.01181.60.857x
Q4_K Decode
Depthmistral.rs ISQ q4_kllama.cpp GGUF Q4_K_Mmistral.rs speedup
128375.7509.50.737x
512450.6482.60.934x
2048444.6404.41.099x
4096417.6337.61.237x
8192269.7252.31.069x
Q6_K Prefill
Lengthmistral.rs ISQ q6_kllama.cpp GGUF Q6_Kmistral.rs speedup
1281209.01278.70.945x
5121486.61363.51.090x
20481540.41287.31.197x
40961298.11183.51.097x
8192944.81027.10.920x
Q6_K Decode
Depthmistral.rs ISQ q6_kllama.cpp GGUF Q6_Kmistral.rs speedup
128379.2429.10.884x
512471.8414.71.138x
2048418.7359.21.165x
4096289.3301.80.959x
8192272.5232.61.172x
Q8_0 Prefill
Lengthmistral.rs ISQ q8_0llama.cpp GGUF Q8_0mistral.rs speedup
1281377.81744.80.790x
5122165.01749.11.238x
20482058.51622.31.269x
40961654.01462.01.131x
81921108.81230.00.901x
Q8_0 Decode
Depthmistral.rs ISQ q8_0llama.cpp GGUF Q8_0mistral.rs speedup
128287.6368.90.780x
512324.7353.70.918x
2048310.0308.61.004x
4096293.8267.61.098x
8192210.5211.20.996x

lfm2.5-8b-a1b (MoE, GB10)

Q4_K Prefill
Lengthmistral.rs ISQ q4_kllama.cpp GGUF Q4_K_Mmistral.rs speedup
512234.8229.21.024x
2048232.9224.01.040x
8192180.8207.20.873x
Q4_K Decode
Depthmistral.rs ISQ q4_kllama.cpp GGUF Q4_K_Mmistral.rs speedup
12881.279.71.019x
51279.777.11.034x
204875.975.01.012x
409670.369.91.006x
819268.461.81.107x

Appendix: ik_llama.cpp

ik_llama.cpp is the CPU-performance-focused fork by the author of llama.cpp's K-quants, and the fastest CPU implementation in the llama.cpp family. Same box (c7i.8xlarge), same GGUF, commit bbc7de4, pinned taskset -c 0-15 -t 16, its best fa configuration per point (fa=1 won every point for it). qwen3-4b Q4_K_M, tokens per second:

pp512pp2048pp8192d512d2048d8192d16384
ik_llama.cpp391.3348.9235.832.928.218.012.2
mistral.rs274.5239.2140.632.429.221.515.9
mistral.rs speedup0.70x0.69x0.60x0.98x1.04x1.19x1.30x

Decode diverges in mistral.rs's favor with depth (+30% at 16K) against a flash-attention implementation substantially better than mainline's (12.2 vs mainline's best 8.8 t/s at d16384). ik's prefill GEMM kernels lead the family and nearly match mainline's AMX path without using AMX. Not benchmarked on aarch64: ik HEAD does not compile there (gcc 13, Ubuntu 24.04).