Skip to content

Commit d7c5ed2

Browse files
committed
refactor benchmark
Signed-off-by: Connor Tsui <[email protected]>
1 parent 3e086fa commit d7c5ed2

File tree

1 file changed

+45
-187
lines changed

1 file changed

+45
-187
lines changed

vortex-compute/benches/filter_buffer_mut.rs

Lines changed: 45 additions & 187 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@ fn main() {
1414
divan::main();
1515
}
1616

17-
// Buffer size to test - focusing on 1024 for now
1817
const BUFFER_SIZE: usize = 1024;
1918

20-
// Pattern types for testing.
19+
// Full selectivity spectrum with extra detail around the 80% threshold.
20+
const SELECTIVITIES: &[f64] = &[
21+
0.01, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.50, 0.75, 0.78, 0.79, 0.80, 0.81, 0.82, 0.85, 0.99,
22+
];
23+
2124
#[derive(Copy, Clone, Debug)]
2225
enum Pattern {
2326
Random,
@@ -35,7 +38,6 @@ impl fmt::Display for Pattern {
3538
}
3639
}
3740

38-
/// Creates a test buffer filled with sequential values.
3941
fn create_test_buffer<T>(size: usize) -> BufferMut<T>
4042
where
4143
T: Copy + Default + From<u8>,
@@ -48,16 +50,13 @@ where
4850
buffer
4951
}
5052

