Local LLM llama.cpp RTX 3090 July 26, 2026 · 10 min read

RTX 3090 at 170 tok/s: Complete Technical Configuration Reference

This is the technical companion to the full tuning diary: How I Pushed an RTX 3090 to 170 Tokens Per Second With Qwen 3.6-35B. The Medium article covers the narrative and crash analysis. This page is the copy-pasteable reference — every flag, config file, and benchmark number.

170
tok/s sustained (code)
125
tok/s (creative writing)
$800
total hardware cost
$0
per-token cost

Hardware Specification

ComponentSpecification
CPUIntel Core i9-10900K (10 cores, 20 threads, 3.70GHz)
System RAM24GB DDR4 (WARNING: insufficient for 131K context + --mlock — see OOM section)
GPUNVIDIA RTX 3090 24GB GDDR6X (Ampere, compute capability 8.6)
VRAM Bandwidth936 GB/s (theoretical max: ~170 tok/s for this model)
OSWindows 11 + WSL2 Ubuntu 26.04
CUDA12.9
DriverNVIDIA 610.62 (Studio)

Software Stack

ComponentVersionPurpose
llama.cppb9971 (turboquant fork)Inference engine
ModelQwen3.6-35B-A3B-UD-IQ4_XS.gguf35B MoE, 3B active params
mmprojmmproj-F16.ggufMultimodal projector
llama-swapLatestModel routing (4 profiles)
Hermes Agentv0.19.0Agent framework

llama.cpp Build Command

Architecture-specific build for Ampere (compute 8.6). These flags produce native RTX 3090 machine code and enable all flash attention quantization paths:

cmake -B build \
  -DGGML_CUDA=ON \
  -DCMAKE_CUDA_ARCHITECTURES=86 \
  -DGGML_CUDA_FA_ALL_QUANTS=ON \
  -DGGML_NATIVE=ON \
  -DGGML_LTO=ON \
  -DGGML_CUDA_GRAPHS=ON \
  -DGGML_CUDA_F16=ON

cmake --build build --config Release -j 10

Critical Build Flags Explained

FlagWhy It Matters
CMAKE_CUDA_ARCHITECTURES=86Emits native Ampere machine code. Without it, GPU JIT-compiles kernels at runtime (slower, suboptimal paths).
GGML_CUDA_FA_ALL_QUANTS=ONEnables flash attention for ALL KV cache quantization formats. Without it, --cache-type-k q8_0 forces slow fallback kernels.
GGML_CUDA_GRAPHS=ONCUDA graph capture for reduced kernel launch overhead.
GGML_CUDA_F16=ONUse FP16 accumulation for faster GPU computation where precision allows.
Update first: Before tuning anything, update llama.cpp. Going from b9418 (May 2026) to b9971 (Jul 2026) gave a free 11-20% speedup from kernel optimizations. This is the highest-ROI action.

Server Launch Command

The complete, battle-tested launch command:

llama-server --port ${PORT} \
  --model Qwen3.6-35B-A3B-UD-IQ4_XS.gguf \
  --mmproj mmproj-F16.gguf \
  -c 131072 -ngl 99 -fa on -b 1024 -ub 2048 \
  -t 10 -tb 16 \
  --cache-type-k q8_0 --cache-type-v turbo4 \
  -fit off --no-mmap --mlock --jinja \
  --poll 100 --prio 2 --reasoning off \
  -np 1 \
  --spec-type draft-mtp --spec-draft-n-max 2

Flag-by-Flag Reference

