Skip to content

Commit 9fcb4a7

Browse files
committed
Add scalar function performance baselines
Adds stable CodSpeed benchmark names for `byte_length`, tensor scalar functions, and the geo binary predicates. The benchmarks use public construction and execution APIs, which lets later implementation changes compare directly against this baseline. CodSpeed runs tensor and geo in a dedicated shard. Each benchmark binary uses vendored `mimalloc` because scalar function execution allocates its output inside the timed trace. `Normalized` keeps its checked inherent constructor because `ScalarFnFactoryExt` cannot represent its normalized-row invariant. Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
1 parent 0a92c58 commit 9fcb4a7

11 files changed

Lines changed: 795 additions & 0 deletions

File tree

‎.github/workflows/codspeed.yml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ jobs:
5757
- { shard: 6, name: "Encodings 3", packages: "vortex-pco vortex-runend vortex-sequence" }
5858
- { shard: 7, name: "Encodings 4", packages: "vortex-sparse vortex-zigzag vortex-zstd" }
5959
- { shard: 8, name: "Storage formats & row encoding", packages: "vortex-flatbuffers vortex-proto vortex-btrblocks vortex-row" }
60+
- { shard: 9, name: "Tensor & geo", packages: "vortex-tensor vortex-geo" }
6061
name: "Benchmark with Codspeed (Shard #${{ matrix.shard }})"
6162
timeout-minutes: 30
6263
runs-on: >-

‎Cargo.lock‎

Lines changed: 3 additions & 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: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@ harness = false
137137
name = "like"
138138
harness = false
139139

140+
[[bench]]
141+
name = "byte_length"
142+
harness = false
143+
140144
[[bench]]
141145
name = "interleave"
142146
harness = false
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3+
4+
//! Baseline throughput for `byte_length` over UTF-8 view arrays.
5+
//!
6+
//! The arms cover inline and out-of-line views, plus nullable out-of-line views. Their names are
7+
//! intended to remain stable across scalar-function implementation changes so CodSpeed can compare
8+
//! them against `develop`.
9+
10+
#![expect(clippy::unwrap_used)]
11+
12+
use std::sync::LazyLock;
13+
14+
use divan::Bencher;
15+
use divan::counter::ItemsCount;
16+
use mimalloc::MiMalloc;
17+
use vortex_array::ArrayRef;
18+
use vortex_array::Canonical;
19+
use vortex_array::IntoArray;
20+
use vortex_array::VortexSessionExecute;
21+
use vortex_array::array_session;
22+
use vortex_array::arrays::MaskedArray;
23+
use vortex_array::arrays::VarBinViewArray;
24+
use vortex_array::arrays::scalar_fn::ScalarFnFactoryExt;
25+
use vortex_array::scalar_fn::EmptyOptions;
26+
use vortex_array::scalar_fn::fns::byte_length::ByteLength;
27+
use vortex_array::validity::Validity;
28+
use vortex_session::VortexSession;
29+
30+
// Scalar function execution allocates its output inside the timed region, so use the vendored
31+
// allocator instead of measuring glibc differences between CodSpeed runner images.
32+
#[global_allocator]
33+
static GLOBAL: MiMalloc = MiMalloc;
34+
35+
static SESSION: LazyLock<VortexSession> = LazyLock::new(array_session);
36+
37+
fn main() {
38+
LazyLock::force(&SESSION);
39+
divan::main();
40+
}
41+
42+
const SIZES: &[usize] = &[4_096, 65_536];
43+
44+
fn long_strings(len: usize) -> ArrayRef {
45+
VarBinViewArray::from_iter_str((0..len).map(|i| format!("a string well past inline: {i}")))
46+
.into_array()
47+
}
48+
49+
fn short_strings(len: usize) -> ArrayRef {
50+
VarBinViewArray::from_iter_str((0..len).map(|i| format!("{}", i % 1_000))).into_array()
51+
}
52+
53+
fn bench_byte_length(bencher: Bencher, input: ArrayRef) {
54+
let len = input.len();
55+
bencher
56+
.counter(ItemsCount::new(len))
57+
.with_inputs(|| {
58+
(
59+
ByteLength
60+
.try_new_array(len, EmptyOptions, [input.clone()])
61+
.unwrap(),
62+
SESSION.create_execution_ctx(),
63+
)
64+
})
65+
.bench_values(|(array, mut ctx)| array.execute::<Canonical>(&mut ctx).unwrap());
66+
}
67+
68+
#[divan::bench(args = SIZES)]
69+
fn inline(bencher: Bencher, len: usize) {
70+
bench_byte_length(bencher, short_strings(len));
71+
}
72+
73+
#[divan::bench(args = SIZES)]
74+
fn out_of_line(bencher: Bencher, len: usize) {
75+
bench_byte_length(bencher, long_strings(len));
76+
}
77+
78+
#[divan::bench(args = SIZES)]
79+
fn nullable_out_of_line(bencher: Bencher, len: usize) {
80+
let validity = Validity::from_iter((0..len).map(|i| i % 8 != 0));
81+
let input = MaskedArray::try_new(long_strings(len), validity)
82+
.unwrap()
83+
.into_array();
84+
bench_byte_length(bencher, input);
85+
}

‎vortex-geo/Cargo.toml‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ _test-harness = []
3636

3737
[dev-dependencies]
3838
divan = { workspace = true }
39+
mimalloc = { workspace = true }
3940
rstest = { workspace = true }
4041
vortex-array = { workspace = true, features = ["_test-harness"] }
4142
vortex-geo = { path = ".", features = ["_test-harness"] }
@@ -45,5 +46,9 @@ vortex-layout = { workspace = true }
4546
name = "envelope"
4647
harness = false
4748

49+
[[bench]]
50+
name = "binary_predicates"
51+
harness = false
52+
4853
[lints]
4954
workspace = true

0 commit comments

Comments
 (0)