]> git.proxmox.com Git - rustc.git/blob - vendor/measureme/src/profiling_data.rs
New upstream version 1.40.0+dfsg1
[rustc.git] / vendor / measureme / src / profiling_data.rs
1 use crate::event::Event;
2 use crate::file_header::FILE_HEADER_SIZE;
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 =
21 fs::read(paths.string_index_file).expect("couldn't read string_index file");
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>> {
59 let event_start_addr = FILE_HEADER_SIZE + 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(&mut vec![vec![]; growth_size])
125 }
126
127 self.thread_stacks[thread_id].push(event);
128 }
129 TimestampKind::Instant => {
130 return Some(MatchingEvent::Instant(event));
131 }
132 TimestampKind::End => {
133 let thread_id = event.thread_id as usize;
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 );
145 }
146
147 return Some(MatchingEvent::StartStop(previous_event, event));
148 }
149 }
150 }
151
152 None
153 }
154 }