Benchmarks#
Solver and index performance is tracked with pytest-benchmark and published to Bencher.
Run locally#
Run the existing solver and index benchmarks with the same Python environment as CI:
pixi run --locked -e test-py313 benchmark
Export the measurements as pytest-benchmark JSON:
pixi run --locked -e test-py313 benchmark --benchmark-json benchmark_results.json
The JSON file is ignored by Git. Local runs do not upload results to Bencher.
To select a smaller group, append a pytest filter such as -k query_search.
Compare local timings on the same machine with the same environment and cache
state.
Solver overhead workloads#
The solver overhead benchmarks use synthetic local channels. Run them with:
pixi run --locked -e test-py313 benchmark -k 'pinned_request or empty_package_cache'
Use -k pinned_request or -k empty_package_cache to select one workload:
The pinned-request benchmark has 10 package names with 200 candidate builds each. Pins exclude the newest version. It times
solve_final_state(), including metadata loading and pin validation. Channel and prefix creation, plus solver construction, happen before timing starts.The empty-cache benchmark requests 100 or 563 packages. It times index construction and a Rattler solve, including package-cache source callbacks. Channel creation and request-spec construction happen before timing starts.
Both workloads clear conda’s in-memory metadata and package-cache objects before each round, outside the timed operation. Filesystem caches are left intact.
Add benchmarks#
Add tests marked with @pytest.mark.benchmark and time the operation with the
benchmark fixture. See the
index benchmarks
and solver benchmarks
for examples.
Keep fixture setup outside the timed callable unless it is part of the operation you intend to measure. Use fixed test data and stable test names and parameter IDs so Bencher can track the same workload across commits. For cache-sensitive benchmarks, define whether each case measures a cold or warm cache.
The existing tests cover index searches, installed-package solver handling, and end-to-end solve comparisons between rattler and libmamba.
Results and regression alerts#
The Benchmarks workflow
runs on pushes to main and pull requests targeting main, and can also be
run manually. It uses Ubuntu 22.04, Python 3.13, and the Pixi lockfile. Its
benchmark-results artifact contains the JSON measurements and is retained for
seven days.
The Track Benchmarks workflow
uploads successful runs to the
Bencher project. Select main
for the baseline or pr-<number> for a pull request. Manual runs are uploaded
only when run from main.
PR reports compare against the base branch’s results. The latency threshold
uses a t-test with an upper threshold of 0.99 and at most 64 historical
samples. A first baseline run records measurements before comparisons can
begin. Detected regressions fail the reporting workflow and generate PR
feedback. Inspect the affected benchmark and its history before changing a
threshold.
Input-state reuse#
tests/test_state_benchmarks.py measures spec collection for 100, 563, and
1,000 installed packages. The first cases include input-state construction,
output-state construction, and spec collection. The retry cases populate the
input-derived values before timing, then rebuild the output state and collect
specs again. Record creation stays outside both timed operations.
The same module includes a complete 563-package update fallback. A pinned app requires an older dependency build, forcing three Rattler attempts across the normal and fallback loops. This case checks the resulting transaction as well as the attempt count. Local channel and prefix creation are outside timing.
Run this group with -k state_ or pass tests/test_state_benchmarks.py to the
benchmark task. Compare first collection, repeated collection, and complete
solves separately. A faster repeated collection does not imply the same
percentage improvement for the full solve. Use separate processes for Python
allocation measurements, since tracing affects timing, and distinguish retained
input-state data from allocation peaks and native Rattler memory.