Skip to content

Commit 7efebc4

Browse files
chore[mask]: intersect_by_rank benchmarks (#7083)
Adds a benchmark for intersect_by_rank to later optimize --------- Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
1 parent 124c698 commit 7efebc4

3 files changed

Lines changed: 121 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-mask/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,12 @@ vortex-buffer = { workspace = true, features = ["arrow"] }
2828
vortex-error = { workspace = true }
2929

3030
[dev-dependencies]
31+
divan = { workspace = true }
3132
rstest = { workspace = true }
3233

34+
[[bench]]
35+
name = "intersect_by_rank"
36+
harness = false
37+
3338
[lints]
3439
workspace = true
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3+
4+
//! Benchmarks for `intersect_by_rank`.
5+
6+
#![allow(clippy::unwrap_used, clippy::cast_possible_truncation)]
7+
8+
use divan::Bencher;
9+
use vortex_buffer::BitBuffer;
10+
use vortex_mask::Mask;
11+
12+
fn main() {
13+
divan::main();
14+
}
15+
16+
// Standard test cases
17+
const BENCH_ARGS: &[(usize, &str)] = &[
18+
(10_000, "random"),
19+
(10_000, "runs"),
20+
(100_000, "random"),
21+
(100_000, "runs"),
22+
];
23+
24+
// Sparse test cases (varying base selectivity)
25+
const SPARSE_ARGS: &[(usize, f64, &str)] = &[
26+
(100_000, 0.01, "sparse_1pct"),
27+
(100_000, 0.05, "sparse_5pct"),
28+
(100_000, 0.10, "sparse_10pct"),
29+
(100_000, 0.50, "dense_50pct"),
30+
];
31+
32+
// Four-case density matrix: (self_density, mask_density)
33+
const DENSITY_MATRIX_ARGS: &[(f64, f64, &str)] = &[
34+
(0.05, 0.05, "self_sparse_mask_sparse"),
35+
(0.05, 0.50, "self_sparse_mask_dense"),
36+
(0.50, 0.05, "self_dense_mask_sparse"),
37+
(0.50, 0.50, "self_dense_mask_dense"),
38+
];
39+
40+
fn create_random_mask(len: usize, selectivity: f64) -> Mask {
41+
Mask::from_buffer(BitBuffer::from_iter((0..len).map(|i| {
42+
let threshold = (selectivity * 1000.0) as usize;
43+
(i * 7 + 13) % 1000 < threshold
44+
})))
45+
}
46+
47+
fn create_runs_mask(len: usize, run_len: usize, gap_len: usize) -> Mask {
48+
Mask::from_buffer(BitBuffer::from_iter((0..len).map(|i| {
49+
let cycle = run_len + gap_len;
50+
(i % cycle) < run_len
51+
})))
52+
}
53+
54+
fn create_fixture(size: usize, pattern: &str) -> (Mask, Mask) {
55+
match pattern {
56+
"random" => {
57+
let base = create_random_mask(size, 0.5);
58+
let rank_len = base.true_count();
59+
let rank = create_random_mask(rank_len, 0.5);
60+
(base, rank)
61+
}
62+
"runs" => {
63+
let base = create_runs_mask(size, 64, 64);
64+
let rank_len = base.true_count();
65+
let rank = create_runs_mask(rank_len, 64, 64);
66+
(base, rank)
67+
}
68+
_ => unreachable!(),
69+
}
70+
}
71+
72+
fn create_sparse_fixture(size: usize, selectivity: f64) -> (Mask, Mask) {
73+
let base = create_random_mask(size, selectivity);
74+
let rank_len = base.true_count();
75+
let rank = create_random_mask(rank_len, 0.5);
76+
(base, rank)
77+
}
78+
79+
fn create_density_matrix_fixture(
80+
size: usize,
81+
self_density: f64,
82+
mask_density: f64,
83+
) -> (Mask, Mask) {
84+
let base = create_random_mask(size, self_density);
85+
let rank_len = base.true_count();
86+
let rank = create_random_mask(rank_len, mask_density);
87+
(base, rank)
88+
}
89+
90+
/// Standard patterns (random / runs)
91+
#[divan::bench(args = BENCH_ARGS)]
92+
fn intersect_by_rank(bencher: Bencher, (size, pattern): (usize, &str)) {
93+
let (base, rank) = create_fixture(size, pattern);
94+
bencher
95+
.with_inputs(|| (&base, &rank))
96+
.bench_refs(|(base, rank)| base.intersect_by_rank(rank));
97+
}
98+
99+
/// Sparse base masks (varying selectivity)
100+
#[divan::bench(args = SPARSE_ARGS)]
101+
fn sparse(bencher: Bencher, (size, selectivity, _name): (usize, f64, &str)) {
102+
let (base, rank) = create_sparse_fixture(size, selectivity);
103+
bencher
104+
.with_inputs(|| (&base, &rank))
105+
.bench_refs(|(base, rank)| base.intersect_by_rank(rank));
106+
}
107+
108+
/// Density matrix (self_density x mask_density)
109+
#[divan::bench(args = DENSITY_MATRIX_ARGS)]
110+
fn density_matrix(bencher: Bencher, (self_density, mask_density, _name): (f64, f64, &str)) {
111+
let (base, rank) = create_density_matrix_fixture(100_000, self_density, mask_density);
112+
bencher
113+
.with_inputs(|| (&base, &rank))
114+
.bench_refs(|(base, rank)| base.intersect_by_rank(rank));
115+
}

0 commit comments

Comments
 (0)