Real numbers measured on hardware in our lab — by us, not copied from vendor slides — with the exact methodology published below. Last updated 2026-10-09.
Every card below ran the same test model: nemotron-3.5-lightning — a 31B-parameter hybrid-MoE reasoning model (~3.5B active parameters, Q4_K_M quantization, 23.68 GiB on disk), available in the Ollama library. Testing against the same model is what makes your numbers comparable to this table. Decode = tokens generated per second while streaming an answer, single request, model fully resident in VRAM.
| GPU | Host | Serving stack | Decode tok/s |
|---|---|---|---|
| NVIDIA RTX 5090 32GB | desktop, internal PCIe | vLLM / NVFP4 4-bit | 377 |
| NVIDIA RTX 5090 32GB | desktop, internal PCIe | Ollama / CUDA (Q4_K_M GGUF) | ≈240 |
| NVIDIA DGX Spark (GB10, 128GB unified) | DGX Spark | vLLM / NVFP4 4-bit | ≈120 |
| Intel Arc Pro B70 32GB (ASRock) | desktop, internal PCIe | Ollama / Vulkan | 45.5 |
| Intel Arc Pro B70 32GB (ASRock) | mini PC + USB4 eGPU enclosure | Ollama / Vulkan | 40.9 |
| Intel Arc Pro B70 32GB — experimental | desktop, internal PCIe | llama.cpp / SYCL-on-OpenCL | 50.6 |
Warm figures, average of 3 runs, identical prompt. Full environment versions in Methodology (Tools tab).
We put an ASRock Arc Pro B70 32GB in a Razer Core X V2 Thunderbolt/USB4 enclosure, drove it from a Getorli mini PC (AMD Ryzen 7 8745HS, 16GB DDR5) over a single USB4 40 Gb/s cable, and benchmarked it against the same model of card in an ordinary internal PCIe slot — same driver, same Ollama 0.32.15, same model file.
| Internal PCIe slot | USB4 eGPU (40Gb/s) | eGPU cost | |
|---|---|---|---|
| Warm decode | 46.3 / 45.5 / 44.7 tok/s | 40.1 / 40.9 / 41.6 tok/s | −10% |
| Cold model load (25GB, caches dropped) | 11.1 s | 33.4 s | 3× slower |
| Prompt processing | within noise of each other | ≈0 | |
LLM token generation is bound by the GPU’s own memory bandwidth — once the 25GB of weights are in VRAM, each generated token moves only kilobytes across the cable. USB4 tunnels PCIe at roughly 3 GB/s of usable bandwidth (the enclosure’s internal slot negotiated PCIe 4.0 x4), and decode simply doesn’t need it. The ~10% penalty we did measure comes from added latency on the small per-token host↔GPU round-trips — not bandwidth.
Loading the model. Weights stream disk → RAM → USB4 → VRAM, and on our platform the tunnel firmware only granted the card a 256MB CPU-visible window (no Resizable BAR — the mini PC’s BIOS has no Above-4G/ReBAR options, and a kernel-level resize returned -ENOSPC: the USB4 bridge windows are fixed at boot). Result: 25GB squeezes through a 256MB porthole and cold loads take 3× longer. A serving box keeps hot models resident, so this is a once-per-boot cost — but know it exists.
clinfo reports zero platforms even though Vulkan works perfectly. Anything that detects GPUs via OpenCL will think the card doesn’t exist — if your tooling relies on OpenCL detection, add a Vulkan fallback.An eGPU is a perfectly good inference box: ~90% of internal-slot decode, full VRAM usable, and it turns a mini PC into a GPU server. If you’re choosing hardware for a new build, an internal slot is ~10% free performance — but if the machine you have is small and the GPU you have is external, it works.
Same card (internal-slot B70), same llama.cpp build (3f545be), same GGUF file — only the compute backend changed:
| Backend | Prompt (pp512) | Decode (tg128) | Notes |
|---|---|---|---|
| Vulkan (Mesa 25.2.8) | 864 ± 5 t/s | 43.4 ± 0.03 t/s | what Ollama ships; rock solid |
| SYCL over Level-Zero | crash — UR_RESULT_ERROR_UNSUPPORTED_FEATURE (OP SCALE) | Level-Zero path not ready for Battlemage Pro | |
| SYCL over OpenCL | 918 ± 4 t/s (+6%) | 50.6 ± 0.03 t/s (+17%) | ONEAPI_DEVICE_SELECTOR=opencl:gpu |
The headline: +17% decode on the same silicon, free, from a backend switch — if you route SYCL over the OpenCL runtime rather than Level-Zero. Caveats: it requires working OpenCL (so not on small-BAR eGPU setups, see above), and Intel’s IPEX-LLM distribution — the thing most “Ollama on Intel” containers wrap — still fails on Battlemage Pro (its Ollama fork is generations old and its custom XMX kernels assert).
llama-serverOllama has no SYCL backend, so capturing this in production means serving the model with llama-server — llama.cpp’s built-in OpenAI-compatible HTTP server — built with -DGGML_SYCL=ON and launched with ONEAPI_DEVICE_SELECTOR=opencl:gpu. The neat part: llama-server can point directly at the GGUF blob Ollama already downloaded (Ollama’s model blobs are plain GGUF files), so there’s no second copy of a 25GB model. On our internal-slot B70 that turns a 45.5 tok/s Ollama setup into a ≈50 tok/s one — same card, same watts. Trade-offs: one model per llama-server process (Ollama’s multi-model juggling goes away), and you own the systemd unit. Worth it on a dedicated inference box; skip it on a machine that hops between models.
Measured during live inference: the card sits pinned at 2800 MHz — its rated maximum boost — for the entire generation, while drawing ~180W of its 230W budget. It isn’t clock-starved and it isn’t power-throttled; it’s waiting on memory. Linux exposes clock floors/ceilings only up to the rated max, and GDDR memory clocks (the thing that would actually move tok/s) aren’t adjustable on any OS. The performance ladder on Arc is backends (see above), not clocks.
Ollama’s OLLAMA_NUM_PARALLEL=2 verified with two simultaneous streams on an RTX 5090: both completed in 2.43s wall clock where serial execution takes ~3.7s, second stream’s first token in 1.4s. Without the setting, a “2-slot” server quietly queues one request behind the other. And a general tip: if a server dies mid-stream the response truncates silently, so robust clients always check finish_reason.
The DGX Spark (GB10 Grace-Blackwell, 128GB unified memory) earns its keep on efficiency: we benchmarked the NVFP4 4-bit build of nemotron — the format Blackwell accelerates natively — via vLLM. Getting there was not a one-liner, and the traps are worth publishing:
pip install vllm does not produce a working install on GB10 — NVIDIA’s NGC container (nvcr.io/nvidia/vllm) is the only sane route. There is no :latest tag; you have to enumerate tags via the registry API and pick a dated one.xgrammar, but a bare pip install -U xgrammar inside the container upgrades transformers v4→v5 and bricks the whole environment. pip install --no-deps xgrammar is the fix. (We bricked it once so you don’t have to.)--mamba-backend flashinfer among them), the same box serves the same model at ≈120 tok/s.Why bother, when Ollama would have run a generic quant with zero effort? Because a generic 4-bit GGUF on this box throws away the NVFP4 hardware path — we measured the difference as the difference between second-string and first-class results. If your silicon has a native low-precision format, serve that format.
/api/generate, non-streamed; tok/s = eval_count / eval_duration as reported by the runtime. Model resident in VRAM, 3 consecutive runs of the same prompt, all runs shown or averaged as labeled.systemctl restart ollama, then echo 3 > /proc/sys/vm/drop_caches (so the OS page cache can’t hide the storage path), then one 5-token generation; load time = load_duration.llama-bench -p 512 -n 128 -r 3 -ngl 99 on llama.cpp build 3f545be, pointed at the identical GGUF file for every backend. ± figures are llama-bench’s own run variance.50a6c5c (CUDA 13.0 on the head, the RPC backend, a Vulkan build of the same commit for the Intel worker), llama-bench -p 512 -n 128 -r 1 -ngl 99 with every placement given explicitly; single runs, so treat differences under ~3% as noise. Link throughput measured with a 4GB single-stream TCP transfer each way.Nbench is our benchmark as a single free binary. Run it plain for the CLI — or run nbench -ui for a browser panel that shows your detected hardware, lists every model your Ollama already has, streams the run live, and shows the model’s actual answer alongside the number. It — no install, no dependencies, no accounts, and it never phones home. It benchmarks your local Ollama with the exact methodology above (hardware detection, warm decode, model load, and the 2-stream parallel check), so the number it prints is directly comparable to every number on this page. Windows, Linux, and macOS.
| Platform | Install (one line, no admin needed) |
|---|---|
| Linux & macOS | show install command |
| Windows (PowerShell) | show install command |
The installer detects your system, puts nbench on your PATH (Windows also gets a Start Menu shortcut), and never needs administrator rights. Paste it into a terminal (PowerShell on Windows).
For scripted or offline installs — same acceptance applies: linux-amd64 · linux-arm64 · windows · mac-apple-silicon · mac-intel
Installing or downloading requires accepting the as-is/no-warranty terms (one click). Needs a local Ollama. Default model is llama3.2:3b (a ~2GB one-time pull) so anyone can run it; to compare directly against the table above, run -model nemotron-3.5-lightning:latest (a ~25GB pull — needs a card with roughly 26GB+ of free VRAM); benchmark any other model with -model <name>, and -json - emits the full machine-readable result. A community leaderboard — opt-in submission of your score — is coming next.