Data contract#
asv-tachyon is a static shell over the tree asv publish already writes.
Adapters (pytest-benchmark exporters, custom CI publishers, alternate runners)
only need to emit the same shapes. No server-side API, no second result format.
Layout#
html_dir/
index.json # required — project atlas
graphs/ # required — one JSON series per bench × env
<param-key>-<value>/.../<benchmark>.json
regressions.json # optional — regression feed
regressions.xml # optional — Atom feed (stock ASV; ignored by UI)
info.json # optional — publish metadata
profiles.json # optional — Explore "Open profile" links
profiles/ # optional — static HTML artifacts referenced above
tachyon/ # from asv_bench_tachyon
memray/ # from asv_bench_memray
asv-tachyon serve html_dir overlays the SPA shell (index.html +
assets/) while every *.json / graphs/** path is still read from
html_dir.
index.json#
Top-level keys the UI reads:
Key |
Role |
|---|---|
|
Display name |
|
Optional project link |
|
Optional commit URL prefix (hash is appended) |
|
Short-hash width (default 8) |
|
Map |
|
Map |
|
Matrix axes: |
|
Concrete env states (cartesian subset actually published) |
|
Machine facts keyed by machine name |
|
Optional |
|
Map of benchmark name → metadata (see below) |
Benchmark metadata (benchmarks[name]):
name— full name (same as key)type—time/memory/peakmemory/track/ …unit—seconds,bytes, or a free-form unitparams— list of parameter axes; each axis is a list of string valuesparam_names— parallel list of axis namescode— optional source snippet shown in Explore
Example (truncated):
{
"project": "asv-demo",
"hash_length": 8,
"revision_to_hash": { "1": "abc…", "2": "def…" },
"revision_to_date": { "1": 1700086400000, "2": 1700172800000 },
"params": {
"branch": ["main"],
"machine": ["cheetah"],
"python": ["3.12", "3.13"]
},
"graph_param_list": [
{"branch": "main", "machine": "cheetah", "python": "3.12"},
{"branch": "main", "machine": "cheetah", "python": "3.13"}
],
"machines": {
"cheetah": {"arch": "x86_64", "cpu": "Ryzen 9", "os": "Linux", "ram": "64GB"}
},
"tags": {},
"benchmarks": {
"time_sort": {
"name": "time_sort",
"type": "time",
"unit": "seconds",
"params": [],
"param_names": [],
"code": "def time_sort():\n …\n"
},
"time_keys": {
"name": "time_keys",
"type": "time",
"unit": "seconds",
"params": [["10", "100", "1000"]],
"param_names": ["n"]
}
}
}
Graph path convention#
For each entry in graph_param_list and each benchmark name, publish:
graphs/<axis>-<value>/…/<benchmark>.json
Rules (mirrors stock ASV Graph.path):
One directory segment per
(axis, value)pair:{axis}-{value}.Segments are sorted alphabetically by the full segment string.
Filename is the sanitized benchmark name +
.json.Characters
<>:"/\|?*and control chars in names/values become_.
Example for branch=main, machine=cheetah, python=3.12,
benchmark time_sort:
graphs/branch-main/machine-cheetah/python-3.12/time_sort.json
Graph JSON shape#
A graph file is a JSON array of [revision, value] points:
revision— integer key present inrevision_to_hashvalue— one of:null— missing / failednumber — scalar result (no benchmark params, or a single series)
array of numbers/null — one entry per flat param combination
Parameter flattening matches ASV: for params = [["10","100","1000"]]
(one axis n), the value array has length 3 with indices 0→n=10,
1→n=100, 2→n=1000. Multi-axis params are a row-major cartesian
product; the last axis varies fastest.
Example scalar series:
[[1, 1.2e-5], [2, 1.21e-5], [3, null], [4, 1.19e-5]]
Example multi-param series (n ∈ {10,100,1000}):
[
[1, [1.0e-6, 1.0e-5, 1.0e-4]],
[2, [1.01e-6, 1.01e-5, 1.01e-4]]
]
regressions.json#
Optional. Written by ASV’s regressions publisher. Top-level:
{ "regressions": [ entry, … ] }
Each entry is a 7-tuple:
[
entry_name, # str — benchmark name, may include "(param=…)" suffix
graph_path, # str — path to the graph JSON (may be relative)
graph_params, # object — subset of env axes that vary (or all used)
param_idx, # int|null — flat param index, or null if scalar
last_value, # number — latest measured value
best_value, # number — best value after the detected step
jumps # list of [rev_before|null, rev_after, value_before, value_after]
]
factor for display is last_value / best_value (higher means a larger
regression for lower-is-better metrics). The UI filters by a user-controlled
threshold on that factor and links each row into Explore with the env filters
and param index applied.
Example:
{
"regressions": [
[
"time_sort",
"graphs/branch-main/machine-cheetah/python-3.12/time_sort.json",
{"branch": "main", "machine": "cheetah", "python": "3.12"},
null,
1.74e-05,
1.2e-05,
[[20, 21, 1.25e-05, 1.74e-05]]
]
]
}
profiles.json (optional sidecar)#
asv-tachyon Explore shows an Open profile link when a key matches the
selected benchmark (prefer bench@rev, fall back to bare bench).
Producers are the metric plugins, not this UI package:
asv_bench_tachyon—sample_*metrics + Tachyon flamegraph HTMLasv_bench_memray—ray_*peak memory + memray HTML
Typical flow:
ASV_BENCH_TACHYON_PROFILE=1 asv run --bench sample_
ASV_BENCH_MEMRAY_PROFILE=1 asv run --bench ray_
asv publish
python -m asv_bench_tachyon profiles publish --html-dir .asv/html
python -m asv_bench_memray profiles publish --html-dir .asv/html
asv-tachyon serve .asv/html --open
Shape:
{
"paths": {
"sample_hot_path@30": "profiles/tachyon/sample_hot_path.html",
"sample_hot_path": "profiles/tachyon/sample_hot_path.html",
"ray_alloc@30": "profiles/memray/ray_alloc.html"
}
}
Paths are relative to html_dir and must be fetchable as static files.
Both plugins merge into the same profiles.json (last publish wins on
duplicate keys).
Adapter checklist (pytest-benchmark, etc.)#
Emit
index.jsonwith at leastproject,revision_to_hash,revision_to_date,params,graph_param_list,benchmarks.For every
graph_param_listentry × benchmark, write the graph JSON at the path convention above.Use revision integers consistently across
revision_to_*and graph points.Prefer string param values (ASV stores them as strings in
benchmarks[name].params).Optionally emit
regressions.jsonin the 7-tuple form above.Point
asv-tachyon serveat the directory — no further conversion.
The repository ships fixtures/sample_site/ as a minimal valid tree.