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 installed Ollama setup: generation speed, prompt processing, time to first token, cold load time, and run-to-run consistency. Then it tells you if something in your configuration is costing you performance.
Planning toolkit
One command. It walks you through the setup interactively: it detects Ollama, lists your installed models, and asks 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 CPU-only by choice. See the scope notes below for what v1 leaves out.
Generation throughput
How fast the model writes on your hardware. This is 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
Each workload runs several times. Inconsistent numbers are reported as inconsistent rather than averaged into one misleading figure.
Diagnostics
Detects the classic misconfigurations: a model partially offloaded to CPU, a GPU present but unused, or model weights that exceed your card’s VRAM. The proof is below: we broke a setup in two ways and it caught both faults.
Zero network access
The tool talks to your local Ollama endpoint and to nothing else. There is no telemetry, no upload and no update check, not even a stubbed-out one. You can read the source and check.
No composite score
There is no single made-up “score”, no grade, and no asserted target. A failed or invalid run is reported as a failed run, because that result is data too.
Open protocol
Each 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 command above on the two machines we develop on. They are not mockups and not cherry-picked: the slow run and the refusals are the point. Our records have since grown to a full sweep of the 22 models installed on the Linux machine, including runs that ended with no valid figure at all, kept on file as such.
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 about 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 each diagnostic resolving cleanly, 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. Each result file records all three, so you 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 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, pinned to 8 GPU layers, and 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 figure is the median of 5 measured passes after one warmup, generating 512 tokens from a 45-token prompt in a 4,096-token context at temperature 0 (seed 42). These were measured mid-sweep, which reads about 3.6% below an isolated run of the same model on this rig, so compare the three against each other, not against other figures.
Each diagnostic fired on its own failure mode and stayed silent on the other two runs: no false alarms, no misses. That is also the argument for running the benchmark at all. All three configurations work, Ollama answers prompts in each of them, and the screen gives no sign that anything is wrong. The 12.9× gap 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%”. A fair machine-to-machine comparison needs many independent submissions measured under identical rules. The protocol itself requires that before any comparison may be shown, and that corpus does not exist yet. Until it does, your results are a diagnostic of yourmachine, for you.
Scope limits: 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 what happens: the benchmark will run on a Mac and complete (we have done it on our own M1), but v1’s detection cannot see an Apple GPU. The run is mislabelled CPU-only, each 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 properly needs protocol work that has not been done yet, and until it is, a clean-looking Mac result is the one output of this tool you should not take at face value.
That is 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 one). The usual culprits are a leftover model and jumping back in too fast. ollama stop <name> clears a leftover model, and note that a long OLLAMA_KEEP_ALIVE keeps models resident for hours after you last touched them; after unloading, give the GPU a few seconds to settle. If you must run anyway, --quality-override will, and it marks the result JSON as compromised so the shortcut cannot 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 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, so there is 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 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 that: post what your machine measured, attach the JSON (it carries no file paths and nothing personal), and ask what a diagnostic is telling you. Nothing posted there feeds this site’s data. It is somewhere to think out loud, not a collection point.
There is a monthly Cleanest Run challenge too. It turns on the lowest run-to-run variance, which rewards the most carefully measured run rather than the fastest hardware. A modest GPU on a quiet machine can beat a much faster one with a browser left open.
Next steps