Skip to content

Commit 1825a06

Browse files
Implement paged serialization approach.
This allows to store all data in a single file instead of three separate ones.
1 parent ce63252 commit 1825a06

File tree

7 files changed

+316
-130
lines changed

7 files changed

+316
-130
lines changed

analyzeme/src/profiling_data.rs

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ use measureme::file_header::{
66
read_file_header, write_file_header, CURRENT_FILE_FORMAT_VERSION, FILE_HEADER_SIZE,
77
FILE_MAGIC_EVENT_STREAM,
88
};
9-
use measureme::{EventId, ProfilerFiles, RawEvent, SerializationSink, StringTableBuilder};
9+
use measureme::{
10+
EventId, PageTag, ProfilerFiles, RawEvent, SerializationSink, SerializationSinkBuilder,
11+
StringTableBuilder,
12+
};
1013
use serde::{Deserialize, Deserializer};
1114
use std::error::Error;
1215
use std::fs;
@@ -46,12 +49,26 @@ impl ProfilingData {
4649
pub fn new(path_stem: &Path) -> Result<ProfilingData, Box<dyn Error>> {
4750
let paths = ProfilerFiles::new(path_stem);
4851

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");
52+
let paged_path = path_stem.with_extension("mm_raw");
53+
54+
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[..]);
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();
5361

54-
ProfilingData::from_buffers(string_data, index_data, event_data)
62+
ProfilingData::from_buffers(string_data, index_data, event_data)
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)
71+
}
5572
}
5673

