From 9e05e3c926823c6458a4550a8ce216427933dd1e Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 20 Jul 2026 15:30:08 +0000 Subject: [PATCH 1/3] bench: drop the 128-bit size from true_count benchmarks `true_count_vortex_buffer[128]` flipped between the same two values (580.6ns <-> 522.2ns, +/-11.17%) on at least nine unrelated PRs since #8742, including java-only (#8811, #8812), Cargo.toml-only (#8820), website-removal-only (#8805), zstd-only (#8843), and geo-only (#8803) changes. A 128-bit true_count is a popcount over two u64 words, so the measurement is fixed dispatch/harness overhead and binary code layout rather than the count itself. Keep only the sizes where the popcount loop dominates, mirroring the bitwise_not_vortex_buffer_mut fix from #8742. Signed-off-by: Claude Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_015ypCZPxvLuJK9FgWKF8U4P --- vortex-buffer/benches/vortex_bitbuffer.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/vortex-buffer/benches/vortex_bitbuffer.rs b/vortex-buffer/benches/vortex_bitbuffer.rs index b67b3f1bf39..b9a6a6ab505 100644 --- a/vortex-buffer/benches/vortex_bitbuffer.rs +++ b/vortex-buffer/benches/vortex_bitbuffer.rs @@ -176,7 +176,12 @@ fn slice_arrow_buffer(bencher: Bencher, length: usize) { }); } -#[divan::bench(args = INPUT_SIZE)] +/// A 128-bit `true_count` is a popcount over two `u64` words, so the measurement is fixed +/// dispatch and harness overhead plus binary code layout rather than the count itself. Only +/// sizes where the popcount loop dominates are worth measuring. +const TRUE_COUNT_INPUT_SIZE: &[usize] = &[1024, 2048, 16_384, 65_536]; + +#[divan::bench(args = TRUE_COUNT_INPUT_SIZE)] fn true_count_vortex_buffer(bencher: Bencher, length: usize) { let buffer = BitBuffer::from_iter((0..length).map(true_count_pattern)); @@ -185,7 +190,7 @@ fn true_count_vortex_buffer(bencher: Bencher, length: usize) { .bench_refs(|buffer| buffer.true_count()) } -#[divan::bench(args = INPUT_SIZE)] +#[divan::bench(args = TRUE_COUNT_INPUT_SIZE)] fn true_count_arrow_buffer(bencher: Bencher, length: usize) { let buffer = Arrow(BooleanBuffer::from_iter( (0..length).map(true_count_pattern), From 30346f6f54bb7ccb1e3405db8feb5d4933874214 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 20 Jul 2026 15:30:08 +0000 Subject: [PATCH 2/3] bench: use mimalloc in cast_decimal benchmarks `copy_nullable[65536]` and `copy_non_nullable[65536]` were on the #8742 watch list and have now been flagged with byte-identical values on two unrelated open PRs (#8838 union scalars, #8724 decimal add/sub kernels; -24.3% / -16.59% each). The copy casts allocate their output buffer in the timed region, so glibc malloc differences across CodSpeed runner images show up as benchmark changes. Install vendored mimalloc as the global allocator, as #8742 did for the other alloc-heavy vortex-array bench files. Signed-off-by: Claude Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_015ypCZPxvLuJK9FgWKF8U4P --- vortex-array/benches/cast_decimal.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/vortex-array/benches/cast_decimal.rs b/vortex-array/benches/cast_decimal.rs index 8e0ddb19b6b..99773b5b553 100644 --- a/vortex-array/benches/cast_decimal.rs +++ b/vortex-array/benches/cast_decimal.rs @@ -14,6 +14,7 @@ use std::sync::LazyLock; use divan::Bencher; +use mimalloc::MiMalloc; use rand::prelude::*; use vortex_array::ArrayRef; use vortex_array::Canonical; @@ -28,6 +29,12 @@ use vortex_array::validity::Validity; use vortex_buffer::BufferMut; use vortex_session::VortexSession; +// The copy casts allocate their output buffer inside the timed region, so route allocation +// through vendored mimalloc to keep glibc malloc (which varies across runner images) out of +// the measured trace. +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; + fn main() { divan::main(); } From 19020724923cd9e1b6071b7dfe6237842f56572a Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 20 Jul 2026 15:30:08 +0000 Subject: [PATCH 3/3] bench: use mimalloc in run_end_compress benchmarks `compress[(100000, 4)]` flipped between the same two values (1.8ms <-> 1.6ms, ~+/-11.9%) on three unrelated PRs since #8742: #8805 (deletes a JS website), #8750, and #8856 (list min/max expressions). runend_encode allocates its output buffers inside the timed region and the runend bench binaries still use glibc malloc, whose code differs across CodSpeed runner images. Install vendored mimalloc as the global allocator, matching the #8742 fix for the flaky vortex-array benches. Signed-off-by: Claude Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_015ypCZPxvLuJK9FgWKF8U4P --- Cargo.lock | 1 + encodings/runend/Cargo.toml | 1 + encodings/runend/benches/run_end_compress.rs | 7 +++++++ 3 files changed, 9 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index e79211b5436..98532fb48a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10566,6 +10566,7 @@ dependencies = [ "arbitrary", "codspeed-divan-compat", "itertools 0.14.0", + "mimalloc", "num-traits", "prost 0.14.4", "rand 0.10.2", diff --git a/encodings/runend/Cargo.toml b/encodings/runend/Cargo.toml index 4d36d0c1548..7ec149b9dd9 100644 --- a/encodings/runend/Cargo.toml +++ b/encodings/runend/Cargo.toml @@ -30,6 +30,7 @@ workspace = true [dev-dependencies] divan = { workspace = true } itertools = { workspace = true } +mimalloc = { workspace = true } rand = { workspace = true } rstest = { workspace = true } vortex-array = { workspace = true, features = ["_test-harness"] } diff --git a/encodings/runend/benches/run_end_compress.rs b/encodings/runend/benches/run_end_compress.rs index cd241ad42c6..d1d08ddee96 100644 --- a/encodings/runend/benches/run_end_compress.rs +++ b/encodings/runend/benches/run_end_compress.rs @@ -7,6 +7,7 @@ use std::sync::LazyLock; use divan::Bencher; use itertools::repeat_n; +use mimalloc::MiMalloc; use vortex_array::IntoArray; use vortex_array::RecursiveCanonical; use vortex_array::VortexSessionExecute; @@ -19,6 +20,12 @@ use vortex_runend::RunEnd; use vortex_runend::compress::runend_encode; use vortex_session::VortexSession; +// `runend_encode` allocates its output buffers inside the timed region, so route allocation +// through vendored mimalloc to keep glibc malloc (which varies across runner images) out of +// the measured trace. +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; + fn main() { divan::main(); }