FlagValuePurpose
-ngl99All layers on GPU. No CPU offload = maximum speed.
-faonFlash Attention. Non-negotiable for Ampere GPUs.
-c131072Context window. WARNING: reduce to 65536 if RAM < 48GB.
-b1024Batch size. Tuned for 24GB VRAM budget.
-ub2048Micro batch for prompt processing chunk size.
-t10CPU threads (matching physical cores).
--cache-type-kq8_0Quantized K cache. Saves VRAM for longer context.
--cache-type-vturbo4TurboQuant V cache. Best speed-quality ratio.
--no-mmapEliminates page-fault jitter (prevents random speed drops from 150→80 tok/s).
--mlockLocks model pages in RAM. Prevents swap degradation. Requires ≥48GB RAM.
--jinjaJinja2 chat template processing. Required for agent frameworks using structured tool calls.
--reasoningoffDisables thinking blocks. Saves tokens in agent workloads.
--spec-typedraft-mtpMTP speculative decoding. +21% on code workloads.
--spec-draft-n-max22-token draft window. Optimal acceptance/speed balance.

MTP Speculative Decoding Benchmarks

MTP (Multi-Token Prediction) uses a lightweight draft model to predict the next 1-2 tokens. The main model verifies them in a single forward pass.

WorkloadWithout MTPWith MTPSpeedupDraft Acceptance
Code generation126.7 tok/s169.7 tok/s+21%91%
Creative writing126.7 tok/s125.3 tok/s-1%62%
Short responses (<30 tok)~120 tok/s57.7 tok/s-52%100%
Key insight: MTP is highly effective for predictable content (code, JSON, tool calls) but net-negative for creative writing and short responses. The draft model setup overhead exceeds savings on short outputs.

Why n-gram Stacking Fails

Stacking n-gram speculative decoding alongside MTP was tested. The result: acceptance went up (62%→85% on creative) but speed went down (125→67 tok/s). Two competing draft engines generate redundant drafts that waste verification compute.

One good speculative engine beats two competing ones.

Sampling Parameters (Agent Workloads)

{
  "temperature": 0.6,
  "top_p": 0.95,
  "top_k": 20,
  "repetition_penalty": 1.05
}
ParameterValueWhy
temperature0.6Lower (0.3) causes repetitive loops on multi-step reasoning. 0.6 explores more solution paths.
top_p0.95Wider candidate pool for format compliance.
top_k20Bounds the candidate pool.
repetition_penalty1.05Standard anti-repetition.

Quantization Comparison

QuantSizeFits 24GB?SpeedQuality
IQ4_XS~17-18 GB✅ (room for KV cache)170 tok/sExcellent
Q4_K_M~18-19 GB⚠️ Tight at 131K ctx148 tok/sExcellent
Q4_K_XL~19-20 GB⚠️ Very tight135 tok/sExcellent
Q5_K_M~24-25 GB❌ (CPU offload needed)75 tok/sMarginally better

IQ4_XS from Unsloth's dynamic quantization gives the best speed-to-quality ratio for 24GB cards. The quality difference vs Q5_K_M is measurable on perplexity but invisible in real agent workloads.

Benchmark Comparison: Published Results

Every documented benchmark we could find for this hardware + model combination:

SourceQuantSpeedNotes
This setupIQ4_XS + MTP169.7 tok/s13-50% faster
Japanese benchmark (zephel01)IQ4_NL149.8 tok/sDifferent quant
Giles ThomasUD-IQ4_NL_XL140 tok/sGPU-only mode
HN user (thc1006)UD-Q4_K_XL135.7 tok/sNo MTP
Reddit r/LocalLLaMAunspecified113 tok/sLikely default settings
HF DiscussionUD-Q3_K_M120 tok/sLighter quant

llama-swap Configuration

llama-swap routes requests to the correct model profile. This is the config structure for a 4-profile setup:

