Skip to content

Commit a01de34

Browse files
committed
Benchmark RowFn Boolean dense retry on CI CPU targets
Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
1 parent 133aacd commit a01de34

2 files changed

Lines changed: 182 additions & 0 deletions

File tree

‎vortex-array/Cargo.toml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ harness = false
145145
name = "binary_ops"
146146
harness = false
147147

148+
[[bench]]
149+
name = "row_fn_bool_retry"
150+
harness = false
151+
148152
[[bench]]
149153
name = "row_fn_output"
150154
harness = false
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3+
4+
//! Measures packed Boolean dense attempts and nullable retry through public RowFn execution.
5+
6+
use std::sync::LazyLock;
7+
8+
use divan::Bencher;
9+
use divan::counter::ItemsCount;
10+
use mimalloc::MiMalloc;
11+
use vortex_array::IntoArray;
12+
use vortex_array::VortexSessionExecute;
13+
use vortex_array::array_session;
14+
use vortex_array::arrays::BoolArray;
15+
use vortex_array::arrays::ConstantArray;
16+
use vortex_array::arrays::PrimitiveArray;
17+
use vortex_array::dtype::DType;
18+
use vortex_array::scalar_fn::EmptyOptions;
19+
use vortex_array::scalar_fn::ScalarFnId;
20+
use vortex_array::scalar_fn::VecExecutionArgs;
21+
use vortex_array::scalar_fn::unstable::row::RowFn;
22+
use vortex_array::scalar_fn::unstable::row::RowVisitor;
23+
use vortex_array::scalar_fn::unstable::row::execute_rows;
24+
use vortex_array::validity::Validity;
25+
use vortex_error::VortexExpect;
26+
use vortex_error::VortexResult;
27+
use vortex_error::vortex_ensure;
28+
use vortex_session::VortexSession;
29+
use vortex_session::registry::CachedId;
30+
31+
#[global_allocator]
32+
static GLOBAL: MiMalloc = MiMalloc;
33+
34+
static SESSION: LazyLock<VortexSession> = LazyLock::new(array_session);
35+
36+
const SIZES: &[usize] = &[64, 16_384];
37+
const CASES: &[(InputShape, Scenario)] = &[
38+
(InputShape::Columns, Scenario::AllValid),
39+
(InputShape::ConstantLhs, Scenario::AllValid),
40+
(InputShape::ConstantRhs, Scenario::AllValid),
41+
(InputShape::Columns, Scenario::PartialAccepted),
42+
(InputShape::ConstantLhs, Scenario::PartialAccepted),
43+
(InputShape::ConstantRhs, Scenario::PartialAccepted),
44+
(InputShape::Columns, Scenario::NullOnlyFailure),
45+
(InputShape::ConstantLhs, Scenario::NullOnlyFailure),
46+
(InputShape::ConstantRhs, Scenario::NullOnlyFailure),
47+
(InputShape::Columns, Scenario::ObservableFailure),
48+
(InputShape::ConstantLhs, Scenario::ObservableFailure),
49+
(InputShape::ConstantRhs, Scenario::ObservableFailure),
50+
];
51+
52+
#[derive(Clone, Copy, Debug)]
53+
enum InputShape {
54+
Columns,
55+
ConstantLhs,
56+
ConstantRhs,
57+
}
58+
59+
#[derive(Clone, Copy, Debug)]
60+
enum Scenario {
61+
AllValid,
62+
PartialAccepted,
63+
NullOnlyFailure,
64+
ObservableFailure,
65+
}
66+
67+
#[derive(Clone)]
68+
struct Predicate<const MULTIVERSIONED: bool>;
69+
70+
impl<const MULTIVERSIONED: bool> RowFn for Predicate<MULTIVERSIONED> {
71+
type Options = EmptyOptions;
72+
73+
const ARG_NAMES: &'static [&'static str] = &["lhs", "rhs"];
74+
const INFALLIBLE: bool = false;
75+
76+
fn id(&self) -> ScalarFnId {
77+
static ID: CachedId = CachedId::new("bench.row_fn_bool_retry");
78+
*ID
79+
}
80+
81+
fn dispatch<V: RowVisitor>(
82+
&self,
83+
_options: &EmptyOptions,
84+
_args: &[DType],
85+
visitor: V,
86+
) -> VortexResult<V::VisitResult> {
87+
visitor.visit_deferred_bool::<(i64, i64), bool, MULTIVERSIONED>(
88+
|(lhs, rhs)| (lhs < rhs, lhs == i64::MAX || rhs == i64::MAX),
89+
|failed| {
90+
vortex_ensure!(!failed, "predicate rejected sentinel");
91+
Ok(())
92+
},
93+
)
94+
}
95+
}
96+
97+
fn main() {
98+
LazyLock::force(&SESSION);
99+
divan::main();
100+
}
101+
102+
#[vortex_bench_support::cpu_features]
103+
#[divan::bench(args = CASES, consts = SIZES)]
104+
fn plain<const ROWS: usize>(bencher: Bencher, &(shape, scenario): &(InputShape, Scenario)) {
105+
bench_predicate::<false>(bencher, ROWS, shape, scenario);
106+
}
107+
108+
#[vortex_bench_support::cpu_features]
109+
#[divan::bench(args = CASES, consts = SIZES)]
110+
fn multiversioned<const ROWS: usize>(
111+
bencher: Bencher,
112+
&(shape, scenario): &(InputShape, Scenario),
113+
) {
114+
bench_predicate::<true>(bencher, ROWS, shape, scenario);
115+
}
116+
117+
fn bench_predicate<const MULTIVERSIONED: bool>(
118+
bencher: Bencher,
119+
rows: usize,
120+
shape: InputShape,
121+
scenario: Scenario,
122+
) {
123+
let validity = match scenario {
124+
Scenario::AllValid | Scenario::ObservableFailure => Validity::NonNullable,
125+
Scenario::PartialAccepted | Scenario::NullOnlyFailure => Validity::Array(
126+
BoolArray::from_iter((0..rows).map(|index| !index.is_multiple_of(8))).into_array(),
127+
),
128+
};
129+
let rejected = matches!(
130+
scenario,
131+
Scenario::NullOnlyFailure | Scenario::ObservableFailure
132+
);
133+
let column = PrimitiveArray::new(
134+
(0..rows)
135+
.map(|index| {
136+
if rejected && index.is_multiple_of(8) {
137+
i64::MAX
138+
} else {
139+
i64::try_from(index % 1024).vortex_expect("fixture value is less than 1024")
140+
}
141+
})
142+
.collect::<Vec<_>>(),
143+
validity,
144+
)
145+
.into_array();
146+
let (lhs, rhs) = match shape {
147+
InputShape::Columns => (
148+
column,
149+
PrimitiveArray::from_iter((0..rows).map(|index| {
150+
i64::try_from(index % 512 + 1).vortex_expect("fixture value is at most 512")
151+
}))
152+
.into_array(),
153+
),
154+
InputShape::ConstantLhs => (ConstantArray::new(512_i64, rows).into_array(), column),
155+
InputShape::ConstantRhs => (column, ConstantArray::new(512_i64, rows).into_array()),
156+
};
157+
let args = VecExecutionArgs::new(vec![lhs, rhs], rows);
158+
let function = Predicate::<MULTIVERSIONED>;
159+
let result = execute_rows(
160+
&function,
161+
&EmptyOptions,
162+
&args,
163+
&mut SESSION.create_execution_ctx(),
164+
);
165+
assert_eq!(
166+
result.is_err(),
167+
matches!(scenario, Scenario::ObservableFailure)
168+
);
169+
drop(result);
170+
171+
bencher
172+
.counter(ItemsCount::new(rows))
173+
.with_inputs(|| (&args, SESSION.create_execution_ctx()))
174+
.bench_refs(|(args, ctx)| {
175+
let result = execute_rows(&function, &EmptyOptions, *args, ctx);
176+
drop(divan::black_box(result));
177+
});
178+
}

0 commit comments

Comments
 (0)