Analysis¶
k4Bench writes plain CSV and JSON, so you can analyse results with any tool. The
k4bench.analysis subpackage adds convenience: loaders that return tidy pandas
objects, and Plotly figures for the common views. It's designed for use in a
Jupyter notebook (see JupyterNotebooks/analysis.ipynb) but works anywhere.
Purpose¶
Turn the per-run artifacts in a log directory into DataFrames and publication- ready figures, handling the fiddly bits (type coercion, warmup-event exclusion, schema validation) for you.
The loaders¶
All three live in
k4bench.analysis.loader and take a
log directory plus an optional list of run labels.
load_results(log_dir, labels=None)¶
Concatenates every *_results.csv into one DataFrame (one row per run). Float
columns become float64; integer columns that may contain NaN use pandas'
nullable Int64.
from k4bench.analysis import load_results
df = load_results("logs/ALLEGRO_o1_v03")
df[["label", "wall_time_s", "peak_rss_mb", "events_per_sec"]]
load_event_timing(log_dir, labels=None)¶
Parses each *_events.json (from the event plugin) into a dict[label →
DataFrame] with columns event_number, event_time_s, rss_begin_mb,
rss_end_mb, rss_delta_mb.
from k4bench.analysis import load_event_timing
events = load_event_timing("logs/ALLEGRO_o1_v03")
events["baseline_all"].head()
load_region_timing(log_dir, labels=None)¶
Parses each *_regions.json (region plugin) into a dict[label → dict] with
keys meta, events, at_location, by_birth, and steps. The
at_location / by_birth entries are DataFrames indexed by event_number,
one column per top-level detector (seconds).
from k4bench.analysis import load_region_timing
regions = load_region_timing("logs/ALLEGRO_o1_v03")
regions["baseline_all"]["at_location"].sum().sort_values(ascending=False)
Loaders validate their input
The JSON loaders check for required keys and consistent array lengths, and
raise a ValueError naming the offending file if a schema is malformed.
Missing-file behaviour differs: with explicit labels, a missing file is an
error; with labels=None, only present files are loaded.
The plots¶
All return a plotly.graph_objects.Figure. In Jupyter they render inline; else
call fig.show() or fig.write_html("out.html"). They accept the same
log_dir (and load internally), so you can go straight from a directory to a
figure.
| Function | Shows | Needs |
|---|---|---|
plot_run_overview |
run-level metrics across runs (wall, RSS, ev/s, …) | *_results.csv |
plot_event_timing |
per-event wall time per run | *_events.json |
plot_event_memory |
per-event RSS per run | *_events.json |
plot_region_timing |
per-detector stepping time | *_regions.json |
from k4bench.analysis import (
plot_run_overview, plot_event_timing, plot_event_memory, plot_region_timing,
)
plot_run_overview("logs/ALLEGRO_o1_v03").show()
plot_event_timing("logs/ALLEGRO_o1_v03").show()
plot_region_timing("logs/ALLEGRO_o1_v03").show()
The shared colour palette is exported as k4bench.analysis.plots.PALETTE so
custom plots can match the built-in ones.
Warmup events¶
The first event (event 0) is consistently slower — caches are cold, lazy initialisation happens. By convention the analysis layer and dashboard exclude event 0 when computing summary statistics (mean, median, p95). When you compute your own stats, do the same:
df = events["baseline_all"]
df = df[df["event_number"] != 0] # drop warmup
df["event_time_s"].median()
Typical notebook workflow¶
from k4bench.analysis import load_results, load_event_timing, plot_run_overview
# 1. Load
runs = load_results("logs/ALLEGRO_o1_v03")
events = load_event_timing("logs/ALLEGRO_o1_v03")
# 2. Per-detector cost relative to baseline
base = runs.loc[runs.label == "baseline_all", "wall_time_s"].iloc[0]
runs["delta_wall_s"] = base - runs["wall_time_s"]
# 3. Steady-state per-event time (warmup excluded)
for label, df in events.items():
steady = df[df.event_number != 0]["event_time_s"]
print(f"{label:30s} median {steady.median()*1e3:.1f} ms/event")
# 4. Figure
plot_run_overview("logs/ALLEGRO_o1_v03").write_html("overview.html")
Inputs and outputs¶
- Inputs: a log directory produced by
k4bench(CSV always; event/region JSON only if the plugins ran). - Outputs: pandas DataFrames / dicts and Plotly figures. Nothing is written
unless you call
write_html/write_image.
Failure modes¶
| Symptom | Cause |
|---|---|
ValueError: No *_results.csv files found |
wrong directory, or the run wrote nothing |
ValueError: ... missing keys / mismatched array lengths |
a truncated/corrupt JSON (e.g. ddsim killed mid-write) |
| Empty event/region plots | plugins weren't loaded for that run (check the .log for the NOTE: line) |
See also¶
- Timing plugins — what produces the JSON.
- Dashboard — the same data, hosted and trended over time.
- File formats — the schemas the loaders parse.
analysisAPI.