]> git.lizzy.rs Git - rust.git/blob - src/librustc/util/profiling.rs
Rollup merge of #60590 - petertodd:2018-test-union-nonzero, r=nikomatsakis,Centril
[rust.git] / src / librustc / util / profiling.rs
1 use std::borrow::Cow;
2 use std::error::Error;
3 use std::mem::{self, Discriminant};
4 use std::process;
5 use std::thread::ThreadId;
6 use std::u32;
7
8 use crate::ty::query::QueryName;
9
10 use measureme::{StringId, TimestampKind};
11
12 /// MmapSerializatioSink is faster on macOS and Linux
13 /// but FileSerializationSink is faster on Windows
14 #[cfg(not(windows))]
15 type Profiler = measureme::Profiler<measureme::MmapSerializationSink>;
16 #[cfg(windows)]
17 type Profiler = measureme::Profiler<measureme::FileSerializationSink>;
18
19 #[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)]
20 pub enum ProfileCategory {
21     Parsing,
22     Expansion,
23     TypeChecking,
24     BorrowChecking,
25     Codegen,
26     Linking,
27     Other,
28 }
29
30 bitflags! {
31     struct EventFilter: u32 {
32         const GENERIC_ACTIVITIES = 1 << 0;
33         const QUERY_PROVIDERS    = 1 << 1;
34         const QUERY_CACHE_HITS   = 1 << 2;
35         const QUERY_BLOCKED      = 1 << 3;
36         const INCR_CACHE_LOADS   = 1 << 4;
37
38         const DEFAULT = Self::GENERIC_ACTIVITIES.bits |
39                         Self::QUERY_PROVIDERS.bits |
40                         Self::QUERY_BLOCKED.bits |
41                         Self::INCR_CACHE_LOADS.bits;
42
43         // empty() and none() aren't const-fns unfortunately
44         const NONE = 0;
45         const ALL  = !Self::NONE.bits;
46     }
47 }
48
49 const EVENT_FILTERS_BY_NAME: &[(&str, EventFilter)] = &[
50     ("none", EventFilter::NONE),
51     ("all", EventFilter::ALL),
52     ("generic-activity", EventFilter::GENERIC_ACTIVITIES),
53     ("query-provider", EventFilter::QUERY_PROVIDERS),
54     ("query-cache-hit", EventFilter::QUERY_CACHE_HITS),
55     ("query-blocked" , EventFilter::QUERY_BLOCKED),
56     ("incr-cache-load", EventFilter::INCR_CACHE_LOADS),
57 ];
58
59 fn thread_id_to_u64(tid: ThreadId) -> u64 {
60     unsafe { mem::transmute::<ThreadId, u64>(tid) }
61 }
62
63 pub struct SelfProfiler {
64     profiler: Profiler,
65     event_filter_mask: EventFilter,
66     query_event_kind: StringId,
67     generic_activity_event_kind: StringId,
68     incremental_load_result_event_kind: StringId,
69     query_blocked_event_kind: StringId,
70     query_cache_hit_event_kind: StringId,
71 }
72
73 impl SelfProfiler {
74     pub fn new(event_filters: &Option<Vec<String>>) -> Result<SelfProfiler, Box<dyn Error>> {
75         let filename = format!("pid-{}.rustc_profile", process::id());
76         let path = std::path::Path::new(&filename);
77         let profiler = Profiler::new(path)?;
78
79         let query_event_kind = profiler.alloc_string("Query");
80         let generic_activity_event_kind = profiler.alloc_string("GenericActivity");
81         let incremental_load_result_event_kind = profiler.alloc_string("IncrementalLoadResult");
82         let query_blocked_event_kind = profiler.alloc_string("QueryBlocked");
83         let query_cache_hit_event_kind = profiler.alloc_string("QueryCacheHit");
84
85         let mut event_filter_mask = EventFilter::empty();
86
87         if let Some(ref event_filters) = *event_filters {
88             let mut unknown_events = vec![];
89             for item in event_filters {
90                 if let Some(&(_, mask)) = EVENT_FILTERS_BY_NAME.iter()
91                                                                .find(|&(name, _)| name == item) {
92                     event_filter_mask |= mask;
93                 } else {
94                     unknown_events.push(item.clone());
95                 }
96             }
97
98             // Warn about any unknown event names
99             if unknown_events.len() > 0 {
100                 unknown_events.sort();
101                 unknown_events.dedup();
102
103                 warn!("Unknown self-profiler events specified: {}. Available options are: {}.",
104                     unknown_events.join(", "),
105                     EVENT_FILTERS_BY_NAME.iter()
106                                          .map(|&(name, _)| name.to_string())
107                                          .collect::<Vec<_>>()
108                                          .join(", "));
109             }
110         } else {
111             event_filter_mask = EventFilter::DEFAULT;
112         }
113
114         Ok(SelfProfiler {
115             profiler,
116             event_filter_mask,
117             query_event_kind,
118             generic_activity_event_kind,
119             incremental_load_result_event_kind,
120             query_blocked_event_kind,
121             query_cache_hit_event_kind,
122         })
123     }
124
125     fn get_query_name_string_id(query_name: QueryName) -> StringId {
126         let discriminant = unsafe {
127             mem::transmute::<Discriminant<QueryName>, u64>(mem::discriminant(&query_name))
128         };
129
130         StringId::reserved(discriminant as u32)
131     }
132
133     pub fn register_query_name(&self, query_name: QueryName) {
134         let id = SelfProfiler::get_query_name_string_id(query_name);
135         self.profiler.alloc_string_with_reserved_id(id, query_name.as_str());
136     }
137
138     #[inline]
139     pub fn start_activity(
140         &self,
141         label: impl Into<Cow<'static, str>>,
142     ) {
143         if self.event_filter_mask.contains(EventFilter::GENERIC_ACTIVITIES) {
144             self.record(&label.into(), self.generic_activity_event_kind, TimestampKind::Start);
145         }
146     }
147
148     #[inline]
149     pub fn end_activity(
150         &self,
151         label: impl Into<Cow<'static, str>>,
152     ) {
153         if self.event_filter_mask.contains(EventFilter::GENERIC_ACTIVITIES) {
154             self.record(&label.into(), self.generic_activity_event_kind, TimestampKind::End);
155         }
156     }
157
158     #[inline]
159     pub fn record_query_hit(&self, query_name: QueryName) {
160         if self.event_filter_mask.contains(EventFilter::QUERY_CACHE_HITS) {
161             self.record_query(query_name, self.query_cache_hit_event_kind, TimestampKind::Instant);
162         }
163     }
164
165     #[inline]
166     pub fn start_query(&self, query_name: QueryName) {
167         if self.event_filter_mask.contains(EventFilter::QUERY_PROVIDERS) {
168             self.record_query(query_name, self.query_event_kind, TimestampKind::Start);
169         }
170     }
171
172     #[inline]
173     pub fn end_query(&self, query_name: QueryName) {
174         if self.event_filter_mask.contains(EventFilter::QUERY_PROVIDERS) {
175             self.record_query(query_name, self.query_event_kind, TimestampKind::End);
176         }
177     }
178
179     #[inline]
180     pub fn incremental_load_result_start(&self, query_name: QueryName) {
181         if self.event_filter_mask.contains(EventFilter::INCR_CACHE_LOADS) {
182             self.record_query(
183                 query_name,
184                 self.incremental_load_result_event_kind,
185                 TimestampKind::Start
186             );
187         }
188     }
189
190     #[inline]
191     pub fn incremental_load_result_end(&self, query_name: QueryName) {
192         if self.event_filter_mask.contains(EventFilter::INCR_CACHE_LOADS) {
193             self.record_query(
194                 query_name,
195                 self.incremental_load_result_event_kind,
196                 TimestampKind::End
197             );
198         }
199     }
200
201     #[inline]
202     pub fn query_blocked_start(&self, query_name: QueryName) {
203         if self.event_filter_mask.contains(EventFilter::QUERY_BLOCKED) {
204             self.record_query(query_name, self.query_blocked_event_kind, TimestampKind::Start);
205         }
206     }
207
208     #[inline]
209     pub fn query_blocked_end(&self, query_name: QueryName) {
210         if self.event_filter_mask.contains(EventFilter::QUERY_BLOCKED) {
211             self.record_query(query_name, self.query_blocked_event_kind, TimestampKind::End);
212         }
213     }
214
215     #[inline]
216     fn record(&self, event_id: &str, event_kind: StringId, timestamp_kind: TimestampKind) {
217         let thread_id = thread_id_to_u64(std::thread::current().id());
218
219         let event_id = self.profiler.alloc_string(event_id);
220         self.profiler.record_event(event_kind, event_id, thread_id, timestamp_kind);
221     }
222
223     #[inline]
224     fn record_query(
225         &self,
226         query_name: QueryName,
227         event_kind: StringId,
228         timestamp_kind: TimestampKind,
229     ) {
230         let dep_node_name = SelfProfiler::get_query_name_string_id(query_name);
231
232         let thread_id = thread_id_to_u64(std::thread::current().id());
233
234         self.profiler.record_event(event_kind, dep_node_name, thread_id, timestamp_kind);
235     }
236 }