Local AI measurement tool

Free & open source (MIT)Runs 100% locallyUpdated November 2026

Measure what your machine does with local AI.

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.

Install & run

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

Node.js 20 or newer

The benchmark is a Node CLI. Check with node --version.

Ollama, running

With at least one model pulled. New to Ollama? Start with the Ollama guide.

Windows or Linux

One discrete GPU, or CPU-only by choice. See the scope notes below for what v1 leaves out.

What it measures

Generation throughput

Tokens per second, sustained

How fast the model writes on your hardware. This is the number that decides whether local AI feels usable day to day.

Prefill throughput

Prompt processing speed

How quickly long prompts and pasted documents are read before the first word of the answer appears.

Time to first token

The wait before output starts

Measured from request to the first streamed token, including thinking-style models that reason before they answer.

Cold load

Model startup time

How long the model takes to load from disk into memory the first time you use it.

Variance

Run-to-run consistency

Each workload runs several times. Inconsistent numbers are reported as inconsistent rather than averaged into one misleading figure.

Diagnostics

What is slowing you down

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.

Why you can trust the numbers

Zero network access

No network access at all

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

Separate measurements, reported separately

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

Versioned & public

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.

Real output from our own machines

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

Three runs, hours apart: 143.58 → 138.87 → 143.46 tok/s

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

114.58 tok/s, first token in 166 ms

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

Two runs it refused

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.

We broke the same model twice, and it caught both

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.

ConfigurationGenerationBandwidth ceiling usedWhat the tool reported
Default (fully in VRAM)112.93 tok/s73%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.

What this page leaves out

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.

Questions you will have

Why did the benchmark refuse to run?

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.

How long does a run take?

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.

Where do my results go?

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.

Why is time to first token “unavailable” for my thinking model?

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.

Does it run on my Mac?

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.

Ran it? Bring the result somewhere useful.

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