@@ -19,7 +19,6 @@ use std::path::{Path, PathBuf};
19
19
use std:: pin:: Pin ;
20
20
use std:: process:: { self , Command } ;
21
21
use std:: str;
22
- use std:: time:: Duration ;
23
22
24
23
pub mod bencher;
25
24
mod etw_parser;
@@ -499,25 +498,15 @@ fn process_stat_output(
499
498
let stdout = String :: from_utf8 ( output. stdout . clone ( ) ) . expect ( "utf8 output" ) ;
500
499
let mut stats = Stats :: new ( ) ;
501
500
502
- let mut profile: Option < SelfProfile > = None ;
503
- let mut dir: Option < PathBuf > = None ;
504
- let mut prefix: Option < String > = None ;
505
- let mut file: Option < PathBuf > = None ;
501
+ let mut self_profile_dir: Option < PathBuf > = None ;
502
+ let mut self_profile_crate: Option < String > = None ;
506
503
for line in stdout. lines ( ) {
507
- if let Some ( stripped) = line. strip_prefix ( "!self-profile-output:" ) {
508
- profile = Some ( serde_json:: from_str ( stripped) . unwrap ( ) ) ;
509
- continue ;
510
- }
511
504
if let Some ( stripped) = line. strip_prefix ( "!self-profile-dir:" ) {
512
- dir = Some ( PathBuf :: from ( stripped) ) ;
505
+ self_profile_dir = Some ( PathBuf :: from ( stripped) ) ;
513
506
continue ;
514
507
}
515
- if let Some ( stripped) = line. strip_prefix ( "!self-profile-prefix:" ) {
516
- prefix = Some ( String :: from ( stripped) ) ;
517
- continue ;
518
- }
519
- if let Some ( stripped) = line. strip_prefix ( "!self-profile-file:" ) {
520
- file = Some ( PathBuf :: from ( stripped) ) ;
508
+ if let Some ( stripped) = line. strip_prefix ( "!self-profile-crate:" ) {
509
+ self_profile_crate = Some ( String :: from ( stripped) ) ;
521
510
continue ;
522
511
}
523
512
if let Some ( counter_file) = line. strip_prefix ( "!counters-file:" ) {
@@ -581,39 +570,13 @@ fn process_stat_output(
581
570
) ;
582
571
}
583
572
584
- let files = if let ( Some ( prefix) , Some ( dir) ) = ( prefix, dir) {
585
- let mut string_index = PathBuf :: new ( ) ;
586
- let mut string_data = PathBuf :: new ( ) ;
587
- let mut events = PathBuf :: new ( ) ;
588
- for entry in fs:: read_dir ( & dir) . unwrap ( ) {
589
- let filename = entry. unwrap ( ) . file_name ( ) ;
590
- let filename_str = filename. to_str ( ) . unwrap ( ) ;
591
- let path = dir. join ( filename_str) ;
592
- if filename_str. ends_with ( ".events" ) {
593
- assert ! ( filename_str. contains( & prefix) , "{:?}" , path) ;
594
- events = path;
595
- } else if filename_str. ends_with ( ".string_data" ) {
596
- assert ! ( filename_str. contains( & prefix) , "{:?}" , path) ;
597
- string_data = path;
598
- } else if filename_str. ends_with ( ".string_index" ) {
599
- assert ! ( filename_str. contains( & prefix) , "{:?}" , path) ;
600
- string_index = path;
601
- }
602
- }
603
-
604
- Some ( SelfProfileFiles :: Seven {
605
- string_index,
606
- string_data,
607
- events,
608
- } )
609
- } else {
610
- file. map ( |file| SelfProfileFiles :: Eight { file } )
611
- } ;
612
-
613
573
if stats. is_empty ( ) {
614
574
return Err ( DeserializeStatError :: NoOutput ( output) ) ;
615
575
}
616
-
576
+ let ( profile, files) = match ( self_profile_dir, self_profile_crate) {
577
+ ( Some ( dir) , Some ( krate) ) => parse_self_profile ( dir, krate) ,
578
+ _ => ( None , None ) ,
579
+ } ;
617
580
Ok ( ( stats, profile, files) )
618
581
}
619
582
@@ -659,3 +622,109 @@ pub struct ArtifactSize {
659
622
#[ serde( rename = "value" ) ]
660
623
pub size : u64 ,
661
624
}
625
+
626
+ fn parse_self_profile (
627
+ dir : PathBuf ,
628
+ crate_name : String ,
629
+ ) -> ( Option < SelfProfile > , Option < SelfProfileFiles > ) {
630
+ // First, find the mm_profdata file prefix, or a single file containing the self-profile
631
+ // results.
632
+ let mut prefix = None ;
633
+ let mut full_path = None ;
634
+ // We don't know the pid of rustc, and can't easily get it -- we only know the
635
+ // `perf` pid. So just blindly look in the directory to hopefully find it.
636
+ for entry in fs:: read_dir ( & dir) . unwrap ( ) {
637
+ let entry = entry. unwrap ( ) ;
638
+ if entry
639
+ . file_name ( )
640
+ . to_str ( )
641
+ . map_or ( false , |s| s. starts_with ( & crate_name) )
642
+ {
643
+ if entry. file_name ( ) . to_str ( ) . unwrap ( ) . ends_with ( "mm_profdata" ) {
644
+ full_path = Some ( entry. path ( ) ) ;
645
+ break ;
646
+ }
647
+ let file = entry. file_name ( ) . to_str ( ) . unwrap ( ) . to_owned ( ) ;
648
+ let new_prefix = Some ( file[ ..file. find ( '.' ) . unwrap ( ) ] . to_owned ( ) ) ;
649
+ assert ! (
650
+ prefix. is_none( ) || prefix == new_prefix,
651
+ "prefix={:?}, new_prefix={:?}" ,
652
+ prefix,
653
+ new_prefix
654
+ ) ;
655
+ prefix = new_prefix;
656
+ }
657
+ }
658
+ let ( profile, files) = if let Some ( profile_path) = full_path {
659
+ // measureme 0.8 has a single file
660
+ let filename = profile_path. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) ;
661
+ let json = run_summarize ( "summarize" , & dir, filename)
662
+ . unwrap_or_else ( |e1| match run_summarize ( "summarize-9.0" , & dir, filename) {
663
+ Ok ( s) => s,
664
+ Err ( e2) => {
665
+ panic ! ( "failed to run summarize and summarize-9.0. Errors:\n summarize: {:?}\n summarize-9.0: {:?}" , e1, e2) ;
666
+ }
667
+ } ) ;
668
+ let profile: SelfProfile = serde_json:: from_str ( & json) . unwrap ( ) ;
669
+ ( profile, SelfProfileFiles :: Eight { file : profile_path } )
670
+ } else {
671
+ let Some ( prefix) = prefix else {
672
+ return ( None , None ) ;
673
+ } ;
674
+
675
+ let mut string_index = PathBuf :: new ( ) ;
676
+ let mut string_data = PathBuf :: new ( ) ;
677
+ let mut events = PathBuf :: new ( ) ;
678
+ for entry in fs:: read_dir ( & dir) . unwrap ( ) {
679
+ let filename = entry. unwrap ( ) . file_name ( ) ;
680
+ let filename_str = filename. to_str ( ) . unwrap ( ) ;
681
+ let path = dir. join ( filename_str) ;
682
+ if filename_str. ends_with ( ".events" ) {
683
+ assert ! ( filename_str. contains( & prefix) , "{:?}" , path) ;
684
+ events = path;
685
+ } else if filename_str. ends_with ( ".string_data" ) {
686
+ assert ! ( filename_str. contains( & prefix) , "{:?}" , path) ;
687
+ string_data = path;
688
+ } else if filename_str. ends_with ( ".string_index" ) {
689
+ assert ! ( filename_str. contains( & prefix) , "{:?}" , path) ;
690
+ string_index = path;
691
+ }
692
+ }
693
+
694
+ let files = SelfProfileFiles :: Seven {
695
+ string_index,
696
+ string_data,
697
+ events,
698
+ } ;
699
+
700
+ let json = run_summarize ( "summarize" , & dir, & prefix)
701
+ . or_else ( |_| run_summarize ( "summarize-0.7" , & dir, & prefix) )
702
+ . expect ( "able to run summarize or summarize-0.7" ) ;
703
+ let profile: SelfProfile = serde_json:: from_str ( & json) . unwrap ( ) ;
704
+ ( profile, files)
705
+ } ;
706
+ ( Some ( profile) , Some ( files) )
707
+ }
708
+
709
+ fn run_summarize ( name : & str , prof_out_dir : & Path , prefix : & str ) -> anyhow:: Result < String > {
710
+ let mut cmd = Command :: new ( name) ;
711
+ cmd. current_dir ( prof_out_dir) ;
712
+ cmd. arg ( "summarize" ) . arg ( "--json" ) ;
713
+ cmd. arg ( prefix) ;
714
+ let status = cmd
715
+ . status ( )
716
+ . with_context ( || format ! ( "Command::new({}).status() failed" , name) ) ?;
717
+ if !status. success ( ) {
718
+ anyhow:: bail!(
719
+ "failed to run {} in {:?} with prefix {:?}" ,
720
+ name,
721
+ prof_out_dir,
722
+ prefix
723
+ )
724
+ }
725
+ let json = prof_out_dir. join ( format ! (
726
+ "{}.json" ,
727
+ prefix. strip_suffix( ".mm_profdata" ) . unwrap_or( prefix)
728
+ ) ) ;
729
+ fs:: read_to_string ( & json) . with_context ( || format ! ( "failed to read {:?}" , json) )
730
+ }
0 commit comments