1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
use crate::file_header::{write_file_header, FILE_MAGIC_EVENT_STREAM};
use crate::raw_event::{RawEvent, Timestamp, TimestampKind};
use crate::serialization::SerializationSink;
use crate::stringtable::{SerializableString, StringId, StringTableBuilder};
use std::error::Error;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::time::Instant;
pub struct ProfilerFiles {
pub events_file: PathBuf,
pub string_data_file: PathBuf,
pub string_index_file: PathBuf,
}
impl ProfilerFiles {
pub fn new(path_stem: &Path) -> ProfilerFiles {
ProfilerFiles {
events_file: path_stem.with_extension("events"),
string_data_file: path_stem.with_extension("string_data"),
string_index_file: path_stem.with_extension("string_index"),
}
}
}
pub struct Profiler<S: SerializationSink> {
event_sink: Arc<S>,
string_table: StringTableBuilder<S>,
start_time: Instant,
}
impl<S: SerializationSink> Profiler<S> {
pub fn new(path_stem: &Path) -> Result<Profiler<S>, Box<dyn Error>> {
let paths = ProfilerFiles::new(path_stem);
let event_sink = Arc::new(S::from_path(&paths.events_file)?);
write_file_header(&*event_sink, FILE_MAGIC_EVENT_STREAM);
let string_table = StringTableBuilder::new(
Arc::new(S::from_path(&paths.string_data_file)?),
Arc::new(S::from_path(&paths.string_index_file)?),
);
Ok(Profiler {
event_sink,
string_table,
start_time: Instant::now(),
})
}
#[inline(always)]
pub fn alloc_string_with_reserved_id<STR: SerializableString + ?Sized>(
&self,
id: StringId,
s: &STR,
) -> StringId {
self.string_table.alloc_with_reserved_id(id, s)
}
#[inline(always)]
pub fn alloc_string<STR: SerializableString + ?Sized>(&self, s: &STR) -> StringId {
self.string_table.alloc(s)
}
pub fn record_event(
&self,
event_kind: StringId,
event_id: StringId,
thread_id: u64,
timestamp_kind: TimestampKind,
) {
let duration_since_start = self.start_time.elapsed();
let nanos_since_start = duration_since_start.as_secs() * 1_000_000_000
+ duration_since_start.subsec_nanos() as u64;
let timestamp = Timestamp::new(nanos_since_start, timestamp_kind);
self.event_sink
.write_atomic(std::mem::size_of::<RawEvent>(), |bytes| {
debug_assert_eq!(bytes.len(), std::mem::size_of::<RawEvent>());
let raw_event = RawEvent {
event_kind,
id: event_id,
thread_id,
timestamp,
};
let raw_event_bytes: &[u8] = unsafe {
std::slice::from_raw_parts(
&raw_event as *const _ as *const u8,
std::mem::size_of::<RawEvent>(),
)
};
bytes.copy_from_slice(raw_event_bytes);
});
}
}