@@ -3,17 +3,19 @@ use crate::lightweight_event::LightweightEvent;
33use crate :: timestamp:: Timestamp ;
44use crate :: StringTable ;
55use measureme:: file_header:: {
6- read_file_header, write_file_header, CURRENT_FILE_FORMAT_VERSION , FILE_HEADER_SIZE ,
7- FILE_MAGIC_EVENT_STREAM ,
6+ verify_file_header, write_file_header, FILE_EXTENSION , FILE_HEADER_SIZE ,
7+ FILE_MAGIC_EVENT_STREAM , FILE_MAGIC_TOP_LEVEL ,
8+ } ;
9+ use measureme:: {
10+ EventId , PageTag , RawEvent , SerializationSink , SerializationSinkBuilder , StringTableBuilder ,
811} ;
9- use measureme:: { EventId , ProfilerFiles , RawEvent , SerializationSink , StringTableBuilder } ;
1012use serde:: { Deserialize , Deserializer } ;
11- use std:: error:: Error ;
1213use std:: fs;
1314use std:: mem;
1415use std:: path:: Path ;
1516use std:: sync:: Arc ;
1617use std:: time:: { Duration , SystemTime , UNIX_EPOCH } ;
18+ use std:: { error:: Error , path:: PathBuf } ;
1719
1820const RAW_EVENT_SIZE : usize = mem:: size_of :: < RawEvent > ( ) ;
1921
@@ -43,35 +45,60 @@ pub struct ProfilingData {
4345}
4446
4547impl ProfilingData {
46- pub fn new ( path_stem : & Path ) -> Result < ProfilingData , Box < dyn Error > > {
47- let paths = ProfilerFiles :: new ( path_stem) ;
48+ pub fn new ( path_stem : & Path ) -> Result < ProfilingData , Box < dyn Error + Send + Sync > > {
49+ let paged_path = path_stem. with_extension ( FILE_EXTENSION ) ;
50+
51+ if paged_path. exists ( ) {
52+ let data = fs:: read ( & paged_path) ?;
53+
54+ verify_file_header ( & data, FILE_MAGIC_TOP_LEVEL , Some ( & paged_path) , "top-level" ) ?;
55+
56+ let mut split_data = measureme:: split_streams ( & data[ FILE_HEADER_SIZE ..] ) ;
57+
58+ let string_data = split_data. remove ( & PageTag :: StringData ) . unwrap ( ) ;
59+ let index_data = split_data. remove ( & PageTag :: StringIndex ) . unwrap ( ) ;
60+ let event_data = split_data. remove ( & PageTag :: Events ) . unwrap ( ) ;
4861
49- let string_data = fs:: read ( paths. string_data_file ) . expect ( "couldn't read string_data file" ) ;
50- let index_data =
51- fs:: read ( paths. string_index_file ) . expect ( "couldn't read string_index file" ) ;
52- let event_data = fs:: read ( paths. events_file ) . expect ( "couldn't read events file" ) ;
62+ ProfilingData :: from_buffers ( string_data, index_data, event_data, Some ( & paged_path) )
63+ } else {
64+ let mut msg = format ! (
65+ "Could not find profiling data file `{}`." ,
66+ paged_path. display( )
67+ ) ;
5368
54- ProfilingData :: from_buffers ( string_data, index_data, event_data)
69+ // Let's try to give a helpful error message if we encounter files
70+ // in the old three-file-format:
71+ let paths = ProfilerFiles :: new ( path_stem) ;
72+
73+ if paths. events_file . exists ( )
74+ || paths. string_data_file . exists ( )
75+ || paths. string_index_file . exists ( )
76+ {
77+ msg += "It looks like your profiling data has been generated \
78+ by an out-dated version of measureme (0.7 or older).";
79+ }
80+
81+ return Err ( From :: from ( msg) ) ;
82+ }
5583 }
5684
5785 pub fn from_buffers (
5886 string_data : Vec < u8 > ,
5987 string_index : Vec < u8 > ,
6088 events : Vec < u8 > ,
61- ) -> Result < ProfilingData , Box < dyn Error > > {
89+ diagnostic_file_path : Option < & Path > ,
90+ ) -> Result < ProfilingData , Box < dyn Error + Send + Sync > > {
6291 let index_data = string_index;
6392 let event_data = events;
6493
65- let event_data_format = read_file_header ( & event_data, FILE_MAGIC_EVENT_STREAM ) ?;
66- if event_data_format != CURRENT_FILE_FORMAT_VERSION {
67- Err ( format ! (
68- "Event stream file format version '{}' is not supported
69- by this version of `measureme`." ,
70- event_data_format
71- ) ) ?;
72- }
94+ verify_file_header (
95+ & event_data,
96+ FILE_MAGIC_EVENT_STREAM ,
97+ diagnostic_file_path,
98+ "event" ,
99+ ) ?;
73100
74- let string_table = StringTable :: new ( string_data, index_data) ?;
101+ let string_table = StringTable :: new ( string_data, index_data, diagnostic_file_path ) ?;
75102
76103 let metadata = string_table. get_metadata ( ) . to_string ( ) ;
77104 let metadata: Metadata = serde_json:: from_str ( & metadata) ?;
@@ -207,17 +234,20 @@ pub struct ProfilingDataBuilder {
207234
208235impl ProfilingDataBuilder {
209236 pub fn new ( ) -> ProfilingDataBuilder {
210- let event_sink = SerializationSink :: new_in_memory ( ) ;
211- let string_table_data_sink = Arc :: new ( SerializationSink :: new_in_memory ( ) ) ;
212- let string_table_index_sink = Arc :: new ( SerializationSink :: new_in_memory ( ) ) ;
237+ let sink_builder = SerializationSinkBuilder :: new_in_memory ( ) ;
238+
239+ let event_sink = sink_builder. new_sink ( PageTag :: Events ) ;
240+ let string_table_data_sink = Arc :: new ( sink_builder. new_sink ( PageTag :: StringData ) ) ;
241+ let string_table_index_sink = Arc :: new ( sink_builder. new_sink ( PageTag :: StringIndex ) ) ;
213242
214243 // The first thing in every file we generate must be the file header.
215- write_file_header ( & event_sink, FILE_MAGIC_EVENT_STREAM ) ;
244+ write_file_header ( & mut event_sink. as_std_write ( ) , FILE_MAGIC_EVENT_STREAM ) . unwrap ( ) ;
216245
217246 let string_table = StringTableBuilder :: new (
218247 string_table_data_sink. clone ( ) ,
219248 string_table_index_sink. clone ( ) ,
220- ) ;
249+ )
250+ . unwrap ( ) ;
221251
222252 ProfilingDataBuilder {
223253 event_sink,
@@ -287,11 +317,9 @@ impl ProfilingDataBuilder {
287317 . unwrap ( )
288318 . into_bytes ( ) ;
289319
290- assert_eq ! (
291- read_file_header( & event_data, FILE_MAGIC_EVENT_STREAM ) . unwrap( ) ,
292- CURRENT_FILE_FORMAT_VERSION
293- ) ;
294- let string_table = StringTable :: new ( data_bytes, index_bytes) . unwrap ( ) ;
320+ verify_file_header ( & event_data, FILE_MAGIC_EVENT_STREAM , None , "event" ) . unwrap ( ) ;
321+
322+ let string_table = StringTable :: new ( data_bytes, index_bytes, None ) . unwrap ( ) ;
295323 let metadata = Metadata {
296324 start_time : UNIX_EPOCH ,
297325 process_id : 0 ,
@@ -319,6 +347,25 @@ fn event_index_to_addr(event_index: usize) -> usize {
319347 FILE_HEADER_SIZE + event_index * mem:: size_of :: < RawEvent > ( )
320348}
321349
350+ // This struct reflects what filenames were in old versions of measureme. It is
351+ // used only for giving helpful error messages now if a user tries to load old
352+ // data.
353+ struct ProfilerFiles {
354+ pub events_file : PathBuf ,
355+ pub string_data_file : PathBuf ,
356+ pub string_index_file : PathBuf ,
357+ }
358+
359+ impl ProfilerFiles {
360+ fn new < P : AsRef < Path > > ( path_stem : P ) -> ProfilerFiles {
361+ ProfilerFiles {
362+ events_file : path_stem. as_ref ( ) . with_extension ( "events" ) ,
363+ string_data_file : path_stem. as_ref ( ) . with_extension ( "string_data" ) ,
364+ string_index_file : path_stem. as_ref ( ) . with_extension ( "string_index" ) ,
365+ }
366+ }
367+ }
368+
322369#[ rustfmt:: skip]
323370#[ cfg( test) ]
324371mod tests {
0 commit comments