Skip to content

Commit 0ef496c

Browse files
authored
Benchmark primitive comparison across CPU features (#9598)
## Summary The measurement half of #9587, split out so the numbers land before the kernels do. Bottom of a three-PR stack: this PR, then #9599, then #9587. Tagging these with `#[cpu_features]` first means the walltime legs record the portable lane kernel's throughput on `avx2`, `avx512`, and `neon` metal as a baseline series. The kernel PR then reports against it rather than introducing both the benchmark and the thing it measures in one diff. ## Changes - Adds the primitive comparison cases a hand-written SIMD kernel would have to beat: constant on the left, `u8`, `u64`, and `f32`. - Tags those four with `#[cpu_features]`, so each walltime leg measures them under its own build flags instead of in simulation. The existing cases are untouched and keep their simulation series. - `bench_compare` now carries an `ItemsCount`, so the report reads as throughput rather than a time that only means something next to another run over the same array length. - Adds module docs recording why these four are tagged and the rest are not. Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
1 parent e4b3421 commit 0ef496c

3 files changed

Lines changed: 72 additions & 0 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vortex-array/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ vortex-array = { path = ".", features = [
9797
"table-display",
9898
"unstable_row_fns",
9999
] }
100+
vortex-bench-support = { workspace = true }
100101

101102
[[bench]]
102103
name = "aggregate_max"

vortex-array/benches/compare.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
11
// SPDX-License-Identifier: Apache-2.0
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
33

4+
//! Benchmarks for the binary comparison path, over every array kind it accepts.
5+
//!
6+
//! `compare_int_constant_left`, `compare_u8`, `compare_u64`, and `compare_f32` carry
7+
//! `#[cpu_features]`, so they are measured on every walltime CPU-feature leg rather than in
8+
//! simulation. Each is written once and compiled differently per leg: today the primitive
9+
//! comparison path is a portable lane kernel, and how well it auto-vectorizes is decided by
10+
//! the build. That is the baseline a hand-written kernel selected through
11+
//! `cfg(target_feature)` has to beat, measured on the silicon it would run on.
12+
413
#![expect(clippy::unwrap_used)]
514

615
use divan::Bencher;
16+
use divan::counter::ItemsCount;
717
use mimalloc::MiMalloc;
818
use rand::RngExt;
919
use rand::SeedableRng;
@@ -38,7 +48,10 @@ const ARRAY_SIZE: usize = 8_192;
3848

3949
fn bench_compare(bencher: Bencher, lhs: ArrayRef, rhs: ArrayRef, op: Operator) {
4050
let session = vortex_array::array_session();
51+
let len = lhs.len();
52+
4153
bencher
54+
.counter(ItemsCount::new(len))
4255
.with_inputs(|| (&lhs, &rhs, session.create_execution_ctx()))
4356
.bench_refs(|input| {
4457
input
@@ -88,6 +101,27 @@ fn float_array(rng: &mut StdRng) -> ArrayRef {
88101
.into_array()
89102
}
90103

104+
fn u8_array(rng: &mut StdRng) -> ArrayRef {
105+
(0..ARRAY_SIZE)
106+
.map(|_| rng.random::<u8>())
107+
.collect::<Buffer<_>>()
108+
.into_array()
109+
}
110+
111+
fn u64_array(rng: &mut StdRng) -> ArrayRef {
112+
(0..ARRAY_SIZE)
113+
.map(|_| rng.random::<u64>())
114+
.collect::<Buffer<_>>()
115+
.into_array()
116+
}
117+
118+
fn f32_array(rng: &mut StdRng) -> ArrayRef {
119+
(0..ARRAY_SIZE)
120+
.map(|_| rng.random_range(0.0f32..1.0))
121+
.collect::<Buffer<_>>()
122+
.into_array()
123+
}
124+
91125
fn string_array(rng: &mut StdRng) -> ArrayRef {
92126
VarBinViewArray::from_iter_str((0..ARRAY_SIZE).map(|_| {
93127
let len = rng.random_range(1usize..24);
@@ -154,6 +188,42 @@ fn compare_int_constant(bencher: Bencher) {
154188
bench_compare(bencher, arr, constant, Operator::Gte);
155189
}
156190

191+
#[vortex_bench_support::cpu_features]
192+
#[divan::bench]
193+
fn compare_int_constant_left(bencher: Bencher) {
194+
let mut rng = StdRng::seed_from_u64(0);
195+
let constant = ConstantArray::new(50_000_000i64, ARRAY_SIZE).into_array();
196+
let arr = int_array(&mut rng);
197+
bench_compare(bencher, constant, arr, Operator::Lte);
198+
}
199+
200+
#[vortex_bench_support::cpu_features]
201+
#[divan::bench]
202+
fn compare_u8(bencher: Bencher) {
203+
let mut rng = StdRng::seed_from_u64(0);
204+
let arr1 = u8_array(&mut rng);
205+
let arr2 = u8_array(&mut rng);
206+
bench_compare(bencher, arr1, arr2, Operator::Gte);
207+
}
208+
209+
#[vortex_bench_support::cpu_features]
210+
#[divan::bench]
211+
fn compare_u64(bencher: Bencher) {
212+
let mut rng = StdRng::seed_from_u64(0);
213+
let arr1 = u64_array(&mut rng);
214+
let arr2 = u64_array(&mut rng);
215+
bench_compare(bencher, arr1, arr2, Operator::Gte);
216+
}
217+
218+
#[vortex_bench_support::cpu_features]
219+
#[divan::bench]
220+
fn compare_f32(bencher: Bencher) {
221+
let mut rng = StdRng::seed_from_u64(0);
222+
let arr1 = f32_array(&mut rng);
223+
let arr2 = f32_array(&mut rng);
224+
bench_compare(bencher, arr1, arr2, Operator::Gte);
225+
}
226+
157227
#[divan::bench]
158228
fn compare_int_eq(bencher: Bencher) {
159229
let mut rng = StdRng::seed_from_u64(0);

0 commit comments

Comments
 (0)