]>
Commit | Line | Data |
---|---|---|
48663c56 | 1 | use crate::event::Event; |
e74abb32 | 2 | use crate::file_header::FILE_HEADER_SIZE; |
48663c56 XL |
3 | use crate::{ProfilerFiles, RawEvent, StringTable, TimestampKind}; |
4 | use std::error::Error; | |
5 | use std::fs; | |
6 | use std::mem; | |
7 | use std::path::Path; | |
8 | use std::time::{Duration, SystemTime}; | |
9 | ||
10 | pub struct ProfilingData { | |
11 | event_data: Vec<u8>, | |
12 | string_table: StringTable, | |
13 | } | |
14 | ||
15 | impl ProfilingData { | |
16 | pub fn new(path_stem: &Path) -> Result<ProfilingData, Box<dyn Error>> { | |
17 | let paths = ProfilerFiles::new(path_stem); | |
18 | ||
19 | let string_data = fs::read(paths.string_data_file).expect("couldn't read string_data file"); | |
e74abb32 XL |
20 | let index_data = |
21 | fs::read(paths.string_index_file).expect("couldn't read string_index file"); | |
48663c56 XL |
22 | let event_data = fs::read(paths.events_file).expect("couldn't read events file"); |
23 | ||
24 | let string_table = StringTable::new(string_data, index_data)?; | |
25 | ||
26 | Ok(ProfilingData { | |
27 | string_table, | |
28 | event_data, | |
29 | }) | |
30 | } | |
31 | ||
32 | pub fn iter(&self) -> impl Iterator<Item = Event<'_>> { | |
33 | ProfilerEventIterator::new(&self) | |
34 | } | |
35 | ||
36 | pub fn iter_matching_events(&self) -> impl Iterator<Item = MatchingEvent<'_>> { | |
37 | MatchingEventsIterator::new(ProfilerEventIterator::new(&self)) | |
38 | } | |
39 | } | |
40 | ||
41 | struct ProfilerEventIterator<'a> { | |
42 | data: &'a ProfilingData, | |
43 | curr_event_idx: usize, | |
44 | } | |
45 | ||
46 | impl<'a> ProfilerEventIterator<'a> { | |
47 | pub fn new(data: &'a ProfilingData) -> ProfilerEventIterator<'a> { | |
48 | ProfilerEventIterator { | |
49 | data, | |
50 | curr_event_idx: 0, | |
51 | } | |
52 | } | |
53 | } | |
54 | ||
55 | impl<'a> Iterator for ProfilerEventIterator<'a> { | |
56 | type Item = Event<'a>; | |
57 | ||
58 | fn next(&mut self) -> Option<Event<'a>> { | |
e74abb32 | 59 | let event_start_addr = FILE_HEADER_SIZE + self.curr_event_idx * mem::size_of::<RawEvent>(); |
48663c56 XL |
60 | let event_end_addr = event_start_addr + mem::size_of::<RawEvent>(); |
61 | if event_end_addr > self.data.event_data.len() { | |
62 | return None; | |
63 | } | |
64 | ||
65 | self.curr_event_idx += 1; | |
66 | ||
67 | let raw_event_bytes = &self.data.event_data[event_start_addr..event_end_addr]; | |
68 | ||
69 | let mut raw_event = RawEvent::default(); | |
70 | unsafe { | |
71 | let raw_event = std::slice::from_raw_parts_mut( | |
72 | &mut raw_event as *mut RawEvent as *mut u8, | |
e74abb32 | 73 | std::mem::size_of::<RawEvent>(), |
48663c56 XL |
74 | ); |
75 | raw_event.copy_from_slice(raw_event_bytes); | |
76 | }; | |
77 | ||
78 | let string_table = &self.data.string_table; | |
79 | ||
80 | let mut timestamp = SystemTime::UNIX_EPOCH; | |
81 | timestamp += Duration::from_nanos(raw_event.timestamp.nanos()); | |
82 | ||
83 | Some(Event { | |
84 | event_kind: string_table.get(raw_event.event_kind).to_string(), | |
85 | label: string_table.get(raw_event.id).to_string(), | |
86 | additional_data: &[], | |
87 | timestamp: timestamp, | |
88 | timestamp_kind: raw_event.timestamp.kind(), | |
89 | thread_id: raw_event.thread_id, | |
90 | }) | |
91 | } | |
92 | } | |
93 | ||
94 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | |
95 | pub enum MatchingEvent<'a> { | |
96 | StartStop(Event<'a>, Event<'a>), | |
97 | Instant(Event<'a>), | |
98 | } | |
99 | ||
100 | struct MatchingEventsIterator<'a> { | |
101 | events: ProfilerEventIterator<'a>, | |
102 | thread_stacks: Vec<Vec<Event<'a>>>, | |
103 | } | |
104 | ||
105 | impl<'a> MatchingEventsIterator<'a> { | |
106 | pub fn new(events: ProfilerEventIterator<'a>) -> MatchingEventsIterator<'a> { | |
107 | MatchingEventsIterator { | |
108 | events, | |
109 | thread_stacks: vec![], | |
110 | } | |
111 | } | |
112 | } | |
113 | ||
114 | impl<'a> Iterator for MatchingEventsIterator<'a> { | |
115 | type Item = MatchingEvent<'a>; | |
116 | ||
117 | fn next(&mut self) -> Option<MatchingEvent<'a>> { | |
118 | while let Some(event) = self.events.next() { | |
119 | match event.timestamp_kind { | |
120 | TimestampKind::Start => { | |
121 | let thread_id = event.thread_id as usize; | |
122 | if thread_id >= self.thread_stacks.len() { | |
123 | let growth_size = (thread_id + 1) - self.thread_stacks.len(); | |
e74abb32 | 124 | self.thread_stacks.append(&mut vec![vec![]; growth_size]) |
48663c56 XL |
125 | } |
126 | ||
127 | self.thread_stacks[thread_id].push(event); | |
e74abb32 | 128 | } |
48663c56 XL |
129 | TimestampKind::Instant => { |
130 | return Some(MatchingEvent::Instant(event)); | |
e74abb32 | 131 | } |
48663c56 XL |
132 | TimestampKind::End => { |
133 | let thread_id = event.thread_id as usize; | |
e74abb32 XL |
134 | let previous_event = self.thread_stacks[thread_id] |
135 | .pop() | |
136 | .expect("no previous event"); | |
137 | if previous_event.event_kind != event.event_kind | |
138 | || previous_event.label != event.label | |
139 | { | |
140 | panic!( | |
141 | "the event with label: \"{}\" went out of scope of the parent \ | |
142 | event with label: \"{}\"", | |
143 | previous_event.label, event.label | |
144 | ); | |
48663c56 XL |
145 | } |
146 | ||
147 | return Some(MatchingEvent::StartStop(previous_event, event)); | |
148 | } | |
149 | } | |
150 | } | |
151 | ||
152 | None | |
153 | } | |
154 | } |