Benchmarking & Diagnostics
Tools for benchmarking and diagnosing failures, covering both the core Rust engine and the Python bindings.
The Tooling Stack
Strict boundaries between measurement tools, to avoid the "Observer Effect" (see Tier 2). Three tiers measure Locus itself; a comparative tier measures it against other detectors.
Comparative tier: cargo xtask sota (published comparisons)
- Tool:
cargo xtask sota(xtask/README.md). - Purpose: Reproducible comparison against pinned references — OpenCV
aruco4.10.0 (three corner refiners), aruco_nano961b18b, AprilTag 3 — on every dataset they can decode (Liu4K, EuRoC, ICRA 2020, the render-tag and board suites). It reports recall, precision, F1, order-preserving and debiased corner error, and latency, and ends with a win table;cargo xtask sota scoreboardaggregates every scored benchmark. - Rule: Any published "Locus vs X" number comes from this tool. Publish latency only from
--jobs 1runs on an idle machine. The Python sweep tools (bench sweep/tune/compare-instances) use the unpinnedopencv-pythonwheel from thebenchgroup and are for exploration, not publication.
Tier 1: End-to-End Regression (The Python CLI)
- Tool:
uv run tools/cli.py bench real(ICRA 2020 scenarios or Hugging Face Hub datasets via--hub-config). - Purpose: Measures the true wall-clock time from Python memory ingestion, through the FFI boundary, across the Rust math kernels, and back to Python. Also reports recall and pose error (translation RMSE in metres) when ground truth poses are available.
- Rule: This is the ultimate ground truth for latency. If a micro-optimization doesn't lower this number, it didn't actually work.
Tier 2: Macro-Profiling (Tracy)
- Tool:
tracing-tracycombined with the Tracy GUI profiler (cargo test --features tracy). - Purpose: Identifies which pipeline stage is the bottleneck (e.g., proving that
decode_batch_soais taking 10ms whileextract_quadsis taking 2ms). - Rule: Never run Tracy concurrently with JSON loggers or console formatters. The string allocation overhead will pollute the nanosecond lock-free ring buffers.
Tier 3: Micro-Benchmarking (Divan)
- Tool:
cargo benchusing the Divan framework incrates/locus-core/benches/. - Purpose: Measures the Instructions Per Clock (IPC) and L1 cache utilization of isolated, single-threaded mathematical kernels (like SIMD bilinear sampling).
- Rule: Run these strictly single-threaded to prevent the OS scheduler or Rayon from thrashing the L1 cache.
Rust Benchmarking (Core Engine)
Source of truth for core engine performance and regressions.
Dataset provisioning
Every external dataset (Hub render suites, ICRA 2020, EuRoC, Liu4K) is pinned in xtask/datasets.toml and fetched into tests/data/ with cargo xtask data:
cargo xtask data list # what exists, where, licence
cargo xtask data fetch icra2020-forward icra2020-circle
cargo xtask data fetch euroc liu4k # EuRoC mirror needs `hf auth login` or HF_TOKEN
cargo xtask data fetch hub --subsets all
cargo xtask data verify # missing or stale-pin copies -> exit 1
Rust tests and Python loaders read the same tests/data/ paths. LOCUS_ICRA_DATASET_DIR, LOCUS_EUROC_DATASET_DIR and LOCUS_HUB_DATASET_DIR only relocate a dataset — except that the render-tag and distortion Hub suites still require LOCUS_HUB_DATASET_DIR to be set (they skip otherwise).
Regression Suite (ICRA 2020)
- Fetch the dataset:
cargo xtask data fetch icra2020-forward(plusicra2020-circle/icra2020-randomfor the extended run). - Run Benchmarks:
# Core check (Forward dataset + Fixtures, approx 15s) cargo test --release --test regression_icra2020 --features bench-internals # Extended check (Circle, Random, Rotation, approx 1-2 mins) LOCUS_EXTENDED_REGRESSION=1 cargo test --release --test regression_icra2020 --features bench-internals # Accurate latency measurement (sequential) cargo test --release --test regression_icra2020 --features bench-internals -- --test-threads=1[!IMPORTANT]
--releaseis mandatory for runningregression_icra2020tests. Running in debug mode is blocked and will panic.
Hub Regression Suite (Hugging Face)
[!IMPORTANT]
--releaseis mandatory for running Hub regression tests. Running in debug mode is extremely slow and will likely timeout in CI or developer environments.
-
Synchronize Data: Download Hub subsets to the local cache (
tests/data/hub_cache/) at the revision pinned inxtask/datasets.toml(cargo xtask data listshows every dataset). With no--subsetsthe manifest's default render-tag set is fetched;alldiscovers every config:Or sync specific subsets:cargo xtask data fetch hub --subsets allcargo xtask data fetch hub --subsets \ locus_v1_tag36h11_640x480,locus_v1_tag36h11_1280x720,locus_v1_tag36h11_1920x1080,\ locus_v1_tag36h11_3840x2160,charuco_golden_v1_1920x1080,aprilgrid_golden_v1_1920x1080 -
Run Hub Tests:
# Tag-level regression (regression_render_tag) # Covers the 4-resolution `high_accuracy` baseline plus quad-extraction variants # (EdLines with None refinement, moments culling) at 720p/1080p. # Requires LOCUS_HUB_DATASET_DIR to locate the cache. LOCUS_HUB_DATASET_DIR=tests/data/hub_cache \ cargo test --release --test regression_render_tag --features bench-internals -- --nocapture # Board-level regression (regression_board_hub) # Validates ChAruco and AprilGrid golden datasets. # Uses workspace-relative tests/data/hub_cache/ automatically — no env var needed. cargo test --release --test regression_board_hub --features bench-internals -- --nocapture
Logic-Specific Benchs (Micro-benchmarking)
For fine-grained benchmarking of specific components, we use Divan. These are located in crates/locus-core/benches.
# Run all micro-benchmarks
cargo bench
# Run specific micro-benchmark (e.g., real-world data)
cargo bench --bench real_data_bench
cargo bench --bench decoding_real_bench
Mutually Exclusive Telemetry Matrix
Emitting structured JSON logs and capturing high-fidelity Tracy profiles simultaneously skews the nanosecond timings (JSON serialization pollutes Tracy's ring buffers). TELEMETRY_MODE decouples them.
Human Mode (Tracy)
Captures pristine binary traces for GUI analysis.
# Tracy client is assumed to be running or capturing headlessly
TRACY_NO_INVARIANT_CHECK=1 TELEMETRY_MODE=tracy cargo test --release --test regression_icra2020 --features tracy,bench-internals -- --test-threads=1
Agent/CI Mode (JSON)
Dumps structured pipeline timings to target/profiling/*_events.json for AI analysis and automated regression tracking.
TELEMETRY_MODE=json cargo test --release --test regression_icra2020 --features bench-internals -- --test-threads=1
Performance Reports
Methodology & durable learnings
- Engineering Lessons — distilled investigation conclusions (pose covariance, rotation tail & edge refinement, EdLines, recall/quad/ICRA): what was tried, what shipped, what was falsified
- Benchmarking Lessons — consolidated timeline + architecture/profile/algorithm tradeoffs that should inform future work
- Micro-Benchmarking Guide — 3-tier validation loop
Point-in-time reports (historical snapshots)
The two 2026-10-04 reports describe the current standard pipeline; the rest are history.
- EuRoC, the real-data benchmark (2026-10-04) — latest. Scorer fixes, 4-connectivity, clipped and gross corners: EuRoC recall 20.9 → 86.0 %, 65/93 cells vs
main57/93; latency +17–28 % - SOTA scoreboard checkpoint (2026-10-04) — latest for corner metrics. Fused + photometrically calibrated corners (#434): 52/73 vs
main47/73; render-tag corners ≈ 3.7× better than the best reference - SOTA scoreboard checkpoint (2026-10-03) —
maina6199d4, opt-in decode-first candidate (37/88) vsstandard(32/88), 1T and 8T latency - SOTA scoreboard baseline (2026-10-02) —
standardvs the best OpenCV / aruco_nano operating point on every compatible dataset;cargo xtask sota scoreboard - Real-image competitiveness: Liu4K + EuRoC (2026-10-01) — reproduce with
cargo xtask sota(xtask/README.md) - Render-tag 1080p SOTA (2026-07-13, v0.7.0-refreshed) — single-tag pose percentiles; predates decode-first, 4-connectivity and the corner stage
- Render-tag 2160p recall lift (2026-04-25)
- Render-tag 1080p SOTA pursuit (2026-04-25)
- Release Performance Report (2026-04-18)
Python Developer CLI
tools/cli.py is the central entry point for high-level evaluations and development tasks.
Data Preparation
Use cargo xtask data fetch … (see Dataset provisioning). tools/cli.py bench prepare is a thin wrapper over the same pinned manifest (ICRA forward + circle and every Hub config).
Real-World Evaluation (ICRA 2020)
Evaluate performance on the ICRA 2020 dataset scenarios (forward, circle):
# Basic run on Locus
PYTHONPATH=. uv run --group bench tools/cli.py bench real --scenarios forward
# Compare against OpenCV and AprilTag 3
PYTHONPATH=. uv run --group bench tools/cli.py bench real --scenarios forward --compare
Real-World Evaluation (Liu4K)
Liu4K is a 924-image, roughly 4K real-photo ArUco set released with the aruco_nano paper. Ground truth is per-marker corners and ids only (no poses, no intrinsics), so the CLI reports quad recall and, with the matching dictionary, id-aware decode recall/precision. No pose numbers are produced, so the Fast/Accurate pose-mode rule does not apply.
# Quad recall (id-agnostic; accepted + decoder-rejected quads within 10 px of a GT centre)
PYTHONPATH=. uv run --group bench tools/cli.py bench real --dataset liu4k
# Adds id-aware decode TP/FP/FN, recall, precision, F1 (markers use ARUCO_MIP_36h12)
PYTHONPATH=. uv run --group bench tools/cli.py bench real --dataset liu4k --family ArUcoMip36h12
# Variant: sharpening off (the LocalMean (opt-in) threshold variants are analysed in the real-image snapshot)
PYTHONPATH=. uv run --group bench tools/cli.py bench real --dataset liu4k --family ArUcoMip36h12 --no-sharpening
The scorer mirrors aruco_nano's testperf.cpp: for each detection, the first unmatched GT marker with
the same id and a centre distance <= 10 px makes it a TP, otherwise it is a FP; FN = GT - TP. The
10 px radius is the Liu4K-specific LIU4K_MATCH_THRESHOLD_PX (tools/bench/liu4k.py); the repo-wide
MATCH_DISTANCE_THRESHOLD_PX is untouched. Results and analysis:
real-image competitiveness snapshot.
Corner error. bench real --dataset liu4k does not report it. cargo xtask sota run liu4k
does: detections are paired with GT markers by id, the GT corner winding (opposite to
Locus/OpenCV) is remapped by one fixed relabelling, the error stays order-preserving, and the
judged cell is the debiased median on tags every detector found (each detector's mean radial
offset is removed and reported separately). Current numbers:
2026-10-04 scoreboard.
cargo xtask data fetch liu4k downloads liu4k.zip (about 4 GB) from Zenodo into
tests/data/liu4k/ (gitignored), verifies its md5 (e8fafe5444a9e346f25123151ef1a699, from the
Zenodo record), extracts it and deletes the archive; the bench CLI fetches it the same way on
first use. The data is never committed, never packaged in wheels or sdist, and never republished
in converted form.
Attribution and license. Dataset: Muñoz-Salinas, R., Liu4K dataset employed for Aruco_Nano
paper, Zenodo, 2026, doi:10.5281/zenodo.18667018,
licensed CC BY 4.0. Locus reads the
files unmodified; any published result derived from them must credit the author, cite the DOI,
link the license and indicate changes. The record's free-text copyright field also reads
"CC0 License"; we apply the CC BY 4.0 attribution terms regardless. Funded by
PID2023-147296NB-I00 (Ministerio de Ciencia, Innovacion y Universidades). The dataset's authors
also ask users of aruco_nano to cite: R. Muñoz-Salinas, F. J. Romero-Ramirez, S. Garrido-Jurado,
"ArUco Nano: a simpler, faster, and more reliable fiducial marker detector" (2026);
S. Garrido-Jurado et al., "Automatic generation and detection of highly reliable fiducial markers
under occlusion", Pattern Recognition, 2014; F. J. Romero-Ramirez et al., "Speeded up detection of
squared fiducial markers", Image and Vision Computing, 2018. Any benchmark report on this dataset
must also carry lscpu hardware metadata, build profile, thread count and env vars
(docs/engineering/constraints.md section 6).
Hub Dataset Evaluation
Evaluate against rendered Hugging Face Hub datasets. These datasets include ground-truth 6-DOF poses, so the CLI reports both recall and pose error (translation RMSE in metres).
[!NOTE] Pose convention: Hub ground truth poses use a center origin (the pose describes the tag center). Locus reports poses at the top-left corner origin. The CLI automatically applies the rigid center-to-top-left shift via
Metrics.align_posebefore computing the error.
# Single-tag evaluation
PYTHONPATH=. uv run --group bench tools/cli.py bench real \
--hub-config locus_v1_tag36h11_1920x1080
# Board-level evaluation (AprilGrid or ChAruco)
# The board topology is inferred automatically from the dataset's rich_truth.json.
PYTHONPATH=. uv run --group bench tools/cli.py bench real \
--hub-config aprilgrid_golden_v1_1920x1080
PYTHONPATH=. uv run --group bench tools/cli.py bench real \
--hub-config charuco_golden_v1_1920x1080
# Limit frames and use a custom cache directory
PYTHONPATH=. uv run --group bench tools/cli.py bench real \
--hub-config aprilgrid_golden_v1_1920x1080 \
--data-dir tests/data/hub_cache \
--limit 50
Hub evaluation is mutually exclusive with ICRA scenarios — passing --hub-config skips the --scenarios loop.
Regression Tracking (Baselines)
You can save a "Golden Baseline" and compare current performance against it.
# Save a baseline
PYTHONPATH=. uv run --group bench tools/cli.py bench real --scenarios forward --save-baseline docs/engineering/benchmarking/baseline.json
# Compare current run against baseline
PYTHONPATH=. uv run --group bench tools/cli.py bench real --scenarios forward --baseline docs/engineering/benchmarking/baseline.json
Deep Profiling (Tracy)
Locus supports high-fidelity profiling using the Tracy Profiler.
- Rebuild with Tracy support:
uv run maturin develop -r -F tracy - Start the Tracy GUI client.
- Run benchmark with profiling flag:
Note: On some Linux systems, you may need
# Add --profile to any 'bench real' command PYTHONPATH=. uv run --group bench tools/cli.py bench real --profile --limit 5TRACY_NO_INVARIANT_CHECK=1if your CPU doesn't support invariant TSC.
Visual Debugging with Rerun
For diagnosing recall issues or tuning parameters:
uv run tools/cli.py visualize --scenario forward --limit 5
Features
- Convergence Tracking: Visualize subpixel jitter (yellow arrows) and reprojection errors (scalar plots) for every tag.
- Failure Diagnosis: Differentiate between geometric rejections (Red) and decoding failures (Orange).
- Remote & Edge Ready: Debug edge devices remotely using
--rerun-addrto stream to a local Rerun viewer.
For a comprehensive walkthrough, see the How-to Guide: Debugging with Rerun.