You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Tracking issue for the CUDA performance gaps surfaced by a head-to-head of the README's recorded CUDA speeds vs llama.cpp CUDA on the same models and the same box. Records the full results, the methodology, and links the per-finding sub-issues so they aren't re-derived.
Methodology
Hardware: RTX 4070 Ti (12 GB) + Ryzen 9 7900X (Zen 4). Same box for both engines.
llama.cpp: CUDA build b9529 (C:\p\llama.cpp-cuda\bin\llama-bench.exe).
README numbers: taken verbatim from the per-model tables in README.md (prefill = warm ~2K-token working-context rate; decode = near-zero-ctx headline, ≈ llama.cpp tg128).
llama.cpp — full-offload models: live llama-bench -ngl 99 -p 2048 -n 128, so pp2048 matches the README's ~2K prefill convention and tg128 matches its decode convention.
llama.cpp — CPU-MoE hybrids: documented -ngl 99 -ncmoe 99 (pp512/tg128) from prior on-box runs (live-running these is heavy CPU-expert inference). Prefill is pp512 (not 2K) so those prefill gaps are approximate; the hybrid decode gaps carry thermal/MTP caveats.
Cross-check: the live numbers land on the README's own inline llama.cpp citations — Gemma4-E4B Q8 8577 / 78.2 vs README's "~8475 / ~78", Gemma4-12B 57.2 vs "57", Qwen3-8B 6010 vs README's pp1008 5764. Methodology is consistent.
Full results
Full GPU offload (live llama-bench, -ngl 99, pp2048 / tg128):
* Decode carries thermal/MTP caveats — README notes plain decode is ~80% of llama.cpp warm-vs-warm (~1.25×); the 2× figures use a cooler reference run. See [project_decode_carnice_cpumoe] analysis.
No clean on-box baseline (not benchmarked): Qwen3-Coder-30B-A3B, Qwen3.6-27B-MTP, Llama-4 Scout (Scout not present locally; the two MoE/GDN ones would need a CPU-heavy -ncmoe run).
OLMoE and SmolLM2 both prefill below their own decode rate — the signature of a per-token prefill loop. CudaForwardPass.IsBatchedPrefillSupported() (src/SharpInference.Engine/CudaForwardPass.cs:2618) gates the fast int8-MMQ batched-trunk prefill:
Qwen3-8B and Gemma4 satisfy the gate, get the batched MMQ trunk, and sit at the residual ~2–2.6× kernel gap vs llama.cpp's cp.async MMQ + flash-attn prefill. → #409
Priority: #406/#407 are 100×+ and only need the existing GPU batched path un-gated → highest value. #410 is the CPU-side sibling (also 19–91×, needs a batched CPU FFN/expert GEMM). #408 needs profiling. #409 is deep kernel work (stretch).
Tracking issue for the CUDA performance gaps surfaced by a head-to-head of the README's recorded CUDA speeds vs llama.cpp CUDA on the same models and the same box. Records the full results, the methodology, and links the per-finding sub-issues so they aren't re-derived.
Methodology
b9529(C:\p\llama.cpp-cuda\bin\llama-bench.exe).README.md(prefill = warm ~2K-token working-context rate; decode = near-zero-ctx headline, ≈ llama.cpptg128).llama-bench -ngl 99 -p 2048 -n 128, sopp2048matches the README's ~2K prefill convention andtg128matches its decode convention.-ngl 99 -ncmoe 99(pp512/tg128) from prior on-box runs (live-running these is heavy CPU-expert inference). Prefill ispp512(not 2K) so those prefill gaps are approximate; the hybrid decode gaps carry thermal/MTP caveats.8577 / 78.2vs README's "~8475 / ~78", Gemma4-12B57.2vs "57", Qwen3-8B6010vs README'spp1008 5764. Methodology is consistent.Full results
Full GPU offload (live
llama-bench,-ngl 99,pp2048/tg128):CPU-MoE hybrids (documented
-ngl 99 -ncmoe 99,pp512/tg128):* Decode carries thermal/MTP caveats — README notes plain decode is ~80% of llama.cpp warm-vs-warm (~1.25×); the 2× figures use a cooler reference run. See [
project_decode_carnice_cpumoe] analysis.No clean on-box baseline (not benchmarked): Qwen3-Coder-30B-A3B, Qwen3.6-27B-MTP, Llama-4 Scout (Scout not present locally; the two MoE/GDN ones would need a CPU-heavy
-ncmoerun).The four biggest differences
Root cause (verified in code)
OLMoE and SmolLM2 both prefill below their own decode rate — the signature of a per-token prefill loop.
CudaForwardPass.IsBatchedPrefillSupported()(src/SharpInference.Engine/CudaForwardPass.cs:2618) gates the fast int8-MMQ batched-trunk prefill:_isMoEtrips it → per-token loop (97.4 t/s). → perf(cuda): batched int8-MMQ trunk prefill gated off for MoE — OLMoE prefill 97 vs llama.cpp 17,137 t/s (176×) #406!_hp.IsNeoxRopetrips it → per-token loop (194 t/s). → perf(cuda): batched int8-MMQ trunk prefill gated off for dense NORM-RoPE & QKV-bias models — SmolLM2 105×, VibeThinker/Qwen2 159× #407Qwen3-8B and Gemma4 satisfy the gate, get the batched MMQ trunk, and sit at the residual ~2–2.6× kernel gap vs llama.cpp's cp.async MMQ + flash-attn prefill. → #409
Sub-issues
_isMoE) → OLMoE prefill 155× (un-gate + batched expert FFN)!IsNeoxRope) & QKV-bias (_hasAttnBias) → SmolLM2 105×, VibeThinker/Qwen2 159×Priority: #406/#407 are 100×+ and only need the existing GPU batched path un-gated → highest value. #410 is the CPU-side sibling (also 19–91×, needs a batched CPU FFN/expert GEMM). #408 needs profiling. #409 is deep kernel work (stretch).