From ea7ddcf48945875feb3e22d7ce3ba86824803787 Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Thu, 23 Jul 2026 22:44:56 +0200 Subject: [PATCH] chore: add opt-in large-tier benchmarks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two production-sized cases (730d x 256 cols at ~415 MiB peak, 365d x 64 cols x 8 scenarios) guard the memory-amplification regime that the PR-sized cases cannot reach. Skipped by default including in CI — a --large flag in benchmarks/conftest.py enables them for local runs before dependency bumps or performance work. Co-Authored-By: Claude Fable 5 --- benchmarks/README.md | 11 +++++++++++ benchmarks/conftest.py | 25 +++++++++++++++++++++++++ benchmarks/test_bench_aggregate.py | 21 +++++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 benchmarks/conftest.py 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)