Skip to content

Commit 410bcaf

Browse files
Update file header handling for paged data format.
1 parent 1825a06 commit 410bcaf

File tree

12 files changed

+201
-126
lines changed

12 files changed

+201
-126
lines changed

analyzeme/src/profiling_data.rs

Lines changed: 64 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,19 @@ use crate::lightweight_event::LightweightEvent;
33
use crate::timestamp::Timestamp;
44
use crate::StringTable;
55
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,
88
};
99
use measureme::{
10-
EventId, PageTag, ProfilerFiles, RawEvent, SerializationSink, SerializationSinkBuilder,
11-
StringTableBuilder,
10+
EventId, PageTag, RawEvent, SerializationSink, SerializationSinkBuilder, StringTableBuilder,
1211
};
1312
use serde::{Deserialize, Deserializer};
14-
use std::error::Error;
1513
use std::fs;
1614
use std::mem;
1715
use std::path::Path;
1816
use std::sync::Arc;
1917
use std::time::{Duration, SystemTime, UNIX_EPOCH};
18+
use std::{error::Error, path::PathBuf};
2019

2120
const RAW_EVENT_SIZE: usize = mem::size_of::<RawEvent>();
2221

@@ -46,49 +45,60 @@ pub struct ProfilingData {
4645
}
4746

4847
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);
5350

5451
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..]);
5757

5858
let string_data = split_data.remove(&PageTag::StringData).unwrap();
5959
let index_data = split_data.remove(&PageTag::StringIndex).unwrap();
6060
let event_data = split_data.remove(&PageTag::Events).unwrap();
6161

62-
ProfilingData::from_buffers(string_data, index_data, event_data)
62+
ProfilingData::from_buffers(string_data, index_data, event_data, Some(&paged_path))
6363
} 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));
7182
}
7283
}
7384

7485
pub fn from_buffers(
7586
string_data: Vec<u8>,
7687
string_index: Vec<u8>,
7788
events: Vec<u8>,
78-
) -> Result<ProfilingData, Box<dyn Error>> {
89+
diagnostic_file_path: Option<&Path>,
90+
) -> Result<ProfilingData, Box<dyn Error + Send + Sync>> {
7991
let index_data = string_index;
8092
let event_data = events;
8193

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+
)?;
90100

91-
let string_table = StringTable::new(string_data, index_data)?;
101+
let string_table = StringTable::new(string_data, index_data, diagnostic_file_path)?;
92102

93103
let metadata = string_table.get_metadata().to_string();
94104
let metadata: Metadata = serde_json::from_str(&metadata)?;
@@ -231,12 +241,13 @@ impl ProfilingDataBuilder {
231241
let string_table_index_sink = Arc::new(sink_builder.new_sink(PageTag::StringIndex));
232242

233243
// 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();
235245

236246
let string_table = StringTableBuilder::new(
237247
string_table_data_sink.clone(),
238248
string_table_index_sink.clone(),
239-
);
249+
)
250+
.unwrap();
240251

