]>
Commit | Line | Data |
---|---|---|
48663c56 XL |
1 | use crate::file_header::FILE_HEADER_SIZE; |
2 | use crate::event::Event; | |
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"); | |
20 | let index_data = fs::read(paths.string_index_file).expect("couldn't read string_index file"); | |
21 | let event_data = fs::read(paths.events_file).expect("couldn't read events file"); | |
22 | ||
23 | let string_table = StringTable::new(string_data, index_data)?; | |
24 | ||
25 | Ok(ProfilingData { | |
26 | string_table, | |
27 | event_data, | |
28 | }) | |
29 | } | |
30 | ||
31 | pub fn iter(&self) -> impl Iterator<Item = Event<'_>> { | |
32 | ProfilerEventIterator::new(&self) | |
33 | } | |
34 | ||
35 | pub fn iter_matching_events(&self) -> impl Iterator<Item = MatchingEvent<'_>> { | |
36 | MatchingEventsIterator::new(ProfilerEventIterator::new(&self)) | |
37 | } | |
38 | } | |
39 | ||
40 | struct ProfilerEventIterator<'a> { | |
41 | data: &'a ProfilingData, | |
42 | curr_event_idx: usize, | |
43 | } | |
44 | ||
45 | impl<'a> ProfilerEventIterator<'a> { | |
46 | pub fn new(data: &'a ProfilingData) -> ProfilerEventIterator<'a> { | |
47 | ProfilerEventIterator { | |
48 | data, | |
49 | curr_event_idx: 0, | |
50 | } | |
51 | } | |
52 | } | |
53 | ||
54 | impl<'a> Iterator for ProfilerEventIterator<'a> { | |
55 | type Item = Event<'a>; | |
56 | ||
57 | fn next(&mut self) -> Option<Event<'a>> { | |
58 | let event_start_addr = FILE_HEADER_SIZE + | |
59 | self.curr_event_idx * mem::size_of::<RawEvent>(); | |
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, | |
73 | std::mem::size_of::<RawEvent>() | |
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(); | |
124 | self.thread_stacks.append( | |
125 | &mut vec![vec![]; growth_size] | |
126 | ) | |
127 | } | |
128 | ||
129 | self.thread_stacks[thread_id].push(event); | |
130 | }, | |
131 | TimestampKind::Instant => { | |
132 | return Some(MatchingEvent::Instant(event)); | |
133 | }, | |
134 | TimestampKind::End => { | |
135 | let thread_id = event.thread_id as usize; | |
136 | let previous_event = self.thread_stacks[thread_id].pop().expect("no previous event"); | |
137 | if previous_event.event_kind != event.event_kind || | |
138 | previous_event.label != event.label { | |
139 | panic!("previous event on thread wasn't the start event"); | |
140 | } | |
141 | ||
142 | return Some(MatchingEvent::StartStop(previous_event, event)); | |
143 | } | |
144 | } | |
145 | } | |
146 | ||
147 | None | |
148 | } | |
149 | } |