@@ -43,13 +43,15 @@ mod render;
4343// ---------------------------------------------------------------------------
4444
4545/// Access pattern for random access benchmarks.
46- #[ derive( Clone , Copy , Debug , Hash , PartialEq , Eq ) ]
46+ #[ derive( Clone , Copy , Debug , Hash , PartialEq , Eq , ValueEnum ) ]
4747pub enum AccessPattern {
4848 /// Multiple clusters of sequential indices scattered across the dataset,
4949 /// simulating workloads with spatial locality (e.g. scanning nearby records).
50+ #[ clap( name = "correlated" ) ]
5051 Correlated ,
5152 /// Indices generated by a Poisson process (exponential inter-arrival times)
5253 /// spread uniformly across the dataset, simulating random lookups with no locality.
54+ #[ clap( name = "uniform" ) ]
5355 Uniform ,
5456}
5557
@@ -62,8 +64,6 @@ impl AccessPattern {
6264 }
6365}
6466
65- const ACCESS_PATTERNS : [ AccessPattern ; 2 ] = [ AccessPattern :: Correlated , AccessPattern :: Uniform ] ;
66-
6767/// Number of clusters for the correlated pattern.
6868const NUM_CLUSTERS : usize = 5 ;
6969
@@ -190,6 +190,14 @@ struct Args {
190190 default_values_t = vec![ DatasetArg :: Taxi , DatasetArg :: FeatureVectors , DatasetArg :: NestedLists , DatasetArg :: NestedStructs ]
191191 ) ]
192192 datasets : Vec < DatasetArg > ,
193+ /// Which access patterns to benchmark.
194+ #[ arg(
195+ long,
196+ value_delimiter = ',' ,
197+ value_enum,
198+ default_values_t = vec![ AccessPattern :: Correlated , AccessPattern :: Uniform ]
199+ ) ]
200+ patterns : Vec < AccessPattern > ,
193201 /// Whether to reopen the file on each iteration, use a cached handle, or run both.
194202 #[ arg( long, value_enum, default_value_t = OpenMode :: Both ) ]
195203 open_mode : OpenMode ,
@@ -201,22 +209,22 @@ async fn main() -> Result<()> {
201209
202210 setup_logging_and_tracing ( args. verbose , args. tracing ) ?;
203211
204- let datasets : Vec < Box < dyn BenchDataset > > = args
205- . datasets
206- . into_iter ( )
207- . map ( |d| d . into_dataset ( ) )
208- . collect ( ) ;
209-
210- run_random_access (
211- & datasets ,
212- args. formats ,
213- args. time_limit ,
214- args. open_mode ,
215- args. display_format ,
216- args. output_path ,
217- args . gh_json_v3 ,
218- )
219- . await
212+ let config = RunConfig {
213+ datasets : args
214+ . datasets
215+ . into_iter ( )
216+ . map ( |d| d . into_dataset ( ) )
217+ . collect ( ) ,
218+ formats : args . formats ,
219+ patterns : args . patterns ,
220+ time_limit : args. time_limit ,
221+ open_mode : args. open_mode ,
222+ display_format : args. display_format ,
223+ output_path : args. output_path ,
224+ gh_json_v3 : args. gh_json_v3 ,
225+ } ;
226+
227+ run_random_access ( config ) . await
220228}
221229
222230// ---------------------------------------------------------------------------
@@ -379,15 +387,30 @@ const BENCHMARK_ID: &str = "random-access";
379387/// Fixed indices used by the original taxi benchmark (preserved for historical continuity).
380388const FIXED_TAXI_INDICES : [ u64 ; 6 ] = [ 10 , 11 , 12 , 13 , 100_000 , 3_000_000 ] ;
381389
382- async fn run_random_access (
383- datasets : & [ Box < dyn BenchDataset > ] ,
390+ /// Resolved configuration for a single random-access benchmark invocation.
391+ struct RunConfig {
392+ datasets : Vec < Box < dyn BenchDataset > > ,
384393 formats : Vec < Format > ,
394+ patterns : Vec < AccessPattern > ,
385395 time_limit : u64 ,
386396 open_mode : OpenMode ,
387397 display_format : DisplayFormat ,
388398 output_path : Option < PathBuf > ,
389399 gh_json_v3 : Option < PathBuf > ,
390- ) -> Result < ( ) > {
400+ }
401+
402+ async fn run_random_access ( config : RunConfig ) -> Result < ( ) > {
403+ let RunConfig {
404+ datasets,
405+ formats,
406+ patterns,
407+ time_limit,
408+ open_mode,
409+ display_format,
410+ output_path,
411+ gh_json_v3,
412+ } = config;
413+
391414 let reopen_variants: & [ bool ] = match open_mode {
392415 OpenMode :: Cached => & [ false ] ,
393416 OpenMode :: Reopen => & [ true ] ,
@@ -398,7 +421,7 @@ async fn run_random_access(
398421 . iter ( )
399422 . map ( |d| {
400423 let legacy_extra = if d. name ( ) == "taxi" { formats. len ( ) } else { 0 } ;
401- ( formats. len ( ) * ACCESS_PATTERNS . len ( ) + legacy_extra) * reopen_variants. len ( )
424+ ( formats. len ( ) * patterns . len ( ) + legacy_extra) * reopen_variants. len ( )
402425 } )
403426 . sum ( ) ;
404427 let progress = ProgressBar :: new ( total_steps as u64 ) ;
@@ -408,7 +431,7 @@ async fn run_random_access(
408431
409432 // Iteration order matters for the table renderer: row order is set by the
410433 // first time each `(dataset, pattern)` pair is observed.
411- for dataset in datasets {
434+ for dataset in & datasets {
412435 for format in & formats {
413436 if dataset. name ( ) == "taxi" {
414437 let name = measurement_name ( dataset. name ( ) , None , * format) ;
@@ -436,7 +459,7 @@ async fn run_random_access(
436459 }
437460 }
438461
439- for pattern in & ACCESS_PATTERNS {
462+ for pattern in & patterns {
440463 let indices = generate_indices ( dataset. as_ref ( ) , * pattern) ;
441464 let name = measurement_name ( dataset. name ( ) , Some ( * pattern) , * format) ;
442465 for & reopen in reopen_variants {
0 commit comments