Skip to content

Commit cd3e70f

Browse files
Extend FileSerializationSink to support in-memory storage and use this instead of ByteVecSink.
1 parent 38e462d commit cd3e70f

File tree

6 files changed

+78
-72
lines changed

6 files changed

+78
-72
lines changed

analyzeme/src/profiling_data.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ 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::ByteVecSink;
10-
use measureme::{EventId, ProfilerFiles, RawEvent, SerializationSink, StringTableBuilder};
9+
use measureme::{
10+
EventId, FileSerializationSink, ProfilerFiles, RawEvent, SerializationSink, StringTableBuilder,
11+
};
1112
use serde::{Deserialize, Deserializer};
1213
use std::error::Error;
1314
use std::fs;
@@ -200,17 +201,17 @@ impl<'a> DoubleEndedIterator for ProfilerEventIterator<'a> {
200201
/// implementation might not be efficient, which why it should only be used for
201202
/// writing tests and other things that are not performance sensitive.
202203
pub struct ProfilingDataBuilder {
203-
event_sink: ByteVecSink,
204-
string_table_data_sink: Arc<ByteVecSink>,
205-
string_table_index_sink: Arc<ByteVecSink>,
206-
string_table: StringTableBuilder<ByteVecSink>,
204+
event_sink: FileSerializationSink,
205+
string_table_data_sink: Arc<FileSerializationSink>,
206+
string_table_index_sink: Arc<FileSerializationSink>,
207+
string_table: StringTableBuilder<FileSerializationSink>,
207208
}
208209

209210
impl ProfilingDataBuilder {
210211
pub fn new() -> ProfilingDataBuilder {
211-
let event_sink = ByteVecSink::new();
212-
let string_table_data_sink = Arc::new(ByteVecSink::new());
213-
let string_table_index_sink = Arc::new(ByteVecSink::new());
212+
let event_sink = FileSerializationSink::new_in_memory();
213+
let string_table_data_sink = Arc::new(FileSerializationSink::new_in_memory());
214+
let string_table_index_sink = Arc::new(FileSerializationSink::new_in_memory());
214215

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

analyzeme/src/stringtable.rs

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

249249
#[test]
250250
fn simple_strings() {
251-
let data_sink = Arc::new(ByteVecSink::new());
252-
let index_sink = Arc::new(ByteVecSink::new());
251+
let data_sink = Arc::new(FileSerializationSink::new_in_memory());
252+
let index_sink = Arc::new(FileSerializationSink::new_in_memory());
253253

254254
let expected_strings = &[
255255
"abc",
@@ -289,8 +289,8 @@ mod tests {
289289

290290
#[test]
291291
fn composite_string() {
292-
let data_sink = Arc::new(ByteVecSink::new());
293-
let index_sink = Arc::new(ByteVecSink::new());
292+
let data_sink = Arc::new(FileSerializationSink::new_in_memory());
293+
let index_sink = Arc::new(FileSerializationSink::new_in_memory());
294294

295295
let expected_strings = &[
296296
"abc", // 0

measureme/src/file_header.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,11 @@ pub fn strip_file_header(data: &[u8]) -> &[u8] {
5454
#[cfg(test)]
5555
mod tests {
5656
use super::*;
57-
use crate::serialization::ByteVecSink;
57+
use crate::file_serialization_sink::FileSerializationSink;
5858

5959
#[test]
6060
fn roundtrip() {
61-
let data_sink = ByteVecSink::new();
61+
let data_sink = FileSerializationSink::new_in_memory();
6262

6363
write_file_header(&data_sink, FILE_MAGIC_EVENT_STREAM);
6464

@@ -72,7 +72,7 @@ mod tests {
7272

7373
#[test]
7474
fn invalid_magic() {
75-
let data_sink = ByteVecSink::new();
75+
let data_sink = FileSerializationSink::new_in_memory();
7676
write_file_header(&data_sink, FILE_MAGIC_STRINGTABLE_DATA);
7777
let mut data = data_sink.into_bytes();
7878

@@ -83,7 +83,7 @@ mod tests {
8383

8484
#[test]
8585
fn other_version() {
86-
let data_sink = ByteVecSink::new();
86+
let data_sink = FileSerializationSink::new_in_memory();
8787

8888
write_file_header(&data_sink, FILE_MAGIC_STRINGTABLE_INDEX);
8989

measureme/src/file_serialization_sink.rs

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,76 @@
11
use crate::serialization::{Addr, SerializationSink};
22
use parking_lot::Mutex;
33
use std::error::Error;
4+
use std::fmt::Debug;
45
use std::fs;
56
use std::io::Write;
67
use std::path::Path;
78

9+
#[derive(Debug)]
810
pub struct FileSerializationSink {
911
data: Mutex<Inner>,
1012
}
1113

14+
/// The `BackingStorage` is what the data gets written to.
15+
trait BackingStorage: Write + Send + Debug {
16+
fn drain_bytes(&mut self) -> Vec<u8>;
17+
}
18+
19+
impl BackingStorage for fs::File {
20+
fn drain_bytes(&mut self) -> Vec<u8> {
21+
unimplemented!()
22+
}
23+
}
24+
25+
impl BackingStorage for Vec<u8> {
26+
fn drain_bytes(&mut self) -> Vec<u8> {
27+
let mut bytes = Vec::new();
28+
std::mem::swap(&mut bytes, self);
29+
bytes
30+
}
31+
}
32+
33+
#[derive(Debug)]
1234
struct Inner {
13-
file: fs::File,
35+
file: Box<dyn BackingStorage>,
1436
buffer: Vec<u8>,
1537
buf_pos: usize,
1638
addr: u32,
1739
}
1840

41+
impl FileSerializationSink {
42+
pub fn new_in_memory() -> FileSerializationSink {
43+
FileSerializationSink {
44+
data: Mutex::new(Inner {
45+
file: Box::new(Vec::new()),
46+
buffer: vec![0; 1024 * 512],
47+
buf_pos: 0,
48+
addr: 0,
49+
}),
50+
}
51+
}
52+
53+
/// Create a copy of all data written so far. This method meant to be used
54+
/// for writing unit tests. It will panic if the underlying `BackingStorage`
55+
/// does not implement `extract_bytes`.
56+
pub fn into_bytes(self) -> Vec<u8> {
57+
let mut data = self.data.lock();
58+
let Inner {
59+
ref mut file,
60+
ref mut buffer,
61+
ref mut buf_pos,
62+
addr: _,
63+
} = *data;
64+
65+
// We need to flush the buffer first.
66+
file.write_all(&buffer[..*buf_pos]).unwrap();
67+
*buf_pos = 0;
68+
69+
// Then we can create a copy of the data written so far.
70+
file.drain_bytes()
71+
}
72+
}
73+
1974
impl SerializationSink for FileSerializationSink {
2075
fn from_path(path: &Path) -> Result<Self, Box<dyn Error + Send + Sync>> {
2176
fs::create_dir_all(path.parent().unwrap())?;
@@ -24,7 +79,7 @@ impl SerializationSink for FileSerializationSink {
2479

2580
Ok(FileSerializationSink {
2681
data: Mutex::new(Inner {
27-
file,
82+
file: Box::new(file),
2883
buffer: vec![0; 1024 * 512],
2984
buf_pos: 0,
3085
addr: 0,

measureme/src/lib.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,7 @@
3636
//! [`Profiler::start_recording_interval_event()`]: Profiler::start_recording_interval_event
3737
//! [`StringId`]: StringId
3838
#![allow(renamed_and_removed_lints)] // intra_doc_link_resolution_failure is renamed on nightly
39-
#![deny(
40-
warnings,
41-
intra_doc_link_resolution_failure,
42-
)]
39+
#![deny(warnings, intra_doc_link_resolution_failure)]
4340

4441
pub mod event_id;
4542
pub mod file_header;
@@ -61,5 +58,5 @@ pub use crate::file_serialization_sink::FileSerializationSink;
6158
pub use crate::mmap_serialization_sink::MmapSerializationSink;
6259
pub use crate::profiler::{Profiler, ProfilerFiles, TimingGuard};
6360
pub use crate::raw_event::{RawEvent, MAX_INSTANT_TIMESTAMP, MAX_INTERVAL_TIMESTAMP};
64-
pub use crate::serialization::{Addr, ByteVecSink, SerializationSink};
61+
pub use crate::serialization::{Addr, SerializationSink};
6562
pub use crate::stringtable::{SerializableString, StringComponent, StringId, StringTableBuilder};

measureme/src/serialization.rs

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use parking_lot::Mutex;
21
use std::error::Error;
32
use std::path::Path;
43

@@ -32,49 +31,3 @@ pub trait SerializationSink: Sized + Send + Sync + 'static {
3231
self.write_atomic(bytes.len(), |sink| sink.copy_from_slice(bytes))
3332
}
3433
}
35-
36-
/// A `SerializationSink` that writes to an internal `Vec<u8>` and can be
37-
/// converted into this raw `Vec<u8>`. This implementation is only meant to be
38-
/// used for testing and is not very efficient.
39-
pub struct ByteVecSink {
40-
data: Mutex<Vec<u8>>,
41-
}
42-
43-
impl ByteVecSink {
44-
pub fn new() -> ByteVecSink {
45-
ByteVecSink {
46-
data: Mutex::new(Vec::new()),
47-
}
48-
}
49-
50-
pub fn into_bytes(self) -> Vec<u8> {
51-
self.data.into_inner()
52-
}
53-
}
54-
55-
impl SerializationSink for ByteVecSink {
56-
fn from_path(_path: &Path) -> Result<Self, Box<dyn Error + Send + Sync>> {
57-
unimplemented!()
58-
}
59-
60-
fn write_atomic<W>(&self, num_bytes: usize, write: W) -> Addr
61-
where
62-
W: FnOnce(&mut [u8]),
63-
{
64-
let mut data = self.data.lock();
65-
66-
let start = data.len();
67-
68-
data.resize(start + num_bytes, 0);
69-
70-
write(&mut data[start..]);
71-
72-
Addr(start as u32)
73-
}
74-
}
75-
76-
impl std::fmt::Debug for ByteVecSink {
77-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78-
write!(f, "ByteVecSink")
79-
}
80-
}

0 commit comments

Comments
 (0)