Node.js 20 or newer
The benchmark is a Node CLI. Check with node --version.
Local AI measurement tool
osai-bench runs a fixed, versioned measurement protocol against your real installed Ollama setup — generation speed, prompt processing, time to first token, cold load time, and run-to-run consistency — then tells you if something about your configuration is quietly costing you performance.
Planning toolkit
One command. It walks you through everything interactively — detecting Ollama, listing your installed models, and asking you to pick one:
npx @opensourcesai/bench
You need
The benchmark is a Node CLI. Check with node --version.
With at least one model pulled. New to Ollama? Start with the Ollama guide.
One discrete GPU, or deliberate CPU-only. See the scope notes below for what v1 leaves out.
Generation throughput
How fast the model actually writes on your hardware — the number that decides whether local AI feels usable day to day.
Prefill throughput
How quickly long prompts and pasted documents are read before the first word of the answer appears.
Time to first token
Measured from request to the first streamed token — including thinking-style models that reason before they answer.
Cold load
How long the model takes to load from disk into memory the first time you use it.
Variance
Every workload runs multiple times. Inconsistent numbers are reported as inconsistent, never averaged into a false single figure.
Diagnostics
Detects the classic misconfigurations: a model partially offloaded to CPU, a GPU present but unused, or model weights that plainly exceed your card’s VRAM. Proof below — we broke a setup on purpose and it caught both faults.
Zero network access
The tool talks to your local Ollama endpoint and nothing else. No telemetry, no upload, no update check — not even stubbed out. You can read the source and verify.
No composite score
There is no single made-up “score”, no grade, and no asserted target. A failed or invalid run is reported as exactly that — a failed run is data.
Open protocol
Every measurement follows the published osai-bench/1.3 protocol, so results stay comparable across time and machines. The spec, source, and real-hardware fixtures are all public.
The first five runs of the published tool, hours after release — fetched from npm with the exact command above, on the two machines we develop on. Not mockups, and not cherry-picked: the slow run and the refusals are the point. Our own records have since grown to a wall-to-wall sweep of the 22 models installed on the Linux machine — including runs that ended with no valid figure at all, kept on file as exactly that.
Repeatability — RTX 4070 Ti, qwen3:4b
The two clean runs agree to 0.08%. The middle run dipped 3% — and flagged itself: its run-to-run variance stamp jumped ~77× (CV 0.024% → 1.84%), the signature of background load. The tool told us which number to trust.
Linux — RTX 3080, qwen3:8b
Generation at 78.8% of the card’s theoretical bandwidth ceiling, with every diagnostic resolving honestly — including one that reports “unavailable” rather than guessing.
The refusals
Before the first clean number, the tool refused two runs: one machine’s GPU was already 15% busy, the other had a leftover model resident in memory. A benchmark that measures anyway would be measuring the interference.
Generation throughput 143.46 tok/s (CV 0.06%) Prefill throughput 9353.02 tok/s (CV 0.18%) Time to first token 199.11 ms (CV 1.13%) Cold load time 2.06 s Pass failure rate 0.00% (0/16 scheduled measured passes)
Measured 2026-08-01 with bench 0.10.0 on Ollama 0.32.5, protocol osai-bench/1.3, scoring osai-bench-derive/1.3 — every result file records all three, so you always know which rules produced a number. These numbers describe each machine on its own terms: the two setups run different models under different runtime settings, and they deliberately cannot be lined up against each other.
The diagnostics card above is a claim, so here is its test. During a full-catalog sweep on our Linux rig (RTX 3080 10 GB, bench 0.10.0, 2026-08-03) we ran the identical llama3.1:8b Q4_K_M three ways: untouched, deliberately pinned to 8 GPU layers, and deliberately forced onto the CPU. Same weights, same session, same machine — the only variable is the misconfiguration.
| Configuration | Generation | Bandwidth ceiling used | What the tool reported |
|---|---|---|---|
| Default — fully in VRAM | 112.93 tok/s | 73% | No issues detected |
num_gpu 8 — partial offload | 8.76 tok/s (12.9× slower) | 5.7% | partial-cpu-offload: detected — only 29% of the model in VRAM |
num_gpu 0 — CPU-only | 6.12 tok/s (18.5× slower) | 4.0% | cpu-only-with-gpu: detected — a working GPU sitting idle |
Each diagnostic fired on exactly its own failure mode and stayed silent on the other two runs — no false alarms, no misses. And this is the quiet argument for running the benchmark at all: all three configurations work. Ollama answers prompts in every one of them, and nothing on screen looks broken. The 12.9× is invisible until something measures it. All three numbers come from the same machine in the same session; they say nothing about how this card compares to yours, and they are not meant to.
No leaderboards, no percentiles, no “your PC ranks better than X%”. Honest machine-to-machine comparison needs many independent submissions measured under identical rules — the protocol itself demands that before any comparison may be shown, and that corpus does not exist yet. Until it does, your results are what they honestly are: a precise diagnostic of your machine, for you.
Scope limits, stated plainly: protocol v1 covers one discrete GPU or CPU-only execution on Windows and Linux. A second GPU is caught by the preconditions and refused. Apple Silicon is the sharper edge, so here is exactly what happens: the benchmark will run on a Mac and complete — we’ve done it on our own M1 — but v1’s detection cannot see an Apple GPU, so the run is silently mislabelled CPU-only, every placement diagnostic returns not-applicable, no bandwidth ceiling gets computed, and nothing in the output warns you. Treat any number produced on a Mac as outside the protocol: measuring unified memory honestly needs protocol work that hasn’t been done yet, and until it is, a clean-looking Mac result is the one output of this tool you shouldn’t take at face value.
That’s the run-quality guard doing its job. It refuses when anything could contaminate the measurement: the GPU already above 10% utilization, non-Ollama processes holding more than a token amount of GPU memory, a different model still resident, or more than one GPU (v1 measures exactly one). The usual culprits are a leftover model — ollama stop <name> clears it, and note that a long OLLAMA_KEEP_ALIVE keeps models resident for hours after you last touched them — and jumping back in too fast: give the GPU a few seconds to settle after unloading. If you must run anyway, --quality-override will — and permanently marks the result JSON as compromised, so the shortcut can’t be laundered out later.
Under a minute is typical when the model fits in VRAM. Misconfiguration stretches it far more than model size does — our worst real case, a 31B model split across GPU and CPU on a 10 GB card, took about half an hour. The tool prints an estimate up front and revises it once, live, when the first real measurements show what your hardware actually delivers.
A single JSON file — osai-bench-result-<timestamp>.json — in the directory you ran it from, and nowhere else. Nothing is uploaded. Useful flags: --model selects a model non-interactively, --output picks the path (it refuses to overwrite an existing file), and --memory-bandwidth supplies the figure by hand if your GPU is missing from the built-in bandwidth table.
Reasoning models can spend the entire measured budget thinking, and Ollama discards that reasoning server-side — there is genuinely no first token to time. The tool reports the metric as unavailable instead of inventing one; since 0.11.0 it also records how many passes withheld output and reports a separate time-to-first-visible-token figure from the long-form workload, which answers the question you were probably asking.
It will run and complete — and that is exactly the problem. See the scope section above: v1 cannot see Apple GPUs, so a Mac result carries no diagnostics, no bandwidth ceiling, and no warning that anything is missing. Treat Mac numbers as outside the protocol.
A result file is worth more with someone to read it with — especially a strange one. Our Discord has a #bench-results channel for exactly that: post what your machine measured, attach the JSON (it carries no file paths and nothing personal, by design), and ask what a diagnostic is actually telling you. Nothing posted there feeds this site’s data — it’s somewhere to think out loud, not a collection point.
There’s a monthly Cleanest Run challenge running too, and it turns on the lowest run-to-run variance — the most carefully measured run, not the fastest hardware. A modest GPU on a quiet machine can win it outright against a much faster one with a browser left open.
Next steps