@@ -3,17 +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
+ } ;
9
+ use measureme:: {
10
+ EventId , PageTag , RawEvent , SerializationSink , SerializationSinkBuilder , StringTableBuilder ,
8
11
} ;
9
- use measureme:: { EventId , ProfilerFiles , RawEvent , SerializationSink , StringTableBuilder } ;
10
12
use serde:: { Deserialize , Deserializer } ;
11
- use std:: error:: Error ;
12
13
use std:: fs;
13
14
use std:: mem;
14
15
use std:: path:: Path ;
15
16
use std:: sync:: Arc ;
16
17
use std:: time:: { Duration , SystemTime , UNIX_EPOCH } ;
18
+ use std:: { error:: Error , path:: PathBuf } ;
17
19
18
20
const RAW_EVENT_SIZE : usize = mem:: size_of :: < RawEvent > ( ) ;
19
21
@@ -43,35 +45,60 @@ pub struct ProfilingData {
43
45
}
44
46
45
47
impl 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 ( ) ;
48
61
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
+ ) ;
53
68
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
+ }
55
83
}
56
84
57
85
pub fn from_buffers (
58
86
string_data : Vec < u8 > ,
59
87
string_index : Vec < u8 > ,
60
88
events : Vec < u8 > ,
61
- ) -> Result < ProfilingData , Box < dyn Error > > {
89
+ diagnostic_file_path : Option < & Path > ,
90
+ ) -> Result < ProfilingData , Box < dyn Error + Send + Sync > > {
62
91
let index_data = string_index;
63
92
let event_data = events;
64
93
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
+ ) ?;
73
100
74
- let string_table = StringTable :: new ( string_data, index_data) ?;
101
+ let string_table = StringTable :: new ( string_data, index_data, diagnostic_file_path ) ?;
75
102
76
103
let metadata = string_table. get_metadata ( ) . to_string ( ) ;
77
104
let metadata: Metadata = serde_json:: from_str ( & metadata) ?;
@@ -207,17 +234,20 @@ pub struct ProfilingDataBuilder {
207
234
208
235
impl ProfilingDataBuilder {
209
236
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 ) ) ;
213
242
214
243
// 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 ( ) ;
216
245
217
246
let string_table = StringTableBuilder :: new (
218
247
string_table_data_sink. clone ( ) ,
219
248
string_table_index_sink. clone ( ) ,
220
- ) ;
249
+ )
250
+ . unwrap ( ) ;
221
251
222
252
ProfilingDataBuilder {
223
253
event_sink,
@@ -287,11 +317,9 @@ impl ProfilingDataBuilder {
287
317
. unwrap ( )
288
318
. into_bytes ( ) ;
289
319
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 ( ) ;
295
323
let metadata = Metadata {
296
324
start_time : UNIX_EPOCH ,
297
325
process_id : 0 ,
@@ -319,6 +347,25 @@ fn event_index_to_addr(event_index: usize) -> usize {
319
347
FILE_HEADER_SIZE + event_index * mem:: size_of :: < RawEvent > ( )
320
348
}
321
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
+
322
369
#[ rustfmt:: skip]
323
370
#[ cfg( test) ]
324
371
mod tests {
0 commit comments