11use  crate :: { 
22    app:: { Filters ,  PackageFilters } , 
33    helpers:: get_codspeed_target_dir, 
4+     measurement_mode:: MeasurementMode , 
45    prelude:: * , 
6+     walltime_results:: { WalltimeBenchmark ,  WalltimeResults } , 
57} ; 
8+ use  anyhow:: Context ; 
69use  cargo_metadata:: { Metadata ,  Package } ; 
7- use  std:: { io,  path:: PathBuf } ; 
10+ use  codspeed:: walltime:: get_raw_result_dir_from_workspace_root; 
11+ use  glob:: glob; 
12+ use  std:: { 
13+     io:: { self ,  Write } , 
14+     path:: { Path ,  PathBuf } , 
15+ } ; 
816
917struct  BenchToRun  { 
1018    bench_path :  PathBuf , 
@@ -86,8 +94,16 @@ impl PackageFilters {
8694    } 
8795} 
8896
89- pub  fn  run_benches ( metadata :  & Metadata ,  filters :  Filters )  -> Result < ( ) >  { 
97+ pub  fn  run_benches ( 
98+     metadata :  & Metadata , 
99+     filters :  Filters , 
100+     measurement_mode :  MeasurementMode , 
101+ )  -> Result < ( ) >  { 
90102    let  codspeed_target_dir = get_codspeed_target_dir ( metadata) ; 
103+     let  workspace_root = metadata. workspace_root . as_std_path ( ) ; 
104+     if  measurement_mode == MeasurementMode :: Walltime  { 
105+         clear_raw_walltime_data ( workspace_root) ?; 
106+     } 
91107    let  benches = filters. benches_to_run ( codspeed_target_dir,  metadata) ?; 
92108    if  benches. is_empty ( )  { 
93109        bail ! ( "No benchmarks found. Run `cargo codspeed build` first." ) ; 
@@ -125,9 +141,16 @@ pub fn run_benches(metadata: &Metadata, filters: Filters) -> Result<()> {
125141        // while CARGO_MANIFEST_DIR returns the path to the sub package 
126142        let  workspace_root = metadata. workspace_root . clone ( ) ; 
127143        eprintln ! ( "Running {} {}" ,  & bench. package_name,  bench_name) ; 
128-         std:: process:: Command :: new ( & bench. bench_path ) 
144+         let  mut  command = std:: process:: Command :: new ( & bench. bench_path ) ; 
145+         command
129146            . env ( "CODSPEED_CARGO_WORKSPACE_ROOT" ,  workspace_root) 
130-             . current_dir ( & bench. working_directory ) 
147+             . current_dir ( & bench. working_directory ) ; 
148+ 
149+         if  measurement_mode == MeasurementMode :: Walltime  { 
150+             command. arg ( "--bench" ) ;  // Walltime targets need this additional argument (inherited from running them with `cargo bench`) 
151+         } 
152+ 
153+         command
131154            . status ( ) 
132155            . map_err ( |e| anyhow ! ( "failed to execute the benchmark process: {}" ,  e) ) 
133156            . and_then ( |status| { 
@@ -143,5 +166,54 @@ pub fn run_benches(metadata: &Metadata, filters: Filters) -> Result<()> {
143166        eprintln ! ( "Done running {}" ,  bench_name) ; 
144167    } 
145168    eprintln ! ( "Finished running {} benchmark suite(s)" ,  to_run. len( ) ) ; 
169+ 
170+     if  measurement_mode == MeasurementMode :: Walltime  { 
171+         aggregate_raw_walltime_data ( workspace_root) ?; 
172+     } 
173+ 
174+     Ok ( ( ) ) 
175+ } 
176+ 
177+ fn  clear_raw_walltime_data ( workspace_root :  & Path )  -> Result < ( ) >  { 
178+     let  raw_results_dir = get_raw_result_dir_from_workspace_root ( workspace_root) ; 
179+     std:: fs:: remove_dir_all ( & raw_results_dir) . ok ( ) ;  // ignore errors when the directory does not exist 
180+     std:: fs:: create_dir_all ( & raw_results_dir) . context ( "Failed to create raw_results directory" ) ?; 
181+     Ok ( ( ) ) 
182+ } 
183+ 
184+ fn  aggregate_raw_walltime_data ( workspace_root :  & Path )  -> Result < ( ) >  { 
185+     let  mut  walltime_benchmarks:  Vec < WalltimeBenchmark >  = Vec :: new ( ) ; 
186+     // retrieve data from `{workspace_root}/target/codspeed/raw_results/{scope}/*.json 
187+     for  sample in  glob ( 
188+         get_raw_result_dir_from_workspace_root ( workspace_root) 
189+             . join ( "**/*.json" ) 
190+             . to_str ( ) 
191+             . unwrap ( ) , 
192+     ) ? { 
193+         let  sample = sample?; 
194+         let  raw_walltime_data:  codspeed:: walltime:: RawWallTimeData  =
195+             serde_json:: from_reader ( std:: fs:: File :: open ( & sample) ?) ?; 
196+         walltime_benchmarks. push ( WalltimeBenchmark :: from ( raw_walltime_data) ) ; 
197+     } 
198+ 
199+     if  walltime_benchmarks. is_empty ( )  { 
200+         eprintln ! ( "No walltime benchmarks found" ) ; 
201+         return  Ok ( ( ) ) ; 
202+     } 
203+ 
204+     let  results_folder = std:: env:: var ( "CODSPEED_PROFILE_FOLDER" ) 
205+         . map ( PathBuf :: from) 
206+         . unwrap_or_else ( |_| workspace_root. join ( "target/codspeed/profiles" ) ) 
207+         . join ( "results" ) ; 
208+     std:: fs:: create_dir_all ( & results_folder) . context ( "Failed to create results folder" ) ?; 
209+ 
210+     let  results = WalltimeResults :: from_benchmarks ( walltime_benchmarks) ; 
211+     let  results_path = results_folder. join ( format ! ( "{}.json" ,  std:: process:: id( ) ) ) ; 
212+     let  mut  results_file =
213+         std:: fs:: File :: create ( & results_path) . context ( "Failed to create results file" ) ?; 
214+     serde_json:: to_writer_pretty ( & results_file,  & results) ?; 
215+     results_file
216+         . flush ( ) 
217+         . context ( "Failed to flush results file" ) ?; 
146218    Ok ( ( ) ) 
147219} 
0 commit comments