# /home/game/.hermes/scripts/llama-swap-config.yaml
models:
  default:
    cmd: |
      llama-server --port ${PORT} \
        --model Qwen3.6-35B-A3B-UD-IQ4_XS.gguf \
        --mmproj mmproj-F16.gguf \
        -c 65536 -ngl 99 -fa on -b 1024 -ub 2048 \
        -t 10 --cache-type-k q8_0 --cache-type-v turbo4 \
        -fit off --no-mmap --mlock --jinja \
        --poll 100 --prio 2 --reasoning off -np 1 \
        --spec-type draft-mtp --spec-draft-n-max 2

  large-context:
    cmd: |
      llama-server --port ${PORT} \
        --model Qwen3.6-35B-A3B-UD-IQ4_XS.gguf \
        --mmproj mmproj-F16.gguf \
        -c 131072 -ngl 99 -fa on -b 1024 -ub 2048 \
        -t 10 --cache-type-k q8_0 --cache-type-v turbo4 \
        -fit off --no-mmap --jinja \
        --poll 100 --prio 2 --reasoning off -np 1 \
        --spec-type draft-mtp --spec-draft-n-max 2

  # Add additional profiles for other models as needed
Note: The default profile uses -c 65536 (not 131072) to avoid OOM crashes on systems with < 48GB RAM. The large-context profile drops --mlock for the same reason.

OOM Crash Analysis & Fix

What Happens at 131K Context + --mlock on 24GB RAM

ResourceValue at Crash
llama-server anon-RSS19,986 MB (~20 GB)
llama-server shmem-RSS1,183 MB (~1.1 GB)
Total system RAM24 GB
Swap100% full (2 GB, 0 free)
Free RAM at crash~122 MB

The kernel OOM killer selected llama-server (highest RSS). Three interacting causes:

  1. 131K KV cache: q8_0 K cache + turbo4 V cache at 131,072 tokens = 4-6 GB on top of model weights.
  2. --mlock pinned pages: Forces all model pages into resident RAM. Cannot be evicted.
  3. VRAM spillover: Some tensors spill to system RAM. With --mlock, those are pinned too.

Math: 17-18 GB model weights + 4-6 GB KV cache + 1-2 GB overhead = 24+ GB. Zero headroom.

The Fix

FixActionEffect
Context reduction-c 65536 for default profileFrees 2-3 GB KV cache memory
Drop --mlock on large ctxOnly use --mlock with -c 65536Allows OS to manage pages
Add RAM (definitive)+32GB → 56GB totalEliminates OOM at any context

Agent Framework Context Optimization

Token savings per turn by optimizing the agent framework config:

OptimizationTokens Saved
Renamed large AGENTS.md to .bak~18,000
Dropped kanban toolset (12 tools)~6,000
protect_last_n 30 → 12~10,000-15,000
Disabled unused plugins~2,000
Split monolithic config~3,000
Total~39,000-44,000 tokens/turn

Hardware Tier Guide (July 2026 Prices)

BudgetHardwareMax ModelExpected Speed
$800-900Used RTX 3090 24GB35B MoE at Q4150-170 tok/s
$1,500-1,600RTX 4090 24GB35B MoE at Q4180-220 tok/s
$2,500RTX 5090 32GB70B at Q460-80 tok/s
$1,500AMD Ryzen AI Max+ 39570B at Q4 (shared RAM)12-15 tok/s

RAM recommendation: Whatever GPU you choose, get at least 48GB system RAM. 24GB system RAM is not enough for 131K context with --mlock.

Remaining Headroom: The Last 10%

AreaPotentialNotes
WSL2 virtualization overhead5-10%Native Ubuntu could reach 180-187 tok/s
Thread tuning (-t 1 or -t 2)3-8%GPU-bound workloads need fewer CPU threads
KV cache precision (q4_0)Variable10x faster prompt processing, needs quality testing
Draft window (n-max 3-4)0-5%Only if acceptance stays >85%

Read the Full Story

This page is the technical reference. The full tuning diary — with the narrative, the debugging process, and what I'd do differently — is on Medium.

Read on Medium → Get the Toolkit

Use coupon LAUNCH20 for 20% off any premium pack.

All benchmarks measured July 25-26, 2026 · llama.cpp b9971 · Qwen3.6-35B-A3B IQ4_XS · RTX 3090 · CUDA 12.9 · Hermes Agent v0.19.0