1+ use core:: ops:: Range ;
12use criterion:: { criterion_group, criterion_main, BenchmarkId , Criterion , Throughput } ;
23use fastpfor:: rust:: { FastPFOR , Integer , BLOCK_SIZE_128 , BLOCK_SIZE_256 , DEFAULT_PAGE_SIZE } ;
34use rand:: rngs:: StdRng ;
@@ -8,15 +9,27 @@ use std::io::Cursor;
89const SIZES : & [ usize ; 2 ] = & [ 1024 , 4096 ] ;
910const SEED : u64 = 456 ;
1011
12+ type DataGeneratorFn = fn ( usize ) -> Vec < u32 > ;
13+
1114/// Generate uniformly distributed random data
12- fn generate_uniform_data ( size : usize , max_value : u32 ) -> Vec < u32 > {
13- let mut rng = StdRng :: seed_from_u64 ( black_box ( SEED ) ) ;
14- ( 0 ..size) . map ( |_| rng. random_range ( 0 ..max_value) ) . collect ( )
15+ fn generate_uniform_data_from_range ( size : usize , value_range : Range < u32 > ) -> Vec < u32 > {
16+ let mut rng = StdRng :: seed_from_u64 ( SEED ) ;
17+ ( 0 ..size)
18+ . map ( |_| rng. random_range ( value_range. clone ( ) ) )
19+ . collect ( )
20+ }
21+
22+ fn generate_uniform_data_small_value_distribution ( size : usize ) -> Vec < u32 > {
23+ generate_uniform_data_from_range ( size, 0 ..1000 )
24+ }
25+
26+ fn generate_uniform_data_large_value_distribution ( size : usize ) -> Vec < u32 > {
27+ generate_uniform_data_from_range ( size, 0 ..u32:: MAX )
1528}
1629
1730/// Generate clustered data - values tend to cluster around changing base values
1831fn generate_clustered_data ( size : usize ) -> Vec < u32 > {
19- let mut rng = StdRng :: seed_from_u64 ( black_box ( SEED ) ) ;
32+ let mut rng = StdRng :: seed_from_u64 ( SEED ) ;
2033 let mut data = Vec :: with_capacity ( size) ;
2134 let mut base = 0u32 ;
2235
@@ -37,7 +50,7 @@ fn generate_sequential_data(size: usize) -> Vec<u32> {
3750
3851/// Generate sparse data - mostly zeros with occasional random values
3952fn generate_sparse_data ( size : usize ) -> Vec < u32 > {
40- let mut rng = StdRng :: seed_from_u64 ( black_box ( SEED ) ) ;
53+ let mut rng = StdRng :: seed_from_u64 ( SEED ) ;
4154 ( 0 ..size)
4255 . map ( |_| {
4356 if rng. random_bool ( 0.9 ) {
@@ -50,8 +63,8 @@ fn generate_sparse_data(size: usize) -> Vec<u32> {
5063}
5164
5265/// Generate constant data - best case for compression
53- fn generate_constant_data ( size : usize , value : u32 ) -> Vec < u32 > {
54- vec ! [ value ; size]
66+ fn generate_constant_data ( size : usize ) -> Vec < u32 > {
67+ vec ! [ SEED as u32 ; size]
5568}
5669
5770/// Generate data with powers of two
@@ -122,18 +135,22 @@ fn decompress_data(codec: &mut FastPFOR, compressed: &[u32], original_size: usiz
122135fn benchmark_compression ( c : & mut Criterion ) {
123136 let mut group = c. benchmark_group ( "compression" ) ;
124137
125- let patterns: Vec < ( & str , fn ( usize ) -> Vec < u32 > ) > = vec ! [
126- ( "uniform_small" , |size| generate_uniform_data( size, 1000 ) ) ,
127- ( "uniform_large" , |size| {
128- generate_uniform_data( size, u32 :: MAX )
129- } ) ,
138+ let patterns: & [ ( & str , DataGeneratorFn ) ] = & [
139+ (
140+ "uniform_small_value_distribution" ,
141+ generate_uniform_data_small_value_distribution,
142+ ) ,
143+ (
144+ "uniform_large_value_distribution" ,
145+ generate_uniform_data_large_value_distribution,
146+ ) ,
130147 ( "clustered" , generate_clustered_data) ,
131148 ( "sequential" , generate_sequential_data) ,
132149 ( "sparse" , generate_sparse_data) ,
133150 ] ;
134151
135152 for & size in SIZES {
136- for ( name, generator) in & patterns {
153+ for ( name, generator) in patterns {
137154 let data = generator ( size) ;
138155 group. throughput ( Throughput :: Elements ( size as u64 ) ) ;
139156 group. bench_with_input ( BenchmarkId :: new ( * name, size) , & data, |b, data| {
@@ -151,18 +168,22 @@ fn benchmark_compression(c: &mut Criterion) {
151168fn benchmark_decompression ( c : & mut Criterion ) {
152169 let mut group = c. benchmark_group ( "decompression" ) ;
153170
154- let patterns: Vec < ( & str , fn ( usize ) -> Vec < u32 > ) > = vec ! [
155- ( "uniform_small" , |size| generate_uniform_data( size, 1000 ) ) ,
156- ( "uniform_large" , |size| {
157- generate_uniform_data( size, u32 :: MAX )
158- } ) ,
171+ let patterns: & [ ( & str , DataGeneratorFn ) ] = & [
172+ (
173+ "uniform_small_value_distribution" ,
174+ generate_uniform_data_small_value_distribution,
175+ ) ,
176+ (
177+ "uniform_large_value_distribution" ,
178+ generate_uniform_data_large_value_distribution,
179+ ) ,
159180 ( "clustered" , generate_clustered_data) ,
160181 ( "sequential" , generate_sequential_data) ,
161182 ( "sparse" , generate_sparse_data) ,
162183 ] ;
163184
164185 for & size in SIZES {
165- for ( name, generator) in & patterns {
186+ for ( name, generator) in patterns {
166187 let data = generator ( size) ;
167188 let compressed = prepare_compressed_data ( & data, BLOCK_SIZE_128 ) ;
168189
@@ -187,7 +208,7 @@ fn benchmark_roundtrip(c: &mut Criterion) {
187208 let mut group = c. benchmark_group ( "roundtrip" ) ;
188209
189210 for & size in SIZES {
190- let data = generate_uniform_data ( size, 1000 ) ;
211+ let data = generate_uniform_data_small_value_distribution ( size) ;
191212
192213 group. throughput ( Throughput :: Elements ( size as u64 ) ) ;
193214 group. bench_with_input (
@@ -239,7 +260,7 @@ fn benchmark_block_sizes(c: &mut Criterion) {
239260 let mut group = c. benchmark_group ( "block_sizes" ) ;
240261
241262 let size = * SIZES . last ( ) . unwrap ( ) ;
242- let data = generate_uniform_data ( size, 1000 ) ;
263+ let data = generate_uniform_data_small_value_distribution ( size) ;
243264
244265 let block_sizes = [ BLOCK_SIZE_128 , BLOCK_SIZE_256 ] ;
245266
@@ -275,22 +296,32 @@ fn benchmark_compression_ratio(c: &mut Criterion) {
275296 group. sample_size ( 20 ) ; // Fewer samples since we're measuring ratio, not just speed
276297
277298 let size = * SIZES . last ( ) . unwrap ( ) ;
278- let patterns = vec ! [
279- ( "uniform_small" , generate_uniform_data( size, 100 ) ) ,
280- ( "uniform_medium" , generate_uniform_data( size, 10000 ) ) ,
281- ( "uniform_large" , generate_uniform_data( size, u32 :: MAX ) ) ,
282- ( "clustered" , generate_clustered_data( size) ) ,
283- ( "sequential" , generate_sequential_data( size) ) ,
284- ( "sparse" , generate_sparse_data( size) ) ,
285- ( "constant" , generate_constant_data( size, 42 ) ) ,
286- ( "geometric" , generate_geometric_data( size) ) ,
299+ let patterns: & [ ( & str , DataGeneratorFn ) ] = & [
300+ (
301+ "uniform_small_distribution" ,
302+ generate_uniform_data_small_value_distribution,
303+ ) ,
304+ (
305+ "uniform_large_distribution" ,
306+ generate_uniform_data_large_value_distribution,
307+ ) ,
308+ ( "clustered" , generate_clustered_data) ,
309+ ( "sequential" , generate_sequential_data) ,
310+ ( "sparse" , generate_sparse_data) ,
311+ ( "constant" , generate_constant_data) ,
312+ ( "geometric" , generate_geometric_data) ,
287313 ] ;
288314
289- for ( name, data) in patterns {
290- group. bench_function ( name, |b| {
315+ for ( name, data_fn) in patterns {
316+ let data = data_fn ( size) ;
317+ group. bench_function ( * name, |b| {
291318 b. iter ( || {
292319 let mut codec = FastPFOR :: default ( ) ;
293320 let compressed_size = compress_data ( & mut codec, black_box ( & data) ) ;
321+ #[ expect(
322+ clippy:: cast_precision_loss,
323+ reason = "Loss of precision is acceptable for compression ratio calculation"
324+ ) ]
294325 let ratio = data. len ( ) as f64 / compressed_size as f64 ;
295326 black_box ( ratio)
296327 } ) ;
0 commit comments