51-
/// Generates a mask with the specified selectivity and pattern.
5253
fn generate_mask(len: usize, selectivity: f64, pattern: Pattern) -> Mask {
5354
#[expect(clippy::cast_possible_truncation)]
5455
#[expect(clippy::cast_sign_loss)]
5556
let num_selected = ((len as f64) * selectivity).round() as usize;
5657

5758
let selection = match pattern {
5859
Pattern::Random => {
59-
// Random selection - distribute selected elements randomly.
60-
// Use a deterministic pattern for reproducibility.
6160
let mut selection = vec![false; len];
6261
let mut indices: Vec<usize> = (0..len).collect();
6362

@@ -73,7 +72,6 @@ fn generate_mask(len: usize, selectivity: f64, pattern: Pattern) -> Mask {
7372
selection
7473
}
7574
Pattern::Contiguous => {
76-
// One contiguous block in the middle.
7775
let mut selection = vec![false; len];
7876
let start = (len.saturating_sub(num_selected)) / 2;
7977
for i in start..(start + num_selected).min(len) {
@@ -82,7 +80,6 @@ fn generate_mask(len: usize, selectivity: f64, pattern: Pattern) -> Mask {
8280
selection
8381
}
8482
Pattern::Alternating => {
85-
// Select every nth element to achieve desired selectivity.
8683
let mut selection = vec![false; len];
8784
if num_selected > 0 {
8885
let step = len.max(1) / num_selected.max(1);
@@ -98,105 +95,61 @@ fn generate_mask(len: usize, selectivity: f64, pattern: Pattern) -> Mask {
9895
Mask::from_iter(selection)
9996
}
10097

101-
// ===== PRIMARY BENCHMARK: Full Selectivity Spectrum =====
102-
// This shows performance across the entire selectivity range
103-
// with extra detail around the 80% threshold.
104-
105-
// Macro to generate a type/size benchmark module with all selectivity benchmarks.
106-
macro_rules! type_size_bench_group {
107-
($mod_name:ident, $type:ty) => {
108-
#[divan::bench_group]
109-
mod $mod_name {
110-
use super::*;
111-
type T = $type;
112-
const SIZE: usize = BUFFER_SIZE;
113-
114-
// Inner macro for generating individual selectivity benchmarks.
115-
macro_rules! selectivity_bench {
116-
($name: ident,$selectivity: expr) => {
117-
#[divan::bench(sample_count = 1000)]
118-
fn $name(bencher: Bencher) {
119-
bencher
120-
.with_inputs(|| {
121-
let buffer = create_test_buffer::<T>(SIZE);
122-
let mask = generate_mask(SIZE, $selectivity, Pattern::Random);
123-
(buffer, mask)
124-
})
125-
.bench_values(|(mut buffer, mask)| {
126-
buffer.filter(&mask);
127-
divan::black_box(buffer);
128-
});
129-
}
130-
};
131-
}
132-
133-
// Generate benchmarks for each selectivity level.
134-
selectivity_bench!(sel_01_percent, 0.01);
135-
selectivity_bench!(sel_25_percent, 0.25);
136-
selectivity_bench!(sel_50_percent, 0.50);
137-
selectivity_bench!(sel_75_percent, 0.75);
138-
selectivity_bench!(sel_78_percent, 0.78);
139-
selectivity_bench!(sel_79_percent, 0.79);
140-
selectivity_bench!(sel_80_percent, 0.80);
141-
selectivity_bench!(sel_81_percent, 0.81);
142-
selectivity_bench!(sel_82_percent, 0.82);
143-
selectivity_bench!(sel_85_percent, 0.85);
144-
selectivity_bench!(sel_99_percent, 0.99);
145-
}
146-
};
98+
#[divan::bench(types = [u8, u32, u64], args = SELECTIVITIES, sample_count = 1000)]
99+
fn filter_selectivity<T: Copy + Default + From<u8>>(bencher: Bencher, selectivity: f64) {
100+
let mask = generate_mask(BUFFER_SIZE, selectivity, Pattern::Random);
101+
bencher
102+
.with_inputs(|| {
103+
let buffer = create_test_buffer::<T>(BUFFER_SIZE);
104+
(buffer, mask.clone())
105+
})
106+
.bench_values(|(mut buffer, mask)| {
107+
buffer.filter(&mask);
108+
divan::black_box(buffer);
109+
});
147110
}
148111

149-
// Generate benchmark modules for each type.
150-
type_size_bench_group!(u8_1024, u8);
151-
type_size_bench_group!(u32_1024, u32);
152-
type_size_bench_group!(u64_1024, u64);
153-
154-
// ===== PATTERN COMPARISON AT THRESHOLD =====
155-
// Test different patterns but ONLY at the 80% threshold where the algorithm choice matters most.
156-
// This tests whether certain patterns perform better with the index-based vs slice-based approach.
157-
158-
#[divan::bench_group]
159-
mod u32_1024_patterns {
112+
#[divan::bench_group(sample_count = 1000)]
113+
mod patterns_at_threshold {
160114
use super::*;
161-
type T = u32;
162-
const SIZE: usize = BUFFER_SIZE;
163-
const SELECTIVITY: f64 = 0.80;
164115

165-
#[divan::bench(sample_count = 1000)]
116+
const SELECTIVITY: f64 = 0.50;
117+
118+
#[divan::bench]
166119
fn random(bencher: Bencher) {
120+
let mask = generate_mask(BUFFER_SIZE, SELECTIVITY, Pattern::Random);
167121
bencher
168122
.with_inputs(|| {
169-
let buffer = create_test_buffer::<T>(SIZE);
170-
let mask = generate_mask(SIZE, SELECTIVITY, Pattern::Random);
171-
(buffer, mask)
123+
let buffer = create_test_buffer::<u32>(BUFFER_SIZE);
124+
(buffer, mask.clone())
172125
})
173126
.bench_values(|(mut buffer, mask)| {
174127
buffer.filter(&mask);
175128
divan::black_box(buffer);
176129
});
177130
}
178131

179-
#[divan::bench(sample_count = 1000)]
132+
#[divan::bench]
180133
fn contiguous(bencher: Bencher) {
134+
let mask = generate_mask(BUFFER_SIZE, SELECTIVITY, Pattern::Contiguous);
181135
bencher
182136
.with_inputs(|| {
183-
let buffer = create_test_buffer::<T>(SIZE);
184-
let mask = generate_mask(SIZE, SELECTIVITY, Pattern::Contiguous);
185-
(buffer, mask)
137+
let buffer = create_test_buffer::<u32>(BUFFER_SIZE);
138+
(buffer, mask.clone())
186139
})
187140
.bench_values(|(mut buffer, mask)| {
188141
buffer.filter(&mask);
189142
divan::black_box(buffer);
190143
});
191144
}
192145

193-
#[divan::bench(sample_count = 1000)]
146+
#[divan::bench]
194147
fn alternating(bencher: Bencher) {
148+
let mask = generate_mask(BUFFER_SIZE, SELECTIVITY, Pattern::Alternating);
195149
bencher
196150
.with_inputs(|| {
197-
let buffer = create_test_buffer::<T>(SIZE);
198-
let mask = generate_mask(SIZE, SELECTIVITY, Pattern::Alternating);
199-
(buffer, mask)
151+
let buffer = create_test_buffer::<u32>(BUFFER_SIZE);
152+
(buffer, mask.clone())
200153
})
201154
.bench_values(|(mut buffer, mask)| {
202155
buffer.filter(&mask);
@@ -205,10 +158,6 @@ mod u32_1024_patterns {
205158
}
206159
}
207160

208-
// ===== LARGE ELEMENT BENCHMARKS =====
209-
// Test with larger element sizes at the critical threshold range to understand
210-
// how memcpy performance affects the algorithms.
211-
212161
#[derive(Copy, Clone, Default)]
213162
#[allow(dead_code)]
214163
struct LargeElement([u8; 32]);
@@ -219,107 +168,16 @@ impl From<u8> for LargeElement {
219168
}
220169
}
221170

222-
#[divan::bench_group]
223-
mod large_elem_1024 {
224-
use super::*;
225-
type T = LargeElement;
226-
const SIZE: usize = BUFFER_SIZE;
227-
228-
#[divan::bench(sample_count = 1000)]
229-
fn sel_50_percent(bencher: Bencher) {
230-
bencher
231-
.with_inputs(|| {
232-
let buffer = create_test_buffer::<T>(SIZE);
233-
let mask = generate_mask(SIZE, 0.50, Pattern::Random);
234-
(buffer, mask)
235-
})
236-
.bench_values(|(mut buffer, mask)| {
237-
buffer.filter(&mask);
238-
divan::black_box(buffer);
239-
});
240-
}
241-
242-
#[divan::bench(sample_count = 1000)]
243-
fn sel_75_percent(bencher: Bencher) {
244-
bencher
245-
.with_inputs(|| {
246-
let buffer = create_test_buffer::<T>(SIZE);
247-
let mask = generate_mask(SIZE, 0.75, Pattern::Random);
248-
(buffer, mask)
249-
})
250-
.bench_values(|(mut buffer, mask)| {
251-
buffer.filter(&mask);
252-
divan::black_box(buffer);
253-
});
254-
}
255-
256-
#[divan::bench(sample_count = 1000)]
257-
fn sel_79_percent(bencher: Bencher) {
258-
bencher
259-
.with_inputs(|| {
260-
let buffer = create_test_buffer::<T>(SIZE);
261-
let mask = generate_mask(SIZE, 0.79, Pattern::Random);
262-
(buffer, mask)
263-
})
264-
.bench_values(|(mut buffer, mask)| {
265-
buffer.filter(&mask);
266-
divan::black_box(buffer);
267-
});
268-
}
269-
270-
#[divan::bench(sample_count = 1000)]
271-
fn sel_80_percent(bencher: Bencher) {
272-
bencher
273-
.with_inputs(|| {
274-
let buffer = create_test_buffer::<T>(SIZE);
275-
let mask = generate_mask(SIZE, 0.80, Pattern::Random);
276-
(buffer, mask)
277-
})
278-
.bench_values(|(mut buffer, mask)| {
279-
buffer.filter(&mask);
280-
divan::black_box(buffer);
281-
});
282-
}
283-
284-
#[divan::bench(sample_count = 1000)]
285-
fn sel_81_percent(bencher: Bencher) {
286-
bencher
287-
.with_inputs(|| {
288-
let buffer = create_test_buffer::<T>(SIZE);
289-
let mask = generate_mask(SIZE, 0.81, Pattern::Random);
290-
(buffer, mask)
291-
})
292-
.bench_values(|(mut buffer, mask)| {
293-
buffer.filter(&mask);
294-
divan::black_box(buffer);
295-
});
296-
}
297-
298-
#[divan::bench]
299-
fn sel_85_percent(bencher: Bencher) {
300-
bencher
301-
.with_inputs(|| {
302-
let buffer = create_test_buffer::<T>(SIZE);
303-
let mask = generate_mask(SIZE, 0.85, Pattern::Random);
304-
(buffer, mask)
305-
})
306-
.bench_values(|(mut buffer, mask)| {
307-
buffer.filter(&mask);
308-
divan::black_box(buffer);
309-
});
310-
}
311-
312-
#[divan::bench]
313-
fn sel_90_percent(bencher: Bencher) {
314-
bencher
315-
.with_inputs(|| {
316-
let buffer = create_test_buffer::<T>(SIZE);
317-
let mask = generate_mask(SIZE, 0.90, Pattern::Random);
318-
(buffer, mask)
319-
})
320-
.bench_values(|(mut buffer, mask)| {
321-
buffer.filter(&mask);
322-
divan::black_box(buffer);
323-
});
324-
}
171+
#[divan::bench(args = SELECTIVITIES, sample_count = 1000)]
172+
fn filter_large_element(bencher: Bencher, selectivity: f64) {
173+
let mask = generate_mask(BUFFER_SIZE, selectivity, Pattern::Random);
174+
bencher
175+
.with_inputs(|| {
176+
let buffer = create_test_buffer::<LargeElement>(BUFFER_SIZE);
177+
(buffer, mask.clone())
178+
})
179+
.bench_values(|(mut buffer, mask)| {
180+
buffer.filter(&mask);
181+
divan::black_box(buffer);
182+
});
325183
}

0 commit comments

Comments
 (0)