11//! CLI runner. Many jobs share the same pattern but do different core actions.
22
33use {
4+ chrono:: Utc ,
45 clap:: ValueEnum ,
56 mollusk_svm:: {
67 result:: { Compare , Config , InstructionResult } ,
78 Mollusk ,
89 } ,
10+ mollusk_svm_bencher:: { get_solana_version, result:: MolluskComputeUnitBenchResult } ,
11+ std:: path:: PathBuf ,
912} ;
1013
1114#[ derive( Clone , Debug , Default , ValueEnum ) ]
@@ -17,8 +20,26 @@ pub enum ProtoLayout {
1720 Firedancer ,
1821}
1922
23+ pub struct CusReport {
24+ pub path : String ,
25+ pub table_header : String ,
26+ }
27+
28+ impl CusReport {
29+ pub fn new ( path : String , table_header : Option < String > ) -> Self {
30+ let table_header = table_header. unwrap_or_else ( || Utc :: now ( ) . to_string ( ) ) ;
31+ Self { path, table_header }
32+ }
33+ }
34+
35+ pub struct RunResult < ' a > {
36+ pub pass : bool ,
37+ pub bench_result : Option < MolluskComputeUnitBenchResult < ' a > > ,
38+ }
39+
2040pub struct Runner {
2141 checks : Vec < Compare > ,
42+ cus_report : Option < CusReport > ,
2243 inputs_only : bool ,
2344 program_logs : bool ,
2445 proto : ProtoLayout ,
@@ -28,13 +49,15 @@ pub struct Runner {
2849impl Runner {
2950 pub fn new (
3051 checks : Vec < Compare > ,
52+ cus_report : Option < CusReport > ,
3153 inputs_only : bool ,
3254 program_logs : bool ,
3355 proto : ProtoLayout ,
3456 verbose : bool ,
3557 ) -> Self {
3658 Self {
3759 checks,
60+ cus_report,
3861 inputs_only,
3962 program_logs,
4063 proto,
@@ -66,12 +89,12 @@ impl Runner {
6689 }
6790 }
6891
69- pub fn run (
92+ fn run < ' a > (
7093 & self ,
7194 ground : Option < & mut Mollusk > ,
7295 target : & mut Mollusk ,
73- fixture_path : & str ,
74- ) -> Result < bool , Box < dyn std:: error:: Error > > {
96+ fixture_path : & ' a str ,
97+ ) -> Result < RunResult < ' a > , Box < dyn std:: error:: Error > > {
7598 // Disable stdout logging of program logs if not specified.
7699 if !self . program_logs {
77100 solana_logger:: setup_with ( "" ) ;
@@ -141,6 +164,16 @@ impl Runner {
141164
142165 let ( target_result, effects) = self . run_fixture ( target, fixture_path) ;
143166
167+ // Record a bench result for the CU report, if specified.
168+ let bench_result = if self . cus_report . is_some ( ) {
169+ Some ( MolluskComputeUnitBenchResult :: new (
170+ parse_fixture_name ( fixture_path) ,
171+ target_result. clone ( ) ,
172+ ) )
173+ } else {
174+ None
175+ } ;
176+
144177 if self . program_logs {
145178 println ! ( ) ;
146179 }
@@ -201,7 +234,7 @@ impl Runner {
201234 println ! ( ) ;
202235 }
203236
204- Ok ( pass)
237+ Ok ( RunResult { pass, bench_result } )
205238 }
206239
207240 pub fn run_all (
@@ -211,11 +244,16 @@ impl Runner {
211244 fixtures : & [ String ] ,
212245 ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
213246 let mut failures = 0 ;
247+ let mut bench_results = Vec :: new ( ) ;
214248
215249 for fixture_path in fixtures {
216- let result = self . run ( ground. as_deref_mut ( ) , target, fixture_path) ?;
250+ let mut result = self . run ( ground. as_deref_mut ( ) , target, fixture_path) ?;
251+
252+ if let Some ( bench_result) = result. bench_result . take ( ) {
253+ bench_results. push ( bench_result) ;
254+ }
217255
218- if !result {
256+ if !result. pass {
219257 failures += 1 ;
220258 }
221259 }
@@ -227,6 +265,24 @@ impl Runner {
227265 std:: process:: exit ( 1 ) ;
228266 }
229267
268+ if let Some ( cus_report) = & self . cus_report {
269+ let solana_version = get_solana_version ( ) ;
270+ mollusk_svm_bencher:: result:: write_results (
271+ & PathBuf :: from ( & cus_report. path ) ,
272+ & cus_report. table_header ,
273+ & solana_version,
274+ bench_results,
275+ ) ;
276+ }
277+
230278 Ok ( ( ) )
231279 }
232280}
281+
282+ fn parse_fixture_name ( fixture_path : & str ) -> & str {
283+ fixture_path
284+ . rsplit_once ( '/' )
285+ . map_or ( fixture_path, |( _, name) | name)
286+ . split_once ( '.' )
287+ . map_or_else ( || fixture_path, |( name, _) | name)
288+ }
0 commit comments