Skip to content

Stabilize CodSpeed microbenchmarks - #11110

Merged
connortsui20 merged 8 commits into
developfrom
ct/codspeed-repeatability
Nov 2, 2026
Merged

connortsui20 merged 8 commits into
developfrom
ct/codspeed-repeatability

Conversation

@connortsui20

@connortsui20 connortsui20 commented Nov 2, 2026 •

Copy link
Copy Markdown
Member

Short walltime benchmarks can report changes on unchanged code because CodSpeed compares the fastest sample. Batch the bitpacked filter and take samples, and keep unreliable cases local. Exclusions live beside the benchmark definitions, using #[cpu_features(exclude = ["neon"])] for whole CPU variants and source-level selection for individual inputs. CI commands stay generic.

Move the chunked-take family to walltime with 16 iterations per sample so it measures the operation's allocator and syscall costs. Keep its x86 variants local after repeatability checks failed; all 27 NEON cases remain in CI. The guide retains practical examples and measurement guidance without an exclusion catalog or a repeatability tool.

Measurement evidence

Spread is max / min - 1 across independent processes, with 1000 Divan samples per process and ten processes on each of three matching hosts.

Case Before Fixed sampling
AVX2 filter[80], sample size 64 9.36% 1.45%
AVX-512 threshold[80], sample size 16 8.26% 1.69%

Across independent base and head AVX2 builds, the fixed filter's worst spread was 4.66% over 60 processes. AVX-512 filter cases stayed within 1.78%. The excluded NEON string case still varied by 6.38%.

Measurements used existing CI executables with matching sample-size overrides from run 41449104113 (44bdefff6e69) and run 41442182591 (7c9bb58e39fe), on three c7i.metal-24xl hosts for x86 and three c7g.metal hosts for NEON. These measure repeatability, not kernel speedups.

Other Rust exclusions follow unexplained variation recorded in #10808 and repeated on the workflow-only #11095. The two Python integer scalar scans include variable calling-thread reactor polling, visible in #11102, even with memory mapping and background workers disabled.

The chunked-take warning on dfb32c5, compared with d8e7467, came from mimalloc lazily allocating page-map metadata. The affected small_m/shuffled/primitive/nonnull/chunks=2048/indices=16 case made one mmap and one prctl call totaling 23.3 µs; the base trace made neither. An untimed warm-up removed the syscall warning but produced eight regression alerts with unchanged kernel code under allocation-excluded simulation. Walltime measures elapsed time without that allocation exclusion and establishes separate per-CPU baselines.

Walltime repeats used the CI executables from 29920deef0, 1000 samples per process, and ten independent processes on each of three matching hosts per architecture. All 27 NEON cases stayed within 4.35% spread; the originally flagged case stayed within 2.88%. The worst x86 spreads were 11.04% for AVX2 and 11.20% for AVX-512. Increasing the sample size to 64 on two troublesome x86 cases still produced 12.15% and 13.38% spread, so those CPU variants remain local through the macro exclusion.

Focused native and simulation Clippy checks passed. Test-mode runs confirmed the local, AVX2, and NEON string case selection and the macro's NEON exclusion. Pinned-nightly formatting, Ruff, ty, YAML linting, and patch whitespace checks passed. All 66 CI checks passed on 29920deef0, including CodSpeed analysis with zero syscall warnings. The final x86 exclusion passed focused native and simulation Clippy checks and test-mode checks for both excluded variants. CI is rerunning for that final change. Local Git hooks were bypassed.

AI assistance: Codex helped investigate, implement and prepare this PR.

Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
@codspeed

codspeed Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Merging this PR will improve performance by 20.4%

1 warning

⚠️ Walltime results may be unreliable

Some benchmarks used the Walltime instrument outside CodSpeed Macro Runners, which can make the results inconsistent.

Learn more about Macro Runners

See affected benchmarks

⚡ 9 improved benchmarks
✅ 2271 untouched benchmarks
🆕 27 new benchmarks
⏩ 38 skipped benchmarks1
🗄️ 47 archived benchmarks run2

Performance Changes

Mode Benchmark BASE HEAD Efficiency
⚡ Walltime filter_avx512[80] 1.7 µs 1.3 µs +29.86%
⚡ Walltime threshold_avx2[80] 2.9 µs 2.3 µs +24.61%
⚡ Walltime filter_avx512[64] 1.7 µs 1.4 µs +23.64%
⚡ Walltime filter_avx2[64] 1.7 µs 1.4 µs +23.43%
⚡ Walltime threshold_avx512[80] 2.7 µs 2.2 µs +20.96%
⚡ Walltime filter_avx2[80] 1.8 µs 1.5 µs +19.31%
⚡ Walltime threshold_avx512[64] 2.5 µs 2.2 µs +18.09%
⚡ Walltime threshold_avx2[64] 2.5 µs 2.2 µs +13.17%
⚡ Walltime starts_with_avx512[8, VarBinView] 76.2 µs 68.3 µs +11.59%
🆕 Walltime take_neon[core/shuffled/primitive/nonnull/chunks=16/indices=1000] N/A 30 µs N/A
🆕 Walltime take_neon[core/shuffled/primitive/nonnull/chunks=16/indices=250] N/A 18.1 µs N/A
🆕 Walltime take_neon[core/shuffled/primitive/nonnull/chunks=4/indices=1000] N/A 17.2 µs N/A
🆕 Walltime take_neon[core/shuffled/primitive/nonnull/chunks=4/indices=250] N/A 8.4 µs N/A
🆕 Walltime take_neon[core/sorted/primitive/nonnull/chunks=16/indices=1000] N/A 20.5 µs N/A
🆕 Walltime take_neon[core/sorted/primitive/nonnull/chunks=16/indices=250] N/A 17.4 µs N/A
🆕 Walltime take_neon[core/sorted/primitive/nonnull/chunks=4/indices=1000] N/A 9.4 µs N/A
🆕 Walltime take_neon[core/sorted/primitive/nonnull/chunks=4/indices=250] N/A 6.5 µs N/A
🆕 Walltime take_neon[duplicates/duplicate90/primitive/nonnull/chunks=16/indices=1000] N/A 29.1 µs N/A
🆕 Walltime take_neon[duplicates/duplicate99/primitive/nonnull/chunks=16/indices=1000] N/A 24.1 µs N/A
🆕 Walltime take_neon[nullable/sorted/primitive/nullable_10pct_null/chunks=16/indices=1000] N/A 26.6 µs N/A
... ... ... ... ... ...

