@@ -3,7 +3,7 @@ use clap::ValueEnum;
33use log:: { debug, info} ;
44use serde_json:: { json, Value } ;
55use std:: collections:: HashMap ;
6- use std:: path:: Path ;
6+ use std:: path:: { Path , PathBuf } ;
77use std:: process:: Command ;
88
99mod build;
@@ -20,36 +20,57 @@ use crate::types::Network;
2020
2121pub struct Runner {
2222 config : GlobalConfig ,
23+ out_dir : PathBuf ,
2324}
2425
2526impl Runner {
26- pub fn new ( config : GlobalConfig ) -> Result < Self > {
27- Ok ( Self { config } )
27+ pub fn new (
28+ config : GlobalConfig ,
29+ out_dir : PathBuf ,
30+ app_config : & PathBuf ,
31+ bench_config : & PathBuf ,
32+ ) -> Result < Self > {
33+ // Configure stage
34+ debug ! ( "Using output directory: {}" , out_dir. display( ) ) ;
35+ std:: fs:: create_dir_all ( & out_dir) ?;
36+ if std:: fs:: read_dir ( & out_dir) ?. next ( ) . is_some ( ) {
37+ anyhow:: bail!(
38+ "Output directory '{}' is not empty. Please clear it before running benchmarks" ,
39+ out_dir. display( )
40+ ) ;
41+ }
42+ let app_config_name = app_config. file_name ( ) . unwrap_or_default ( ) ;
43+ let bench_config_name = bench_config. file_name ( ) . unwrap_or_default ( ) ;
44+ std:: fs:: copy ( app_config, out_dir. join ( app_config_name) ) ?;
45+ std:: fs:: copy ( bench_config, out_dir. join ( bench_config_name) ) ?;
46+
47+ Ok ( Self { config, out_dir } )
2848 }
2949
30- pub async fn run ( & self ) -> Result < ( ) > {
31- for bench in & self . config . bench . benchmarks {
50+ pub async fn run ( & self , name : Option < & str > ) -> Result < ( ) > {
51+ let benchmarks = match name {
52+ Some ( n) => {
53+ let bench = self
54+ . config
55+ . bench
56+ . benchmarks
57+ . iter ( )
58+ . find ( |b| b. name == n)
59+ . with_context ( || format ! ( "Benchmark not found: {}" , n) ) ?;
60+ vec ! [ bench]
61+ }
62+ None => self . config . bench . benchmarks . iter ( ) . collect ( ) ,
63+ } ;
64+
65+ for bench in benchmarks {
66+ // TODO: Remove this check to enable runs without AssumeUTXO
3267 self . check_snapshot ( bench, & self . config . app . snapshot_dir )
3368 . await ?;
3469 self . run_benchmark ( bench) . await ?;
3570 }
3671 Ok ( ( ) )
3772 }
3873
39- pub async fn run_single ( & self , name : & str ) -> Result < ( ) > {
40- let bench = self
41- . config
42- . bench
43- . benchmarks
44- . iter ( )
45- . find ( |b| b. name == name)
46- . with_context ( || format ! ( "Benchmark not found: {}" , name) ) ?;
47-
48- self . check_snapshot ( bench, & self . config . app . snapshot_dir )
49- . await ?;
50- self . run_benchmark ( bench) . await
51- }
52-
5374 async fn check_snapshot ( & self , bench : & SingleConfig , snapshot_dir : & Path ) -> Result < ( ) > {
5475 // Check if we have the correct snapshot
5576 let network = Network :: from_str ( & bench. network , true )
@@ -82,9 +103,6 @@ This can be downloaded with `benchkit snapshot download {}`",
82103 }
83104 merged_hyperfine. extend ( bench. hyperfine . clone ( ) ) ;
84105
85- // Create a temporary output directory
86- // let out_dir = tempfile::TempDir::new()?.into_path();
87-
88106 // Update command to use full binary path and apply chain= param
89107 if let Some ( Value :: String ( command) ) = merged_hyperfine. get_mut ( "command" ) {
90108 let new_command = command. replace (
@@ -116,6 +134,7 @@ This can be downloaded with `benchkit snapshot download {}`",
116134 let script_args = ScriptArgs {
117135 binary : format ! ( "{}/bitcoind-{{commit}}" , self . config. app. bin_dir. display( ) ) ,
118136 connect_address : bench. connect . clone ( ) . unwrap_or_default ( ) ,
137+ out_dir : self . out_dir . clone ( ) ,
119138 network : bench. network . clone ( ) ,
120139 snapshot_path,
121140 tmp_data_dir : self . config . bench . global . tmp_data_dir . clone ( ) ,
@@ -127,11 +146,11 @@ This can be downloaded with `benchkit snapshot download {}`",
127146 . with_context ( || "Failed to add hyperfine script hooks" ) ?;
128147
129148 // Add commits to parameter-lists if not already present
130- let param_lists = merged_hyperfine
149+ let parameter_lists = merged_hyperfine
131150 . entry ( "parameter_lists" . to_string ( ) )
132151 . or_insert_with ( || Value :: Array ( Vec :: new ( ) ) ) ;
133152
134- if let Value :: Array ( lists) = param_lists {
153+ if let Value :: Array ( lists) = parameter_lists {
135154 // Check if commits parameter list already exists
136155 if !lists
137156 . iter ( )
@@ -146,31 +165,27 @@ This can be downloaded with `benchkit snapshot download {}`",
146165 }
147166 }
148167
149- // Check the export path before running hyperfine
150- let export_path = merged_hyperfine
151- . get ( "export_json" )
152- . and_then ( Value :: as_str)
153- . with_context ( || {
154- format ! (
155- "Missing required 'export_json' field in benchmark '{}'" ,
156- bench. name
157- )
158- } ) ?;
168+ // Hardcode the export path to the top-level of the out_dir
169+ let export_path = self . out_dir . join ( "results.json" ) ;
170+ merged_hyperfine. insert (
171+ "export_json" . to_string ( ) ,
172+ Value :: String ( export_path. to_string_lossy ( ) . into_owned ( ) ) ,
173+ ) ;
159174
160175 // Run hyperfine with merged options
161176 self . run_hyperfine ( bench, & merged_hyperfine) ?;
162177
163178 // Check for and process results
164- if !Path :: new ( export_path) . exists ( ) {
179+ if !Path :: new ( & export_path) . exists ( ) {
165180 anyhow:: bail!(
166181 "Expected JSON results file not found at '{}' for benchmark '{}'" ,
167- export_path,
182+ export_path. display ( ) ,
168183 bench. name
169184 ) ;
170185 }
171186
172- let results_json = std:: fs:: read_to_string ( export_path)
173- . with_context ( || format ! ( "Failed to read results file: {}" , export_path) ) ?;
187+ let results_json = std:: fs:: read_to_string ( & export_path)
188+ . with_context ( || format ! ( "Failed to read results file: {}" , export_path. display ( ) ) ) ?;
174189
175190 // Store results in database
176191 crate :: database:: store_results (
@@ -180,11 +195,6 @@ This can be downloaded with `benchkit snapshot download {}`",
180195 self . config . bench . run_id ,
181196 )
182197 . await ?;
183-
184- // Cleanup
185- std:: fs:: remove_file ( export_path)
186- . with_context ( || format ! ( "Failed to remove results file: {}" , export_path) ) ?;
187-
188198 Ok ( ( ) )
189199 }
190200
0 commit comments