diff --git a/benchmarks/README.md b/benchmarks/README.md index 90114af..ead2a4d 100644 --- a/benchmarks/README.md +++ b/benchmarks/README.md @@ -24,6 +24,17 @@ uv run --with "pytest-benchmem[plot]" pytest benchmarks/ \ (`-o addopts="" -p no:xdist` because the project's xdist config auto-disables benchmarks.) +## Large tier + +Production-sized cases (`test_large_*`, several seconds and hundreds of MiB +peak each) are skipped by default — in CI too. Run them locally before +dependency bumps or performance work: + +```bash +uv run --with "pytest-benchmem[plot]" pytest benchmarks/ --large -k large \ + -o addopts="" -p no:xdist --benchmark-only --benchmark-memory +``` + ## Baselines Save a named baseline (stored in `.benchmarks/`, gitignored — machine-specific): diff --git a/benchmarks/conftest.py b/benchmarks/conftest.py new file mode 100644 index 0000000..4e5d516 --- /dev/null +++ b/benchmarks/conftest.py @@ -0,0 +1,25 @@ +import pytest + + +def pytest_addoption(parser): + parser.addoption( + "--large", + action="store_true", + default=False, + help="run large-scale benchmarks (production-sized data, minutes)", + ) + + +def pytest_configure(config): + config.addinivalue_line( + "markers", "large: large-scale benchmark, runs only with --large" + ) + + +def pytest_collection_modifyitems(config, items): + if config.getoption("--large"): + return + skip = pytest.mark.skip(reason="large benchmark: pass --large to run") + for item in items: + if "large" in item.keywords: + item.add_marker(skip) diff --git a/benchmarks/test_bench_aggregate.py b/benchmarks/test_bench_aggregate.py index ba7a7af..4c5c169 100644 --- a/benchmarks/test_bench_aggregate.py +++ b/benchmarks/test_bench_aggregate.py @@ -17,6 +17,10 @@ integration surprises (tsam version bumps, config plumbing), the representation-by-width interaction, and the multi-``cluster_dim`` MultiIndex path. +- ``test_large_*`` — production-sized cases (hundreds of MiB peak) that + guard the memory-amplification regime. Opt-in via ``--large`` (skipped + otherwise, including in CI) — run locally before dependency bumps or + performance work. - ``test_user_*`` — post-aggregation operations users run on results: reusing a stored clustering on new data (``clustering.apply``) and expanding cluster-level data back to the full time axis @@ -226,3 +230,20 @@ def test_user_disaggregate(benchmark, wide_result): args=(result.cluster_representatives,), **CONFIG_OPTS, ) + + +# --- large tier (production-sized, opt-in via --large) ------------------------- + +LARGE_OPTS = dict(rounds=2, iterations=1, warmup_rounds=0) + + +@pytest.mark.large +def test_large_wide(benchmark): + da = make_data(730, n_cols=256, n_slices=1) + benchmark.pedantic(run_aggregate, args=(da, FULL_CONFIG), **LARGE_OPTS) + + +@pytest.mark.large +def test_large_scenarios(benchmark): + da = make_data(365, n_cols=64, n_slices=8) + benchmark.pedantic(run_aggregate, args=(da, FULL_CONFIG), **LARGE_OPTS)