Skip to content

Refactor benchmarks#1993

Merged
ricardoV94 merged 2 commits intopymc-devs:v3from
ricardoV94:cleanup_benchmarks
Mar 23, 2026
Merged

Refactor benchmarks#1993
ricardoV94 merged 2 commits intopymc-devs:v3from
ricardoV94:cleanup_benchmarks

Conversation

@ricardoV94
Copy link
Copy Markdown
Member

Work in #1122 and #1961 made me realize our test suite is a bit of a mess

  • CI job was running in "FAST_COMPILE" ??
  • After Make Numba the default linker #1862 many benchmarks that were focused on "CVM" now runned in "NUMBA", sometimes even both
  • Tests were duplicated across the codebase, and in odd places, making it hard to see what was already being benchmarked.

This PR collects all benchmarks under tests/benchmark. This will be changed again by the #1122 but the changes should be separate from it.

@ricardoV94 ricardoV94 changed the title Cleanup benchmarks Refactor benchmarks Mar 20, 2026
@ricardoV94 ricardoV94 marked this pull request as ready for review March 20, 2026 22:12
config.change_flags(numba__cache=cache) if cache is not None else nullcontext()
)
with ctx:
benchmark.pedantic(compile_and_call_once, rounds=5, iterations=1)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why rounds >2?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

less noise?

Comment on lines +34 to +42
def test_convolve1d_benchmark_c(batch, convolve_mode, benchmark):
_test_convolve1d_benchmark(
mode="CVM", batch=batch, convolve_mode=convolve_mode, benchmark=benchmark
)


@pytest.mark.parametrize("convolve_mode", ("full", "valid"), ids=lambda x: f"mode={x}")
@pytest.mark.parametrize("batch", (False, True), ids=lambda x: f"batch={x}")
def test_convolve1d_benchmark_numba(batch, convolve_mode, benchmark):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not parameterize mode

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did that at first, makes it hard to isolate the mode I am interested in benching, and we usually try to optimize one mode at a time, so the others are just noise

y = vector("z")
out = exp(2 * x * y + y)

rng = np.random.default_rng(42)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i put use sum(map(ord)) for seed in my instructions file, i hate seeing 42 everywhere (HAHA NERD NUMBER)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also for the purpose of ASV im not sure using a seed is sufficient. I guess the reason you want to seed it is to have better comparability between runs, but we can't be use that the generator state will be advanced in the same way between different PRs

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why isn't a seed sufficient? this is local to the test. default_rng(42) yields the same state (for the same os/numpy version)

Copy link
Copy Markdown
Member

@jessegrabowski jessegrabowski Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah but the benchmarks will run across os/numpy versions, that's what I was thinking about

It's an extremely minor point


def _test_join_benchmark(mode, ndim, axis, memory_layout, gc, benchmark):
if ndim == 1 and not (memory_layout == "C-contiguous" and axis == 0):
pytest.skip("Redundant parametrization")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we do this in linalg too, is there not a more idiomatic way to handle this in pytest?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can make a fancy fixture that skips it programatically, but then you have to go read the logic elsewhere

@pytest.mark.parametrize("rewrite", [True, False], ids=["rewrite", "no_rewrite"])
@pytest.mark.parametrize("size", [10, 100, 1000], ids=["small", "medium", "large"])
def test_block_diag_dot_benchmark(benchmark, size, rewrite):
rng = np.random.default_rng()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to seed or not to seed, that is the question

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems fine unseeded? It shouldn't affect anything.

@ricardoV94 ricardoV94 merged commit c311830 into pymc-devs:v3 Mar 23, 2026
66 checks passed
@ricardoV94 ricardoV94 deleted the cleanup_benchmarks branch March 23, 2026 18:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants