bencher.render

Out-of-process rendering for benchmark results.

This module is the render half of bencher’s collect/render split. The collect half (bencher.Bench.collect(), i.e. plot_sweep(auto_plot=False)) runs a sweep and computes regression detection without building any holoviews/panel/bokeh objects, returning a fully-populated BenchResult.

Why split: holoviews/panel/bokeh build large object graphs backed by C-extension wrappers (param, pandas, bokeh). When CPython’s cyclic garbage collector traverses those wrappers while foreign live C-extension state exists in the same interpreter (e.g. ROS 2 rclpy/DDS), the process can segfault. Rendering from a persisted result in a separate, clean process (one that never imported the foreign extension) makes that class of crash impossible by construction.

Typical usage:

# Process 1 — holds rclpy/DDS; never builds plots:
res = bench.collect(...)            # auto_plot=False under the hood
bencher.save_result(res, "result.pkl")

# Process 2 — clean (only imports bencher), e.g. spawned via:
#   python -m bencher.render result.pkl output_dir
bencher.render_report("result.pkl", "output_dir")

render_report is also importable for in-process use when isolation is not required.

Attributes

logger

Functions

save_result(→ pathlib.Path)

Persist a collected BenchResult to path via pickle.

load_result(→ bencher.results.bench_result.BenchResult)

Load a BenchResult previously written by save_result().

render_report(→ pathlib.Path)

Render a collected result to an HTML report.

main(→ int)

CLI entrypoint: python -m bencher.render <result_path> <output_dir>.

Module Contents

bencher.render.logger
bencher.render.save_result(bench_res: bencher.results.bench_result.BenchResult, path: str | pathlib.Path) pathlib.Path

Persist a collected BenchResult to path via pickle.

Mirrors how bencher already caches results internally: the (potentially non-pickleable) object_index is stripped before writing and restored afterwards, so the live object is unchanged.

Parameters:
  • bench_res – A result from Bench.collect() / plot_sweep.

  • path – Destination file path.

Returns:

The path written.

bencher.render.load_result(path: str | pathlib.Path) bencher.results.bench_result.BenchResult

Load a BenchResult previously written by save_result().

bencher.render.render_report(result_or_path: bencher.results.bench_result.BenchResult | str | pathlib.Path, output_dir: str | pathlib.Path, *, report: bencher.bench_report.BenchReport | None = None, filename: str | None = None, in_html_folder: bool = False, portable: bool = False) pathlib.Path

Render a collected result to an HTML report.

Reconstructs the holoviews/panel report from a result produced by Bench.collect() (or a path to one saved with save_result()) and writes it under output_dir. This is the only step that constructs plotting objects, and it is designed to run in a process free of foreign C-extension state.

The result already carries its regression_report (computed during collection), so no sweep re-execution happens here.

Parameters:
  • result_or_path – A BenchResult, or a path to a saved one.

  • output_dir – Directory to write the report into.

  • report – An existing BenchReport to append to. A new one is created (named after the benchmark) when omitted.

  • filename – Output HTML filename. Defaults to <bench_name>.html.

  • in_html_folder – Forwarded to BenchReport.save().

  • portable – Forwarded to BenchReport.save() (base64-inline assets).

Returns:

The path to the saved report.

bencher.render.main(argv: list[str] | None = None) int

CLI entrypoint: python -m bencher.render <result_path> <output_dir>.