@@ -7,6 +7,7 @@ use measureme::file_header::{
77use measureme:: {
88 EventId , PageTag , RawEvent , SerializationSink , SerializationSinkBuilder , StringTableBuilder ,
99} ;
10+ use std:: cell:: OnceCell ;
1011use std:: fs;
1112use std:: path:: Path ;
1213use std:: sync:: Arc ;
@@ -15,6 +16,7 @@ use std::{error::Error, path::PathBuf};
1516#[ derive( Debug ) ]
1617pub struct ProfilingData {
1718 event_decoder : Box < dyn EventDecoder > ,
19+ metadata : OnceCell < Metadata > ,
1820}
1921
2022impl ProfilingData {
@@ -50,9 +52,6 @@ impl ProfilingData {
5052 data : Vec < u8 > ,
5153 diagnostic_file_path : Option < & Path > ,
5254 ) -> Result < ProfilingData , Box < dyn Error + Send + Sync > > {
53- // let event_decoder = EventDecoder::new(data, diagnostic_file_path)?;
54- // Ok(ProfilingData { event_decoder })
55-
5655 let file_format_version = read_file_header (
5756 & data,
5857 FILE_MAGIC_TOP_LEVEL ,
@@ -66,6 +65,10 @@ impl ProfilingData {
6665 data,
6766 diagnostic_file_path,
6867 ) ?) ,
68+ file_formats:: v9:: FILE_FORMAT => Box :: new ( file_formats:: v9:: EventDecoder :: new (
69+ data,
70+ diagnostic_file_path,
71+ ) ?) ,
6972 unsupported_version => {
7073 let msg = if unsupported_version > file_formats:: current:: FILE_FORMAT {
7174 format ! (
@@ -83,11 +86,15 @@ impl ProfilingData {
8386 }
8487 } ;
8588
86- Ok ( ProfilingData { event_decoder } )
89+ Ok ( ProfilingData {
90+ event_decoder,
91+ metadata : OnceCell :: new ( ) ,
92+ } )
8793 }
8894
8995 pub fn metadata ( & self ) -> & Metadata {
90- self . event_decoder . metadata ( )
96+ // Cache the metadata during the first access
97+ self . metadata . get_or_init ( || self . event_decoder . metadata ( ) )
9198 }
9299
93100 pub fn iter < ' a > ( & ' a self ) -> ProfilerEventIterator < ' a > {
@@ -301,6 +308,7 @@ impl ProfilingDataBuilder {
301308 )
302309 . unwrap ( ) ,
303310 ) ,
311+ metadata : OnceCell :: new ( ) ,
304312 }
305313 }
306314
@@ -641,6 +649,86 @@ mod tests {
641649 ) ;
642650 }
643651
652+ // To generate this revision, a v9 revision of the rust toolchain was
653+ // created, and "rustup toolchain link" was used to name it "bespoke".
654+ // Then, the following commands were executed:
655+ //
656+ // # Make a small test binary and profile it.
657+ // cargo new --bin testbinary
658+ // cargo +bespoke rustc --bin testbinary -- -Zself-profile
659+ //
660+ // # Gzip the output profdata.
661+ // gzip testbinary-...mm_profdata
662+ // mv testbinary-...mm_profdata.gz v9.mm_profdata.gz
663+ #[ test]
664+ fn can_read_v9_profdata_files ( ) {
665+ let ( data, file_format_version) =
666+ read_data_and_version ( "tests/profdata/v9.mm_profdata.gz" ) ;
667+ assert_eq ! ( file_format_version, file_formats:: v9:: FILE_FORMAT ) ;
668+ let profiling_data = ProfilingData :: from_paged_buffer ( data, None )
669+ . expect ( "Creating the profiling data failed" ) ;
670+ let grouped_events = group_events ( & profiling_data) ;
671+ let event_kinds = grouped_events
672+ . keys ( )
673+ . map ( |k| k. as_str ( ) )
674+ . collect :: < HashSet < _ > > ( ) ;
675+ let expect_event_kinds = vec ! [
676+ "GenericActivity" ,
677+ "IncrementalResultHashing" ,
678+ "Query" ,
679+ "ArtifactSize" ,
680+ ]
681+ . into_iter ( )
682+ . collect :: < HashSet < _ > > ( ) ;
683+ assert_eq ! ( event_kinds, expect_event_kinds) ;
684+
685+ let generic_activity_len = 5125 ;
686+ let incremental_hashing_len = 1844 ;
687+ let query_len = 1877 ;
688+ let artifact_size_len = 24 ;
689+ assert_eq ! (
690+ grouped_events[ "GenericActivity" ] . len( ) ,
691+ generic_activity_len
692+ ) ;
693+ assert_eq ! (
694+ grouped_events[ "IncrementalResultHashing" ] . len( ) ,
695+ incremental_hashing_len
696+ ) ;
697+ assert_eq ! ( grouped_events[ "Query" ] . len( ) , query_len) ;
698+ assert_eq ! ( grouped_events[ "ArtifactSize" ] . len( ) , artifact_size_len) ;
699+
700+ assert_eq ! (
701+ grouped_events[ "GenericActivity" ] [ generic_activity_len / 2 ] . label,
702+ "metadata_decode_entry_item_attrs"
703+ ) ;
704+ assert_eq ! (
705+ grouped_events[ "GenericActivity" ] [ generic_activity_len / 2 ] . duration( ) ,
706+ Some ( Duration :: from_nanos( 376 ) )
707+ ) ;
708+
709+ assert_eq ! (
710+ grouped_events[ "IncrementalResultHashing" ] [ incremental_hashing_len - 1 ] . label,
711+ "crate_hash"
712+ ) ;
713+ assert_eq ! (
714+ grouped_events[ "IncrementalResultHashing" ] [ incremental_hashing_len - 1 ] . duration( ) ,
715+ Some ( Duration :: from_nanos( 461 ) )
716+ ) ;
717+
718+ assert_eq ! ( grouped_events[ "Query" ] [ 0 ] . label, "registered_tools" ) ;
719+ assert_eq ! (
720+ grouped_events[ "Query" ] [ 0 ] . duration( ) ,
721+ Some ( Duration :: from_nanos( 45077 ) )
722+ ) ;
723+
724+ assert_eq ! (
725+ grouped_events[ "ArtifactSize" ] [ 0 ] . label,
726+ "codegen_unit_size_estimate"
727+ ) ;
728+ assert_eq ! ( grouped_events[ "ArtifactSize" ] [ 0 ] . duration( ) , None ) ;
729+ assert_eq ! ( grouped_events[ "ArtifactSize" ] [ 0 ] . integer( ) , Some ( 3 ) ) ;
730+ }
731+
644732 fn read_data_and_version ( file_path : & str ) -> ( Vec < u8 > , u32 ) {
645733 let data = std:: fs:: read ( file_path) . expect ( "Test data not found" ) ;
646734 let mut gz = flate2:: read:: GzDecoder :: new ( & data[ ..] ) ;
0 commit comments