(std bench store)

Reference

Overview

Benchmark runs as data: written to a file and read back, and compared, with a saved run or in A/B rounds.

(import (std bench store))

(match (read-saved-run "base.bjodat")
  ((Ok saved) (compare-runs saved this-run 0.05 0.02))
  ((Err why) (println why)))

What --save FILE, --compare FILE and bjo bench --against are made of. (std bench) measures and prints; this module knows runs only as data, so that the two do not import each other.

The file is one bjodat form, a case to a line, so that a diff of two saved runs says which cases changed:

(bench-run
  (version 1)
  (saved "2026-10-16T12:00:00Z")
  (machine "95c59c6948245e2e")
  (header (build "Release") (dotnet ".NET 10.0.4") (cpu "...") ...)
  (case (name "sort") (labels ("n" "1000")) (k 512) (once #f) (bytes 0.0) (samples [41213.0 ...])))

Every sample is kept, in nanoseconds per call and in the order taken, rather than a summary: a comparison needs the distribution.

A comparison reports, per case, the change in the median, its 95% interval, a p-value corrected for the number of comparisons by Holm’s method, and a verdict. The verdict is Faster or Slower only when the corrected p is below the level and the change is larger than the threshold; a real change smaller than the threshold is SmallChange.

A comparison with a saved run is unpaired, and treats the samples of each run as independent. Two processes of one program can differ by more than a threshold of 2%, so such a comparison can call a difference between processes a change; compare-paired with several process pairs measures that difference instead.

See also: SavedRun, write-saved-run!, read-saved-run, compare-runs, compare-paired

Reference

Types

Functions

Types

SavedCase

record ↑ Types

One benchmark at one combination of its parameters, as a saved run keeps it.

name
The benchmark's name.
labels
Its parameters, name and value, as the report shows them.
k
The calls in each sample.
once
#t for a benchmark of single cold runs.
bytes
Bytes allocated per call.
samples
Nanoseconds per call, in the order the samples were taken.

See also: SavedRun, case-key

SavedRun

record ↑ Types

A benchmark run: when and where it was taken, and its cases.

saved
When it was saved: UTC, ISO 8601, to the second.
machine
The machine key: a hash of the CPU, the core count, the memory and the operating system.
header
The facts of the machine and the build, by name: build, dotnet, arch, cores, gc-server, cpu, os and governor.
cases
What was measured.

See also: SavedCase, write-saved-run!, compare-runs

Verdict

union ↑ Types

What a comparison concludes about one case.

Faster
Significant after the correction, and faster by more than the threshold.
Slower
Significant after the correction, and slower by more than the threshold.
SmallChange
Significant, and smaller than the threshold: there, and decided not to matter.
NoChange
Not significant.

See also: Comparison

Comparison

record ↑ Types

One case compared: the medians, the change and its interval, the p-values and the verdict.

name
The benchmark's name.
labels
Its parameters.
was
The median per call of the earlier side, A or the saved run, in nanoseconds.
now
The median per call of the later side, B or this run.
change
The ratio of now to was, less one: 0.05 is 5% slower.
lo
The low end of the change's 95% interval.
hi
The high end.
p-raw
The p-value as the test gave it.
p
The p-value corrected by Holm's method for the comparisons of the run.
verdict
What it comes to, with the run's level and threshold.
spread
With several process pairs, the standard deviation of their log ratios; -1 when it was not measured.

See also: CompareResult, Verdict

CompareResult

record ↑ Types

Two runs compared.

comparisons
The cases both have, compared, in the later run's order.
only-now
The keys of the cases only the later side has.
only-saved
The keys of the cases only the earlier side has.
warnings
The facts of the two runs that differ and move times: the build, the .NET version, server GC, the governor.
other-machine
#t when the machine keys differ: the numbers mean little and no verdict is to be believed.

See also: compare-runs, compare-paired

PairedCase

record ↑ Types

One case of an A/B run: each process pair’s samples of A and of B, a sample of each a round.

name
The benchmark's name.
labels
Its parameters.
a
For each process pair, A's nanoseconds per call in the order of the rounds.
b
The same for B, round for round.

See also: compare-paired

Functions

case-key

function ↑ Functions

(: case-key (-> SavedCase string))
(case-key c)

What a case is known by across runs: its name and parameters, as the report shows them.

c
The case.
returns
"sort n=1000 order=random", or the name alone without parameters.

saved-run->string

function ↑ Functions

(: saved-run->string (-> SavedRun string))
(saved-run->string r)

The text of a saved run: one (bench-run …) form, a case to a line.

r
The run.
returns
The text, ending in a newline.

See also: parse-saved-run, write-saved-run!

parse-saved-run

function ↑ Functions

(: parse-saved-run (-> string (Result string SavedRun)))
(parse-saved-run text)

Reads a saved run from its text.

text
The text.
returns
The run, or what is wrong with the text: not bjodat, not a (bench-run ...), a newer version of the format, or a case that lacks something.

See also: saved-run->string, read-saved-run

write-saved-run!

function ↑ Functions

(: write-saved-run! (-> string SavedRun void))
(write-saved-run! path r)

Writes a run to a file, replacing what was there.

path
The file.
r
The run.

See also: read-saved-run

read-saved-run

function ↑ Functions

(: read-saved-run (-> string (Result string SavedRun)))
(read-saved-run path)

Reads the run saved in a file.

path
The file.
returns
The run, or a sentence saying what is wrong: no such file, unreadable, or not a saved run.

See also: write-saved-run!, compare-runs

compare-runs

function ↑ Functions

(: compare-runs (-> SavedRun SavedRun double double CompareResult))
(compare-runs saved now alpha threshold)

A run compared with a saved one, case by case: unpaired, by the Mann-Whitney U test and a bootstrap of the ratio of the medians.

saved
The earlier run.
now
The later run.
alpha
The significance level of a verdict: 0.05.
threshold
The smallest change a verdict counts, as a fraction: 0.02.
returns
The comparison.

See also: compare-paired, CompareResult

compare-paired

function ↑ Functions

(: compare-paired (-> (List PairedCase) (List string) (List string) double double CompareResult))
(compare-paired cases only-a only-b alpha threshold)

An A/B run compared, A as was and B as now, paired by round or by process pair.

cases
The cases both sides have.
only-a
The keys of the cases only A has.
only-b
The keys of the cases only B has.
alpha
The significance level of a verdict.
threshold
The smallest change a verdict counts, as a fraction.
returns
The comparison.

With one process pair, the rounds are the pairs: the Wilcoxon signed-rank test on each round’s log ratio, and the paired bootstrap. A drift that moved both of a round’s samples moves neither. What it cannot see is a difference between the two processes as a whole.

With several, each pair gives one ratio of medians, and the test is a t-test on their logs, with a t-interval: the difference between processes is then in the test, and its size is spread.

See also: compare-runs, PairedCase