ℹ️ Only the first 20 benchmarks are displayed. Go to the app to view all benchmarks.

Tip

Curious why performance improved? Comment @codspeedbot explain why performance improved on this PR, or directly use the CodSpeed MCP with your agent.


Comparing ct/codspeed-repeatability (7da7699) with develop (d8e7467)

Open in CodSpeed

Footnotes

  1. 38 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

  2. 47 benchmarks were run, but are now archived. If they were deleted in another branch, consider rebasing to remove them from the report. Instead if they were added back, click here to restore them. ↩

Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
@connortsui20
connortsui20 enabled auto-merge (squash) November 2, 2026 21:15
@connortsui20
connortsui20 merged commit 7d00329 into develop Nov 2, 2026
78 of 79 checks passed
@connortsui20
connortsui20 deleted the ct/codspeed-repeatability branch November 2, 2026 21:22
connortsui20 added a commit that referenced this pull request Nov 3, 2026
## Summary

Follow-up to #11110. Keep the remaining noisy cases out of automatic
CodSpeed runs while preserving them for local benchmarks.

The Python scalar exclusions in #11110 never took effect because the
runner exports simulation as `instrumentation`, while the fixture
checked for `simulation`. Use the plugin's resolved mode so these cases
are actually skipped.

## Changes

- Allow a trailing comma in `#[divan::bench(...)]` when the CPU-feature
macro appends its options. The multiline bitpacked take definition
covers this case in CI builds.
- Share the resolved simulation check between the scalar and filter
fixtures. Also skip the 2 integer one-shot filtered scans that still
report system calls under simulation.
- Keep AVX2 bitpacked take with 80 selections local after batching still
produced a regression alert. Retain the 64-selection case and both
AVX-512 cases in CI.
- Keep AVX-512 nullable integer comparison local because its minimum
changes by more than 10% while its median stays stable.
- Keep the small random power-law boolean filter and the large
correlated power-law boolean filter local under simulation. The former
has repeated unexplained changes, and the latter repeatedly makes system
calls that simulation cannot measure.

<details>
<summary>Evidence from recent PR reports</summary>

Reviewed 40 CodSpeed report comments updated between November 2 at 19:28
UTC and November 3 at 19:28 UTC, including their comparison revisions
and the affected measurement modes.

| Case | Evidence |
| --- | --- |
| Python integer scalar scans |
[#11154](#11154 (comment))
still reports the repeated scan's 10 system calls. [A develop run after
#11110](https://github.com/vortex-data/vortex/actions/runs/41677647530/job/126062463160)
executes both integer scalar cases instead of skipping them. The [runner
exports the legacy `instrumentation`
value](https://github.com/CodSpeedHQ/codspeed/blob/main/crates/runner-shared/src/measurement_mode.rs),
which pytest-codspeed 5.0.3 normalizes to simulation. |
| Python integer filtered scans |
[#11130](#11130 (comment))
reports 30 system calls totaling 14.3 ms in `test_scan_filter[int]`.
[#11138](#11138 (comment))
reports 30 calls totaling 16.3 ms in
`test_scan_filter_to_arrow_array[int]`. |
| AVX2 `threshold[80]` |
[#11004](#11004 (comment))
compares `f7b5b1d864` with `e59b236d7b`: 2.183 to 2.531 µs, reported as
a 13.75% regression. Both use 1000 samples of 16 iterations. The head
median is 2.556 µs, so this is not just a single outlying minimum. The
PR does not change the fastlanes code or benchmark. |
| AVX-512 `lt_i64_nullable` |
[#11168](#11168 (comment))
reports 7.342 to 8.217 µs. Several unrelated CUDA PRs report the
opposite direction, including
[#10872](#10872 (comment)),
at 8.208 to 7.348 µs. Their head medians remain around 8.3 to 8.5 µs. |
| Boolean `filter_powerlaw_by_random[10000]` |
[#11167](#11167 (comment))
reports a 16.2% regression,
[#11168](#11168 (comment))
a 23.56% improvement, and
[#11169](#11169 (comment))
a 13.06% regression. The cause is unknown. |
| Boolean `filter_powerlaw_by_correlated_runs[100000]` |
[#10871](#10871 (comment))
and
[#11165](#11165 (comment))
each report 2 system calls totaling about 44 µs. |

The NEON chunked-take alerts on #11090 are on a PR that changes
execution substantially, so those cases remain enabled. Other dictionary
simulation alerts need more attribution before excluding them.

</details>

CI passes formatting, Python lint and script tests, Rust lint,
default-feature and all-feature Rust builds, all 3 CPU walltime
benchmark jobs, and Python benchmarks (36 passed, 4 intentionally
skipped). The previously failed simulation shard also passes. Some
remaining CI jobs and CodSpeed performance analysis are still pending.

No local checks were run. The pre-commit and pre-push hooks were
bypassed as requested.

---------

Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>

This branch was successfully deployed

1 active deployment
vercel-docs — 7da7699b Deployed Nov 2, 2026 by connortsui20 via Publish preview / Deploy #7528
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants