@@ -3,20 +3,19 @@ use crate::lightweight_event::LightweightEvent;
3
3
use crate :: timestamp:: Timestamp ;
4
4
use crate :: StringTable ;
5
5
use 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
8
} ;
9
9
use measureme:: {
10
- EventId , PageTag , ProfilerFiles , RawEvent , SerializationSink , SerializationSinkBuilder ,
11
- StringTableBuilder ,
10
+ EventId , PageTag , RawEvent , SerializationSink , SerializationSinkBuilder , StringTableBuilder ,
12
11
} ;
13
12
use serde:: { Deserialize , Deserializer } ;
14
- use std:: error:: Error ;
15
13
use std:: fs;
16
14
use std:: mem;
17
15
use std:: path:: Path ;
18
16
use std:: sync:: Arc ;
19
17
use std:: time:: { Duration , SystemTime , UNIX_EPOCH } ;
18
+ use std:: { error:: Error , path:: PathBuf } ;
20
19
21
20
const RAW_EVENT_SIZE : usize = mem:: size_of :: < RawEvent > ( ) ;
22
21
@@ -46,49 +45,60 @@ pub struct ProfilingData {
46
45
}
47
46
48
47
impl ProfilingData {
49
- pub fn new ( path_stem : & Path ) -> Result < ProfilingData , Box < dyn Error > > {
50
- let paths = ProfilerFiles :: new ( path_stem) ;
51
-
52
- let paged_path = path_stem. with_extension ( "mm_raw" ) ;
48
+ pub fn new ( path_stem : & Path ) -> Result < ProfilingData , Box < dyn Error + Send + Sync > > {
49
+ let paged_path = path_stem. with_extension ( FILE_EXTENSION ) ;
53
50
54
51
if paged_path. exists ( ) {
55
- let data = fs:: read ( paged_path) . expect ( "couldn't read paged file" ) ;
56
- let mut split_data = measureme:: split_streams ( & data[ ..] ) ;
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
57
58
58
let string_data = split_data. remove ( & PageTag :: StringData ) . unwrap ( ) ;
59
59
let index_data = split_data. remove ( & PageTag :: StringIndex ) . unwrap ( ) ;
60
60
let event_data = split_data. remove ( & PageTag :: Events ) . unwrap ( ) ;
61
61
62
- ProfilingData :: from_buffers ( string_data, index_data, event_data)
62
+ ProfilingData :: from_buffers ( string_data, index_data, event_data, Some ( & paged_path ) )
63
63
} else {
64
- let string_data =
65
- fs:: read ( paths. string_data_file ) . expect ( "couldn't read string_data file" ) ;
66
- let index_data =
67
- fs:: read ( paths. string_index_file ) . expect ( "couldn't read string_index file" ) ;
68
- let event_data = fs:: read ( paths. events_file ) . expect ( "couldn't read events file" ) ;
69
-
70
- ProfilingData :: from_buffers ( string_data, index_data, event_data)
64
+ let mut msg = format ! (
65
+ "Could not find profiling data file `{}`." ,
66
+ paged_path. display( )
67
+ ) ;
68
+
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) ) ;
71
82
}
72
83
}
73
84
74
85
pub fn from_buffers (
75
86
string_data : Vec < u8 > ,
76
87
string_index : Vec < u8 > ,
77
88
events : Vec < u8 > ,
78
- ) -> Result < ProfilingData , Box < dyn Error > > {
89
+ diagnostic_file_path : Option < & Path > ,
90
+ ) -> Result < ProfilingData , Box < dyn Error + Send + Sync > > {
79
91
let index_data = string_index;
80
92
let event_data = events;
81
93
82
- let event_data_format = read_file_header ( & event_data, FILE_MAGIC_EVENT_STREAM ) ?;
83
- if event_data_format != CURRENT_FILE_FORMAT_VERSION {
84
- Err ( format ! (
85
- "Event stream file format version '{}' is not supported
86
- by this version of `measureme`." ,
87
- event_data_format
88
- ) ) ?;
89
- }
94
+ verify_file_header (
95
+ & event_data,
96
+ FILE_MAGIC_EVENT_STREAM ,
97
+ diagnostic_file_path,
98
+ "event" ,
99
+ ) ?;
90
100
91
- let string_table = StringTable :: new ( string_data, index_data) ?;
101
+ let string_table = StringTable :: new ( string_data, index_data, diagnostic_file_path ) ?;
92
102
93
103
let metadata = string_table. get_metadata ( ) . to_string ( ) ;
94
104
let metadata: Metadata = serde_json:: from_str ( & metadata) ?;
@@ -231,12 +241,13 @@ impl ProfilingDataBuilder {
231
241
let string_table_index_sink = Arc :: new ( sink_builder. new_sink ( PageTag :: StringIndex ) ) ;
232
242
233
243
// The first thing in every file we generate must be the file header.
234
- write_file_header ( & event_sink, FILE_MAGIC_EVENT_STREAM ) ;
244
+ write_file_header ( & mut event_sink. as_std_write ( ) , FILE_MAGIC_EVENT_STREAM ) . unwrap ( ) ;
235
245
236
246
let string_table = StringTableBuilder :: new (
237
247
string_table_data_sink. clone ( ) ,
238
248
string_table_index_sink. clone ( ) ,
239
- ) ;
249
+ )
250
+ . unwrap ( ) ;
240
251
241
252
ProfilingDataBuilder {
242
253
event_sink,
@@ -306,11 +317,9 @@ impl ProfilingDataBuilder {
306
317
. unwrap ( )
307
318
. into_bytes ( ) ;
308
319
309
- assert_eq ! (
310
- read_file_header( & event_data, FILE_MAGIC_EVENT_STREAM ) . unwrap( ) ,
311
- CURRENT_FILE_FORMAT_VERSION
312
- ) ;
313
- 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 ( ) ;
314
323
let metadata = Metadata {
315
324
start_time : UNIX_EPOCH ,
316
325
process_id : 0 ,
@@ -338,6 +347,25 @@ fn event_index_to_addr(event_index: usize) -> usize {
338
347
FILE_HEADER_SIZE + event_index * mem:: size_of :: < RawEvent > ( )
339
348
}
340
349
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
+
341
369
#[ rustfmt:: skip]
342
370
#[ cfg( test) ]
343
371
mod tests {
0 commit comments