ubq 4.0.0

Lock-free unbounded MPMC queue backed by a linked ring of fixed-size blocks.
Documentation
#!/usr/bin/env python

import argparse
import shlex
import subprocess
import sys
from pathlib import Path


SCRIPT_DIR = Path(__file__).resolve().parent
REPO_ROOT = SCRIPT_DIR.parent


def collect_run_jsons(runs_dir: Path):
    if not runs_dir.exists():
        return []

    return sorted(path for path in runs_dir.rglob("*.json") if path.is_file())


def resolve_plot_python() -> str:
    current_python = Path(sys.executable).resolve()
    venv_candidates = (
        REPO_ROOT / ".venv" / "bin" / "python",
        REPO_ROOT / ".venv" / "Scripts" / "python.exe",
    )

    for candidate in venv_candidates:
        if not candidate.is_file():
            continue
        resolved_candidate = candidate.resolve()
        if resolved_candidate == current_python:
            return str(candidate)
        return str(candidate)

    return sys.executable


def main() -> int:
    parser = argparse.ArgumentParser(
        description=(
            "Collect all benchmark JSON files under a runs directory tree and generate "
            "per-machine CSV/PNG outputs via scripts/plot_bench.py."
        )
    )
    parser.add_argument(
        "--runs-dir",
        default="bench_results/runs",
        help="Root directory containing machine/scenario/label run folders (default: bench_results/runs)",
    )
    parser.add_argument(
        "--out-dir",
        default="bench_results/plots",
        help="Output root for generated CSV/PNG artifacts (default: bench_results/plots)",
    )
    parser.add_argument(
        "--error-bars",
        choices=["sem", "stddev", "none"],
        default="sem",
        help="Error bar mode forwarded to plot_bench.py (default: sem)",
    )
    parser.add_argument(
        "--dry-run",
        action="store_true",
        help="Print the plot command without running it.",
    )
    parser.add_argument(
        "--no-clean",
        action="store_true",
        help="Pass through to plot_bench.py to keep pre-existing output files.",
    )
    parser.add_argument(
        "--max-line-series",
        type=int,
        default=10,
        help="Maximum configs shown in per-machine scenario line charts; <=0 shows all (default: 10)",
    )
    args = parser.parse_args()

    runs_dir = Path(args.runs_dir)
    out_dir = Path(args.out_dir)
    if not collect_run_jsons(runs_dir):
        print(f"No benchmark JSON files found under: {runs_dir}")
        return 1

    plot_python = resolve_plot_python()
    cmd = [
        plot_python,
        str(REPO_ROOT / "scripts" / "plot_bench.py"),
        "--runs-dir",
        str(runs_dir),
        "--out-dir",
        str(out_dir),
        "--error-bars",
        args.error_bars,
        "--max-line-series",
        str(args.max_line_series),
    ]
    if args.no_clean:
        cmd.append("--no-clean")
    print(f"Plot command: {shlex.join(cmd)}")

    if args.dry_run:
        return 0

    subprocess.run(cmd, check=True, cwd=REPO_ROOT)
    return 0


if __name__ == "__main__":
    sys.exit(main())