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