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(); } 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(); } 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),