Skip to content

Commit eff83d4

Browse files
connortsui20claude
andauthored
Trim constant-operand cases from scalar function benchmarks (#9696)
## Summary - Tracking Issue: #9128 The scalar function benchmarks carried 37 cases with a constant operand, 34 of them tagged `#[cpu_features]` and so measured on three walltime legs each. Decoding a constant operand, orienting it, and carrying its validity are shared across operators, element types, and output modes, so most of those cases measure the same path again and crowd out the per-row against per-row shape the kernels are tuned for. Or in other words, just reduces the # of constant benchmarks we have. Ideally we would keep this, but because they are so noisy we might as well just remove them. ## Changes Keeps 10 constant cases as a regression guard on that path, 8 of them tagged, and makes per-row against per-row the default shape everywhere else. Signed-off-by: Claude <[email protected]> Co-authored-by: Claude <[email protected]>
1 parent a745604 commit eff83d4

3 files changed

Lines changed: 46 additions & 61 deletions

File tree

‎vortex-array/benches/binary_ops.rs‎

Lines changed: 16 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,19 @@ const I16_LEN: usize = primitive_len::<i16>();
6161
const I32_LEN: usize = primitive_len::<i32>();
6262
const I64_LEN: usize = primitive_len::<i64>();
6363

64+
/// Per-row against per-row, short and long. This is the shape the operators are tuned for, so it
65+
/// is the one every operator is measured on.
6466
const BINARY_SHAPE_CASES: &[(usize, BinaryShape)] = &[
6567
(128, BinaryShape::PerRowPerRow),
66-
(128, BinaryShape::PerRowConstant),
67-
(128, BinaryShape::ConstantPerRow),
68-
(128, BinaryShape::PerRowNullableConstant),
6968
(I64_LEN, BinaryShape::PerRowPerRow),
69+
];
70+
71+
/// Constant operands are measured on `Add` alone, at the long length.
72+
///
73+
/// Decoding a constant operand, orienting it, and carrying its validity are shared by every
74+
/// operator, so repeating all three shapes under `Sub` and `Mul` costs three walltime legs apiece
75+
/// and measures the same code again. These cases stay as the regression guard on that path.
76+
const CONSTANT_SHAPE_CASES: &[(usize, BinaryShape)] = &[
7077
(I64_LEN, BinaryShape::PerRowConstant),
7178
(I64_LEN, BinaryShape::ConstantPerRow),
7279
(I64_LEN, BinaryShape::PerRowNullableConstant),
@@ -90,6 +97,12 @@ fn add_shapes(bencher: Bencher, &(len, shape): &(usize, BinaryShape)) {
9097
bench_binary_shape(bencher, len, shape, Operator::Add);
9198
}
9299

100+
#[vortex_bench_support::cpu_features]
101+
#[divan::bench(args = CONSTANT_SHAPE_CASES)]
102+
fn add_constant_shapes(bencher: Bencher, &(len, shape): &(usize, BinaryShape)) {
103+
bench_binary_shape(bencher, len, shape, Operator::Add);
104+
}
105+
93106
#[vortex_bench_support::cpu_features]
94107
#[divan::bench(args = BINARY_SHAPE_CASES)]
95108
fn subtract_shapes(bencher: Bencher, &(len, shape): &(usize, BinaryShape)) {
@@ -136,15 +149,6 @@ fn add_i64_nullable(bencher: Bencher) {
136149
bench_primitive(bencher, lhs, rhs, Operator::Add);
137150
}
138151

139-
#[vortex_bench_support::cpu_features]
140-
#[divan::bench]
141-
fn add_i64_constant(bencher: Bencher) {
142-
let lhs = primitive_nonnull(0, I64_LEN).into_array();
143-
let rhs = ConstantArray::new(1_000_000i64, I64_LEN).into_array();
144-
145-
bench_primitive(bencher, lhs, rhs, Operator::Add);
146-
}
147-
148152
#[vortex_bench_support::cpu_features]
149153
#[divan::bench]
150154
fn add_i32_nonnull(bencher: Bencher) {
@@ -244,15 +248,6 @@ fn mul_i32_nullable(bencher: Bencher) {
244248
bench_primitive(bencher, lhs, rhs, Operator::Mul);
245249
}
246250

247-
#[vortex_bench_support::cpu_features]
248-
#[divan::bench]
249-
fn mul_i32_constant(bencher: Bencher) {
250-
let lhs = primitive_i32_small_nonnull(1, I32_LEN).into_array();
251-
let rhs = ConstantArray::new(31i32, I32_LEN).into_array();
252-
253-
bench_primitive(bencher, lhs, rhs, Operator::Mul);
254-
}
255-
256251
#[vortex_bench_support::cpu_features]
257252
#[divan::bench]
258253
fn div_i64_nonnull(bencher: Bencher) {
@@ -271,15 +266,6 @@ fn div_i64_nullable(bencher: Bencher) {
271266
bench_primitive(bencher, lhs, rhs, Operator::Div);
272267
}
273268

274-
#[vortex_bench_support::cpu_features]
275-
#[divan::bench]
276-
fn sub_i64_constant(bencher: Bencher) {
277-
let lhs = primitive_nonnull(0, I64_LEN).into_array();
278-
let rhs = ConstantArray::new(37i64, I64_LEN).into_array();
279-
280-
bench_primitive(bencher, lhs, rhs, Operator::Sub);
281-
}
282-
283269
#[divan::bench]
284270
fn add_decimal_i64_nonnull(bencher: Bencher) {
285271
let lhs = decimal_i64_nonnull(0, LEN).into_array();
@@ -328,15 +314,6 @@ fn div_decimal_i128_nullable(bencher: Bencher) {
328314
bench_decimal(bencher, lhs, rhs, Operator::Div);
329315
}
330316

331-
#[vortex_bench_support::cpu_features]
332-
#[divan::bench]
333-
fn eq_i64_constant(bencher: Bencher) {
334-
let lhs = primitive_nonnull(0, LEN).into_array();
335-
let rhs = ConstantArray::new(1024i64, LEN).into_array();
336-
337-
bench_bool(bencher, lhs, rhs, Operator::Eq);
338-
}
339-
340317
#[vortex_bench_support::cpu_features]
341318
#[divan::bench]
342319
fn lt_i64_nullable(bencher: Bencher) {
@@ -354,14 +331,6 @@ fn and_bool_nullable(bencher: Bencher) {
354331
bench_bool(bencher, lhs, rhs, Operator::And);
355332
}
356333

357-
#[divan::bench]
358-
fn or_bool_constant(bencher: Bencher) {
359-
let lhs = bool_nullable(2, 7).into_array();
360-
let rhs = ConstantArray::new(true, LEN).into_array();
361-
362-
bench_bool(bencher, lhs, rhs, Operator::Or);
363-
}
364-
365334
fn bench_primitive(bencher: Bencher, lhs: ArrayRef, rhs: ArrayRef, operator: Operator) {
366335
bench_binary::<PrimitiveArray>(bencher, lhs, rhs, operator);
367336
}

‎vortex-array/benches/compare.rs‎

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
//! selected through `cfg(target_feature)` has to beat, measured on the silicon it would run
1111
//! on.
1212
//!
13+
//! Every case here compares one array against another, which is the shape the path is tuned for.
14+
//! The three constant cases that remain — boolean, integer, and string — are a regression guard on
15+
//! constant handling rather than coverage of it: a constant operand is decoded the same way
16+
//! whatever it holds. Constant orientation is measured once, in `binary_ops.rs`.
17+
//!
1318
//! The boolean, decimal, string, and struct cases are not tagged. A wider vector register is
1419
//! not what decides them: booleans are already word-at-a-time over a bitmap, decimals are
1520
//! `i128`, and the string and struct cases are dominated by view chasing and per-field
@@ -196,15 +201,6 @@ fn compare_int_constant(bencher: Bencher) {
196201
bench_compare(bencher, arr, constant, Operator::Gte);
197202
}
198203

199-
#[vortex_bench_support::cpu_features]
200-
#[divan::bench]
201-
fn compare_int_constant_left(bencher: Bencher) {
202-
let mut rng = StdRng::seed_from_u64(0);
203-
let constant = ConstantArray::new(50_000_000i64, ARRAY_SIZE).into_array();
204-
let arr = int_array(&mut rng);
205-
bench_compare(bencher, constant, arr, Operator::Lte);
206-
}
207-
208204
#[vortex_bench_support::cpu_features]
209205
#[divan::bench]
210206
fn compare_u8(bencher: Bencher) {

‎vortex-array/benches/row_fn_output.rs‎

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,17 @@ static SESSION: LazyLock<VortexSession> = LazyLock::new(array_session);
4444

4545
const ROWS: usize = 1 << 14;
4646

47-
const INPUT_SHAPES: &[InputShape] = &[
48-
InputShape::PerRowPerRow,
49-
InputShape::PerRowConstant,
50-
InputShape::ConstantPerRow,
51-
];
47+
/// The shape every row function is measured on: one per-row operand against another.
48+
const INPUT_SHAPES: &[InputShape] = &[InputShape::PerRowPerRow];
49+
50+
/// Constant operands are measured on `i64` alone, by the `*_constant` benchmarks below.
51+
///
52+
/// The row executor decodes and orients a constant operand the same way whatever the row kernel
53+
/// does with the value, so running both constant orientations under every element type and every
54+
/// output mode measures one path repeatedly, three walltime legs at a time. One infallible pair and
55+
/// one deferred pair keep it covered: those two differ in how a constant row reaches the kernel,
56+
/// and that is the difference worth watching.
57+
const CONSTANT_SHAPES: &[InputShape] = &[InputShape::PerRowConstant, InputShape::ConstantPerRow];
5258

5359
#[derive(Clone, Copy, Debug)]
5460
enum InputShape {
@@ -182,13 +188,27 @@ fn infallible_bool<T: BenchPrimitive>(bencher: Bencher, &shape: &InputShape) {
182188
bench_row_fn(bencher, &function, make_args::<T>(shape));
183189
}
184190

191+
#[vortex_bench_support::cpu_features]
192+
#[divan::bench(args = CONSTANT_SHAPES)]
193+
fn infallible_bool_constant(bencher: Bencher, &shape: &InputShape) {
194+
let function = InfallibleBool::<i64>(PhantomData);
195+
bench_row_fn(bencher, &function, make_args::<i64>(shape));
196+
}
197+
185198
#[vortex_bench_support::cpu_features]
186199
#[divan::bench(types = [i32, i64], args = INPUT_SHAPES)]
187200
fn deferred_bool<T: BenchPrimitive>(bencher: Bencher, &shape: &InputShape) {
188201
let function = DeferredBool::<T>(PhantomData);
189202
bench_row_fn(bencher, &function, make_args::<T>(shape));
190203
}
191204

205+
#[vortex_bench_support::cpu_features]
206+
#[divan::bench(args = CONSTANT_SHAPES)]
207+
fn deferred_bool_constant(bencher: Bencher, &shape: &InputShape) {
208+
let function = DeferredBool::<i64>(PhantomData);
209+
bench_row_fn(bencher, &function, make_args::<i64>(shape));
210+
}
211+
192212
#[vortex_bench_support::cpu_features]
193213
#[divan::bench(args = INPUT_SHAPES)]
194214
fn deferred_i64(bencher: Bencher, &shape: &InputShape) {

0 commit comments

Comments
 (0)