241252
ProfilingDataBuilder {
242253
event_sink,
@@ -306,11 +317,9 @@ impl ProfilingDataBuilder {
306317
.unwrap()
307318
.into_bytes();
308319

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();
314323
let metadata = Metadata {
315324
start_time: UNIX_EPOCH,
316325
process_id: 0,
@@ -338,6 +347,25 @@ fn event_index_to_addr(event_index: usize) -> usize {
338347
FILE_HEADER_SIZE + event_index * mem::size_of::<RawEvent>()
339348
}
340349

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+
341369
#[rustfmt::skip]
342370
#[cfg(test)]
343371
mod tests {

analyzeme/src/stringtable.rs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! See module-level documentation `measureme::stringtable`.
22
33
use measureme::file_header::{
4-
read_file_header, strip_file_header, CURRENT_FILE_FORMAT_VERSION, FILE_MAGIC_STRINGTABLE_DATA,
4+
strip_file_header, verify_file_header, FILE_MAGIC_STRINGTABLE_DATA,
55
FILE_MAGIC_STRINGTABLE_INDEX,
66
};
77
use measureme::stringtable::{METADATA_STRING_ID, STRING_ID_MASK, TERMINATOR};
@@ -11,6 +11,7 @@ use rustc_hash::FxHashMap;
1111
use std::borrow::Cow;
1212
use std::convert::TryInto;
1313
use std::error::Error;
14+
use std::path::Path;
1415

1516
fn deserialize_index_entry(bytes: &[u8]) -> (StringId, Addr) {
1617
(
@@ -204,21 +205,23 @@ pub struct StringTable {
204205
}
205206

206207
impl StringTable {
207-
pub fn new(string_data: Vec<u8>, index_data: Vec<u8>) -> Result<StringTable, Box<dyn Error>> {
208-
let string_data_format = read_file_header(&string_data, FILE_MAGIC_STRINGTABLE_DATA)?;
209-
let index_data_format = read_file_header(&index_data, FILE_MAGIC_STRINGTABLE_INDEX)?;
210-
211-
if string_data_format != index_data_format {
212-
Err("Mismatch between StringTable DATA and INDEX format version")?;
213-
}
214-
215-
if string_data_format != CURRENT_FILE_FORMAT_VERSION {
216-
Err(format!(
217-
"StringTable file format version '{}' is not supported
218-
by this version of `measureme`.",
219-
string_data_format
220-
))?;
221-
}
208+
pub fn new(
209+
string_data: Vec<u8>,
210+
index_data: Vec<u8>,
211+
diagnostic_file_path: Option<&Path>,
212+
) -> Result<StringTable, Box<dyn Error + Send + Sync>> {
213+
verify_file_header(
214+
&string_data,
215+
FILE_MAGIC_STRINGTABLE_DATA,
216+
diagnostic_file_path,
217+
"StringTable Data",
218+
)?;
219+
verify_file_header(
220+
&index_data,
221+
FILE_MAGIC_STRINGTABLE_INDEX,
222+
diagnostic_file_path,
223+
"StringTable Index",
224+
)?;
222225

223226
assert!(index_data.len() % 8 == 0);
224227
let index: FxHashMap<_, _> = strip_file_header(&index_data)
@@ -265,7 +268,7 @@ mod tests {
265268
let mut string_ids = vec![];
266269

267270
{
268-
let builder = StringTableBuilder::new(data_sink.clone(), index_sink.clone());
271+
let builder = StringTableBuilder::new(data_sink.clone(), index_sink.clone()).unwrap();
269272

270273
for &s in expected_strings {
271274
string_ids.push(builder.alloc(s));
@@ -275,7 +278,7 @@ mod tests {
275278
let data_bytes = Arc::try_unwrap(data_sink).unwrap().into_bytes();
276279
let index_bytes = Arc::try_unwrap(index_sink).unwrap().into_bytes();
277280

278-
let string_table = StringTable::new(data_bytes, index_bytes).unwrap();
281+
let string_table = StringTable::new(data_bytes, index_bytes, None).unwrap();
279282

280283
for (&id, &expected_string) in string_ids.iter().zip(expected_strings.iter()) {
281284
let str_ref = string_table.get(id);
@@ -308,7 +311,7 @@ mod tests {
308311
let mut string_ids = vec![];
309312

310313
{
311-
let builder = StringTableBuilder::new(data_sink.clone(), index_sink.clone());
314+
let builder = StringTableBuilder::new(data_sink.clone(), index_sink.clone()).unwrap();
312315

313316
let r = |id| StringComponent::Ref(id);
314317
let v = |s| StringComponent::Value(s);
@@ -331,7 +334,7 @@ mod tests {
331334
let data_bytes = Arc::try_unwrap(data_sink).unwrap().into_bytes();
332335
let index_bytes = Arc::try_unwrap(index_sink).unwrap().into_bytes();
333336

334-
let string_table = StringTable::new(data_bytes, index_bytes).unwrap();
337+
let string_table = StringTable::new(data_bytes, index_bytes, None).unwrap();
335338

336339
for (&id, &expected_string) in string_ids.iter().zip(expected_strings.iter()) {
337340
let str_ref = string_table.get(id);

crox/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ fn get_args(full_event: &analyzeme::Event) -> Option<FxHashMap<String, String>>
131131
}
132132
}
133133

134-
fn main() -> Result<(), Box<dyn std::error::Error>> {
134+
fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
135135
let opt = Opt::from_args();
136136

137137
let chrome_file = BufWriter::new(fs::File::create("chrome_profiler.json")?);

flamegraph/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ struct Opt {
1212
file_prefix: PathBuf,
1313
}
1414

15-
fn main() -> Result<(), Box<dyn Error>> {
15+
fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
1616
let opt = Opt::from_args();
1717

1818
let profiling_data = ProfilingData::new(&opt.file_prefix)?;

0 commit comments

Comments
 (0)