5774
pub fn from_buffers(
@@ -207,9 +224,11 @@ pub struct ProfilingDataBuilder {
207224

208225
impl ProfilingDataBuilder {
209226
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());
227+
let sink_builder = SerializationSinkBuilder::new_in_memory();
228+
229+
let event_sink = sink_builder.new_sink(PageTag::Events);
230+
let string_table_data_sink = Arc::new(sink_builder.new_sink(PageTag::StringData));
231+
let string_table_index_sink = Arc::new(sink_builder.new_sink(PageTag::StringIndex));
213232

214233
// The first thing in every file we generate must be the file header.
215234
write_file_header(&event_sink, FILE_MAGIC_EVENT_STREAM);

analyzeme/src/stringtable.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -243,13 +243,14 @@ impl StringTable {
243243
#[cfg(test)]
244244
mod tests {
245245
use super::*;
246-
use measureme::{SerializationSink, StringComponent, StringTableBuilder};
246+
use measureme::{PageTag, SerializationSinkBuilder, StringComponent, StringTableBuilder};
247247
use std::sync::Arc;
248248

249249
#[test]
250250
fn simple_strings() {
251-
let data_sink = Arc::new(SerializationSink::new_in_memory());
252-
let index_sink = Arc::new(SerializationSink::new_in_memory());
251+
let sink_builder = SerializationSinkBuilder::new_in_memory();
252+
let data_sink = Arc::new(sink_builder.new_sink(PageTag::StringData));
253+
let index_sink = Arc::new(sink_builder.new_sink(PageTag::StringIndex));
253254

254255
let expected_strings = &[
255256
"abc",
@@ -289,8 +290,9 @@ mod tests {
289290

290291
#[test]
291292
fn composite_string() {
292-
let data_sink = Arc::new(SerializationSink::new_in_memory());
293-
let index_sink = Arc::new(SerializationSink::new_in_memory());
293+
let sink_builder = SerializationSinkBuilder::new_in_memory();
294+
let data_sink = Arc::new(sink_builder.new_sink(PageTag::StringData));
295+
let index_sink = Arc::new(sink_builder.new_sink(PageTag::StringIndex));
294296

295297
let expected_strings = &[
296298
"abc", // 0

analyzeme/src/testing_common.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,18 +96,20 @@ fn generate_profiling_data(
9696
})
9797
.collect();
9898

99-
let expected_events: Vec<_> = threads
100-
.into_iter()
101-
.flat_map(|t| t.join().unwrap())
102-
.collect();
103-
10499
// An example of allocating the string contents of an event id that has
105100
// already been used
106101
profiler.map_virtual_to_concrete_string(
107102
event_id_virtual.to_string_id(),
108103
profiler.alloc_string("SomeQuery"),
109104
);
110105

106+
drop(profiler);
107+
108+
let expected_events: Vec<_> = threads
109+
.into_iter()
110+
.flat_map(|t| t.join().unwrap())
111+
.collect();
112+
111113
expected_events
112114
}
113115

measureme/src/file_header.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::SerializationSink;
55
use std::convert::TryInto;
66
use std::error::Error;
77

8-
pub const CURRENT_FILE_FORMAT_VERSION: u32 = 5;
8+
pub const CURRENT_FILE_FORMAT_VERSION: u32 = 6;
99
pub const FILE_MAGIC_EVENT_STREAM: &[u8; 4] = b"MMES";
1010
pub const FILE_MAGIC_STRINGTABLE_DATA: &[u8; 4] = b"MMSD";
1111
pub const FILE_MAGIC_STRINGTABLE_INDEX: &[u8; 4] = b"MMSI";
@@ -53,11 +53,11 @@ pub fn strip_file_header(data: &[u8]) -> &[u8] {
5353
#[cfg(test)]
5454
mod tests {
5555
use super::*;
56-
use crate::SerializationSink;
56+
use crate::{PageTag, SerializationSinkBuilder};
5757

5858
#[test]
5959
fn roundtrip() {
60-
let data_sink = SerializationSink::new_in_memory();
60+
let data_sink = SerializationSinkBuilder::new_in_memory().new_sink(PageTag::Events);
6161

6262
write_file_header(&data_sink, FILE_MAGIC_EVENT_STREAM);
6363

@@ -71,7 +71,7 @@ mod tests {
7171

7272
#[test]
7373
fn invalid_magic() {
74-
let data_sink = SerializationSink::new_in_memory();
74+
let data_sink = SerializationSinkBuilder::new_in_memory().new_sink(PageTag::Events);
7575
write_file_header(&data_sink, FILE_MAGIC_STRINGTABLE_DATA);
7676
let mut data = data_sink.into_bytes();
7777

@@ -82,7 +82,7 @@ mod tests {
8282

8383
#[test]
8484
fn other_version() {
85-
let data_sink = SerializationSink::new_in_memory();
85+
let data_sink = SerializationSinkBuilder::new_in_memory().new_sink(PageTag::Events);
8686

8787
write_file_header(&data_sink, FILE_MAGIC_STRINGTABLE_INDEX);
8888

measureme/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,5 +50,7 @@ pub mod rustc;
5050
pub use crate::event_id::{EventId, EventIdBuilder};
5151
pub use crate::profiler::{Profiler, ProfilerFiles, TimingGuard};
5252
pub use crate::raw_event::{RawEvent, MAX_INSTANT_TIMESTAMP, MAX_INTERVAL_TIMESTAMP};
53-
pub use crate::serialization::{Addr, SerializationSink};
53+
pub use crate::serialization::{
54+
split_streams, Addr, PageTag, SerializationSink, SerializationSinkBuilder,
55+
};
5456
pub use crate::stringtable::{SerializableString, StringComponent, StringId, StringTableBuilder};

measureme/src/profiler.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::event_id::EventId;
22
use crate::file_header::{write_file_header, FILE_MAGIC_EVENT_STREAM};
33
use crate::raw_event::RawEvent;
4-
use crate::serialization::SerializationSink;
4+
use crate::serialization::{PageTag, SerializationSink, SerializationSinkBuilder};
55
use crate::stringtable::{SerializableString, StringId, StringTableBuilder};
66
use std::error::Error;
77
use std::path::{Path, PathBuf};
@@ -32,15 +32,17 @@ pub struct Profiler {
3232

3333
impl Profiler {
3434
pub fn new<P: AsRef<Path>>(path_stem: P) -> Result<Profiler, Box<dyn Error + Send + Sync>> {
35-
let paths = ProfilerFiles::new(path_stem.as_ref());
36-
let event_sink = Arc::new(SerializationSink::from_path(&paths.events_file)?);
35+
let path = path_stem.as_ref().with_extension("mm_raw");
36+
let sink_builder = SerializationSinkBuilder::from_path(&path)?;
3737

38-
// The first thing in every file we generate must be the file header.
38+
let event_sink = Arc::new(sink_builder.new_sink(PageTag::Events));
39+
40+
// The first thing in every stream we generate must be the stream header.
3941
write_file_header(&*event_sink, FILE_MAGIC_EVENT_STREAM);
4042

4143
let string_table = StringTableBuilder::new(
42-
Arc::new(SerializationSink::from_path(&paths.string_data_file)?),
43-
Arc::new(SerializationSink::from_path(&paths.string_index_file)?),
44+
Arc::new(sink_builder.new_sink(PageTag::StringData)),
45+
Arc::new(sink_builder.new_sink(PageTag::StringIndex)),
4446
);
4547

4648
let profiler = Profiler {

0 commit comments

Comments
 (0)