@@ -26,7 +26,9 @@ use tabled::settings::{Alignment, Border, Color, Modify};
26
26
use tokio:: runtime:: Runtime ;
27
27
28
28
use 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
+ } ;
30
32
use collector:: codegen:: { codegen_diff, CodegenType } ;
31
33
use collector:: compile:: benchmark:: category:: Category ;
32
34
use collector:: compile:: benchmark:: codegen_backend:: CodegenBackend ;
@@ -408,39 +410,65 @@ struct PurgeOption {
408
410
purge : Option < PurgeMode > ,
409
411
}
410
412
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 ) ]
414
414
#[ 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 ,
422
418
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 ,
426
422
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 ,
430
426
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 ,
434
441
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
+ }
438
456
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 {
439
464
/// Also print symbol comparison in addition to section comparison.
440
465
///
441
466
/// Warning: may generate *A LOT* of data.
442
- #[ arg( long, default_value_t = false ) ]
467
+ #[ arg( long, default_value_t = false , global = true ) ]
443
468
symbols : bool ,
469
+
470
+ #[ clap( subcommand) ]
471
+ mode : BinaryStatsMode ,
444
472
} ,
445
473
446
474
/// Benchmarks the performance of programs generated by a local rustc
@@ -649,89 +677,13 @@ fn main_result() -> anyhow::Result<i32> {
649
677
let target_triple = format ! ( "{}-unknown-linux-gnu" , std:: env:: consts:: ARCH ) ;
650
678
651
679
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) ?;
735
687
}
736
688
}
737
689
@@ -1234,6 +1186,122 @@ Make sure to modify `{dir}/perf-config.json` if the category/artifact don't matc
1234
1186
}
1235
1187
}
1236
1188
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
+
1237
1305
fn build_async_runtime ( ) -> Runtime {
1238
1306
let mut builder = tokio:: runtime:: Builder :: new_multi_thread ( ) ;
1239
1307
// We want to minimize noise from the runtime
0 commit comments