@@ -14,10 +14,13 @@ fn main() {
1414 divan:: main ( ) ;
1515}
1616
17- // Buffer size to test - focusing on 1024 for now
1817const 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 ) ]
2225enum Pattern {
2326 Random ,
@@ -35,7 +38,6 @@ impl fmt::Display for Pattern {
3538 }
3639}
3740
38- /// Creates a test buffer filled with sequential values.
3941fn create_test_buffer < T > ( size : usize ) -> BufferMut < T >
4042where
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.
5253fn 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) ]
214163struct 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