@@ -26,7 +26,9 @@ use tabled::settings::{Alignment, Border, Color, Modify};
2626use tokio:: runtime:: Runtime ;
2727
2828use collector:: api:: next_artifact:: NextArtifact ;
29- use collector:: artifact_stats:: { compile_and_get_stats, ArtifactWithStats , CargoProfile } ;
29+ use collector:: artifact_stats:: {
30+ compile_and_get_stats, ArtifactStats , ArtifactWithStats , CargoProfile ,
31+ } ;
3032use collector:: codegen:: { codegen_diff, CodegenType } ;
3133use collector:: compile:: benchmark:: category:: Category ;
3234use collector:: compile:: benchmark:: codegen_backend:: CodegenBackend ;
@@ -408,39 +410,65 @@ struct PurgeOption {
408410 purge : Option < PurgeMode > ,
409411}
410412
411- // For each subcommand we list the mandatory arguments in the required
412- // order, followed by the options in alphabetical order.
413- #[ derive( Debug , clap:: Subcommand ) ]
413+ #[ derive( Debug , clap:: Args ) ]
414414#[ command( rename_all = "snake_case" ) ]
415- enum Commands {
416- /// Show binary (executable or library) section (and optionally symbol) size statistics of the
417- /// selected compile benchmark(s).
418- /// Optionally compares sizes between two compiler toolchains, if `--rustc2` is provided.
419- BinaryStats {
420- #[ command( flatten) ]
421- local : LocalOptions ,
415+ struct BinaryStatsCompile {
416+ #[ command( flatten) ]
417+ local : LocalOptions ,
422418
423- /// Cargo profile to use.
424- #[ arg( long, default_value = "Debug" ) ]
425- profile : Profile ,
419+ /// Cargo profile to use.
420+ #[ arg( long, default_value = "Debug" ) ]
421+ profile : Profile ,
426422
427- /// Codegen backend to use.
428- #[ arg( long = "backend" , default_value = "Llvm" ) ]
429- codegen_backend : CodegenBackend ,
423+ /// Codegen backend to use.
424+ #[ arg( long = "backend" , default_value = "Llvm" ) ]
425+ codegen_backend : CodegenBackend ,
430426
431- /// An optional second toolchain to compare to.
432- #[ arg( long) ]
433- rustc2 : Option < String > ,
427+ /// An optional second toolchain to compare to.
428+ #[ arg( long) ]
429+ rustc2 : Option < String > ,
430+
431+ /// Codegen backend to use for the second toolchain.
432+ #[ arg( long = "backend2" ) ]
433+ codegen_backend2 : Option < CodegenBackend > ,
434+ }
435+
436+ #[ derive( Debug , clap:: Args ) ]
437+ #[ command( rename_all = "snake_case" ) ]
438+ struct BinaryStatsLocal {
439+ /// Binary artifact to examine.
440+ artifact : PathBuf ,
434441
435- /// Codegen backend to use for the second toolchain.
436- #[ arg( long = "backend2" ) ]
437- codegen_backend2 : Option < CodegenBackend > ,
442+ /// Optional second artifact to compare with the first one.
443+ artifact2 : Option < PathBuf > ,
444+ }
445+
446+ #[ derive( Debug , clap:: Subcommand ) ]
447+ #[ command( rename_all = "snake_case" ) ]
448+ enum BinaryStatsMode {
449+ /// Show size statistics for the selected compile benchmark(s).
450+ /// Optionally compares sizes between two compiler toolchains, if `--rustc2` is provided.
451+ Compile ( BinaryStatsCompile ) ,
452+ /// Show size statistics for the selected binary artifact on disk.
453+ /// Optionally compares sizes with a second provided artifact, if `--artifact2` is provided.
454+ Local ( BinaryStatsLocal ) ,
455+ }
438456
457+ // For each subcommand we list the mandatory arguments in the required
458+ // order, followed by the options in alphabetical order.
459+ #[ derive( Debug , clap:: Subcommand ) ]
460+ #[ command( rename_all = "snake_case" ) ]
461+ enum Commands {
462+ /// Show binary (executable or library) section (and optionally symbol) size statistics.
463+ BinaryStats {
439464 /// Also print symbol comparison in addition to section comparison.
440465 ///
441466 /// Warning: may generate *A LOT* of data.
442- #[ arg( long, default_value_t = false ) ]
467+ #[ arg( long, default_value_t = false , global = true ) ]
443468 symbols : bool ,
469+
470+ #[ clap( subcommand) ]
471+ mode : BinaryStatsMode ,
444472 } ,
445473
446474 /// Benchmarks the performance of programs generated by a local rustc
@@ -649,89 +677,13 @@ fn main_result() -> anyhow::Result<i32> {
649677 let target_triple = format ! ( "{}-unknown-linux-gnu" , std:: env:: consts:: ARCH ) ;
650678
651679 match args. command {
652- Commands :: BinaryStats {
653- local,
654- codegen_backend,
655- profile,
656- rustc2,
657- codegen_backend2,
658- symbols,
659- } => {
660- let codegen_backend2 = codegen_backend2. unwrap_or ( codegen_backend) ;
661- let toolchain = get_local_toolchain (
662- & [ Profile :: Debug , Profile :: Opt ] ,
663- & [ codegen_backend] ,
664- & local. rustc ,
665- * ToolchainConfig :: default ( )
666- . cargo ( local. cargo . as_deref ( ) )
667- . id ( local. id . as_deref ( ) ) ,
668- "" ,
669- target_triple. clone ( ) ,
670- ) ?;
671- let toolchain2 = rustc2
672- . map ( |rustc| {
673- get_local_toolchain (
674- & [ Profile :: Debug , Profile :: Opt ] ,
675- & [ codegen_backend2] ,
676- & rustc,
677- * ToolchainConfig :: default ( )
678- . cargo ( local. cargo . as_deref ( ) )
679- . id ( local. id . as_deref ( ) ) ,
680- "" ,
681- target_triple,
682- )
683- } )
684- . transpose ( ) ?;
685- let profile = match profile {
686- Profile :: Debug => CargoProfile :: Debug ,
687- Profile :: Opt => CargoProfile :: Release ,
688- _ => return Err ( anyhow:: anyhow!( "Only Debug and Opt profiles are supported" ) ) ,
689- } ;
690- let benchmarks = get_compile_benchmarks (
691- & compile_benchmark_dir,
692- & local. include ,
693- & local. exclude ,
694- & local. exclude_suffix ,
695- ) ?;
696- for benchmark in benchmarks {
697- println ! ( "Stats for benchmark `{}`" , benchmark. name) ;
698- println ! ( "{}" , "-" . repeat( 20 ) ) ;
699- let artifacts =
700- compile_and_get_stats ( & benchmark. path , & toolchain, profile, codegen_backend) ?;
701- let archives2: HashMap < String , ArtifactWithStats > = toolchain2
702- . as_ref ( )
703- . map ( |toolchain| {
704- compile_and_get_stats ( & benchmark. path , toolchain, profile, codegen_backend2)
705- } )
706- . transpose ( ) ?
707- . unwrap_or_default ( )
708- . into_iter ( )
709- . map ( |artifact| ( artifact. target_name . clone ( ) , artifact) )
710- . collect ( ) ;
711-
712- for artifact in artifacts {
713- let archive2 = archives2. get ( & artifact. target_name ) ;
714-
715- println ! (
716- "Target `{}` (artifact `{}`)" ,
717- artifact. target_name,
718- artifact
719- . path
720- . file_name( )
721- . and_then( |s| s. to_str( ) )
722- . unwrap_or( & artifact. target_name)
723- ) ;
724-
725- let sections = artifact. stats . sections ;
726- let sections2 = archive2. as_ref ( ) . map ( |a| a. stats . sections . clone ( ) ) ;
727- print_binary_stats ( "Section" , sections, sections2) ;
728-
729- if symbols {
730- let symbols = artifact. stats . symbols ;
731- let symbols2 = archive2. as_ref ( ) . map ( |a| a. stats . symbols . clone ( ) ) ;
732- print_binary_stats ( "Symbol" , symbols, symbols2) ;
733- }
734- println ! ( ) ;
680+ Commands :: BinaryStats { mode, symbols } => {
681+ match mode {
682+ BinaryStatsMode :: Compile ( args) => {
683+ binary_stats_compile ( args, symbols, & target_triple) ?;
684+ }
685+ BinaryStatsMode :: Local ( args) => {
686+ binary_stats_local ( args, symbols) ?;
735687 }
736688 }
737689
@@ -1234,6 +1186,122 @@ Make sure to modify `{dir}/perf-config.json` if the category/artifact don't matc
12341186 }
12351187}
12361188
1189+ fn binary_stats_local ( args : BinaryStatsLocal , symbols : bool ) -> anyhow:: Result < ( ) > {
1190+ let stats = ArtifactStats :: from_path ( & args. artifact )
1191+ . with_context ( || format ! ( "Cannot load artifact from {}" , args. artifact. display( ) ) ) ?;
1192+ let stats2 = args
1193+ . artifact2
1194+ . as_ref ( )
1195+ . map ( |path| {
1196+ ArtifactStats :: from_path ( path)
1197+ . with_context ( || format ! ( "Cannot load artifact from {}" , path. display( ) ) )
1198+ } )
1199+ . transpose ( ) ?;
1200+ print_binary_stats (
1201+ "Sections" ,
1202+ stats. sections ,
1203+ stats2. as_ref ( ) . map ( |s| s. sections . clone ( ) ) ,
1204+ ) ;
1205+ if symbols {
1206+ print_binary_stats ( "Symbols" , stats. symbols , stats2. map ( |s| s. symbols ) ) ;
1207+ }
1208+
1209+ Ok ( ( ) )
1210+ }
1211+
1212+ fn binary_stats_compile (
1213+ args : BinaryStatsCompile ,
1214+ symbols : bool ,
1215+ target_triple : & str ,
1216+ ) -> anyhow:: Result < ( ) > {
1217+ let BinaryStatsCompile {
1218+ local,
1219+ profile,
1220+ codegen_backend,
1221+ rustc2,
1222+ codegen_backend2,
1223+ } = args;
1224+
1225+ let codegen_backend2 = codegen_backend2. unwrap_or ( codegen_backend) ;
1226+ let toolchain = get_local_toolchain (
1227+ & [ Profile :: Debug , Profile :: Opt ] ,
1228+ & [ codegen_backend] ,
1229+ & local. rustc ,
1230+ * ToolchainConfig :: default ( )
1231+ . cargo ( local. cargo . as_deref ( ) )
1232+ . id ( local. id . as_deref ( ) ) ,
1233+ "" ,
1234+ target_triple. to_string ( ) ,
1235+ ) ?;
1236+ let toolchain2 = rustc2
1237+ . map ( |rustc| {
1238+ get_local_toolchain (
1239+ & [ Profile :: Debug , Profile :: Opt ] ,
1240+ & [ codegen_backend2] ,
1241+ & rustc,
1242+ * ToolchainConfig :: default ( )
1243+ . cargo ( local. cargo . as_deref ( ) )
1244+ . id ( local. id . as_deref ( ) ) ,
1245+ "" ,
1246+ target_triple. to_string ( ) ,
1247+ )
1248+ } )
1249+ . transpose ( ) ?;
1250+ let profile = match profile {
1251+ Profile :: Debug => CargoProfile :: Debug ,
1252+ Profile :: Opt => CargoProfile :: Release ,
1253+ _ => return Err ( anyhow:: anyhow!( "Only Debug and Opt profiles are supported" ) ) ,
1254+ } ;
1255+ let benchmarks = get_compile_benchmarks (
1256+ & compile_benchmark_dir ( ) ,
1257+ & local. include ,
1258+ & local. exclude ,
1259+ & local. exclude_suffix ,
1260+ ) ?;
1261+ for benchmark in benchmarks {
1262+ println ! ( "Stats for benchmark `{}`" , benchmark. name) ;
1263+ println ! ( "{}" , "-" . repeat( 20 ) ) ;
1264+ let artifacts =
1265+ compile_and_get_stats ( & benchmark. path , & toolchain, profile, codegen_backend) ?;
1266+ let archives2: HashMap < String , ArtifactWithStats > = toolchain2
1267+ . as_ref ( )
1268+ . map ( |toolchain| {
1269+ compile_and_get_stats ( & benchmark. path , toolchain, profile, codegen_backend2)
1270+ } )
1271+ . transpose ( ) ?
1272+ . unwrap_or_default ( )
1273+ . into_iter ( )
1274+ . map ( |artifact| ( artifact. target_name . clone ( ) , artifact) )
1275+ . collect ( ) ;
1276+
1277+ for artifact in artifacts {
1278+ let archive2 = archives2. get ( & artifact. target_name ) ;
1279+
1280+ println ! (
1281+ "Target `{}` (artifact `{}`)" ,
1282+ artifact. target_name,
1283+ artifact
1284+ . path
1285+ . file_name( )
1286+ . and_then( |s| s. to_str( ) )
1287+ . unwrap_or( & artifact. target_name)
1288+ ) ;
1289+
1290+ let sections = artifact. stats . sections ;
1291+ let sections2 = archive2. as_ref ( ) . map ( |a| a. stats . sections . clone ( ) ) ;
1292+ print_binary_stats ( "Section" , sections, sections2) ;
1293+
1294+ if symbols {
1295+ let symbols = artifact. stats . symbols ;
1296+ let symbols2 = archive2. as_ref ( ) . map ( |a| a. stats . symbols . clone ( ) ) ;
1297+ print_binary_stats ( "Symbol" , symbols, symbols2) ;
1298+ }
1299+ println ! ( ) ;
1300+ }
1301+ }
1302+ Ok ( ( ) )
1303+ }
1304+
12371305fn build_async_runtime ( ) -> Runtime {
12381306 let mut builder = tokio:: runtime:: Builder :: new_multi_thread ( ) ;
12391307 // We want to minimize noise from the runtime
0 commit comments