]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_query_impl/src/profiling_support.rs
Rollup merge of #102273 - woppopo:relax_const_bound, r=fee1-dead
[rust.git] / compiler / rustc_query_impl / src / profiling_support.rs
1 use crate::QueryCtxt;
2 use measureme::{StringComponent, StringId};
3 use rustc_data_structures::fx::FxHashMap;
4 use rustc_data_structures::profiling::SelfProfiler;
5 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE};
6 use rustc_hir::definitions::DefPathData;
7 use rustc_middle::ty::{TyCtxt, WithOptConstParam};
8 use rustc_query_system::query::QueryCache;
9 use std::fmt::Debug;
10 use std::io::Write;
11
12 pub(crate) struct QueryKeyStringCache {
13     def_id_cache: FxHashMap<DefId, StringId>,
14 }
15
16 impl QueryKeyStringCache {
17     fn new() -> QueryKeyStringCache {
18         QueryKeyStringCache { def_id_cache: Default::default() }
19     }
20 }
21
22 struct QueryKeyStringBuilder<'p, 'c, 'tcx> {
23     profiler: &'p SelfProfiler,
24     tcx: TyCtxt<'tcx>,
25     string_cache: &'c mut QueryKeyStringCache,
26 }
27
28 impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> {
29     fn new(
30         profiler: &'p SelfProfiler,
31         tcx: TyCtxt<'tcx>,
32         string_cache: &'c mut QueryKeyStringCache,
33     ) -> QueryKeyStringBuilder<'p, 'c, 'tcx> {
34         QueryKeyStringBuilder { profiler, tcx, string_cache }
35     }
36
37     // The current implementation is rather crude. In the future it might be a
38     // good idea to base this on `ty::print` in order to get nicer and more
39     // efficient query keys.
40     fn def_id_to_string_id(&mut self, def_id: DefId) -> StringId {
41         if let Some(&string_id) = self.string_cache.def_id_cache.get(&def_id) {
42             return string_id;
43         }
44
45         let def_key = self.tcx.def_key(def_id);
46
47         let (parent_string_id, start_index) = match def_key.parent {
48             Some(parent_index) => {
49                 let parent_def_id = DefId { index: parent_index, krate: def_id.krate };
50
51                 (self.def_id_to_string_id(parent_def_id), 0)
52             }
53             None => (StringId::INVALID, 2),
54         };
55
56         let dis_buffer = &mut [0u8; 16];
57         let crate_name;
58         let other_name;
59         let name;
60         let dis;
61         let end_index;
62
63         match def_key.disambiguated_data.data {
64             DefPathData::CrateRoot => {
65                 crate_name = self.tcx.crate_name(def_id.krate);
66                 name = crate_name.as_str();
67                 dis = "";
68                 end_index = 3;
69             }
70             other => {
71                 other_name = other.to_string();
72                 name = other_name.as_str();
73                 if def_key.disambiguated_data.disambiguator == 0 {
74                     dis = "";
75                     end_index = 3;
76                 } else {
77                     write!(&mut dis_buffer[..], "[{}]", def_key.disambiguated_data.disambiguator)
78                         .unwrap();
79                     let end_of_dis = dis_buffer.iter().position(|&c| c == b']').unwrap();
80                     dis = std::str::from_utf8(&dis_buffer[..end_of_dis + 1]).unwrap();
81                     end_index = 4;
82                 }
83             }
84         }
85
86         let components = [
87             StringComponent::Ref(parent_string_id),
88             StringComponent::Value("::"),
89             StringComponent::Value(name),
90             StringComponent::Value(dis),
91         ];
92
93         let string_id = self.profiler.alloc_string(&components[start_index..end_index]);
94
95         self.string_cache.def_id_cache.insert(def_id, string_id);
96
97         string_id
98     }
99 }
100
101 trait IntoSelfProfilingString {
102     fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId;
103 }
104
105 // The default implementation of `IntoSelfProfilingString` just uses `Debug`
106 // which is slow and causes lots of duplication of string data.
107 // The specialized impls below take care of making the `DefId` case more
108 // efficient.
109 impl<T: Debug> IntoSelfProfilingString for T {
110     default fn to_self_profile_string(
111         &self,
112         builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
113     ) -> StringId {
114         let s = format!("{:?}", self);
115         builder.profiler.alloc_string(&s[..])
116     }
117 }
118
119 impl<T: SpecIntoSelfProfilingString> IntoSelfProfilingString for T {
120     fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId {
121         self.spec_to_self_profile_string(builder)
122     }
123 }
124
125 #[rustc_specialization_trait]
126 trait SpecIntoSelfProfilingString: Debug {
127     fn spec_to_self_profile_string(
128         &self,
129         builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
130     ) -> StringId;
131 }
132
133 impl SpecIntoSelfProfilingString for DefId {
134     fn spec_to_self_profile_string(
135         &self,
136         builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
137     ) -> StringId {
138         builder.def_id_to_string_id(*self)
139     }
140 }
141
142 impl SpecIntoSelfProfilingString for CrateNum {
143     fn spec_to_self_profile_string(
144         &self,
145         builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
146     ) -> StringId {
147         builder.def_id_to_string_id(self.as_def_id())
148     }
149 }
150
151 impl SpecIntoSelfProfilingString for DefIndex {
152     fn spec_to_self_profile_string(
153         &self,
154         builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
155     ) -> StringId {
156         builder.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: *self })
157     }
158 }
159
160 impl SpecIntoSelfProfilingString for LocalDefId {
161     fn spec_to_self_profile_string(
162         &self,
163         builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
164     ) -> StringId {
165         builder.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: self.local_def_index })
166     }
167 }
168
169 impl<T: SpecIntoSelfProfilingString> SpecIntoSelfProfilingString for WithOptConstParam<T> {
170     fn spec_to_self_profile_string(
171         &self,
172         builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
173     ) -> StringId {
174         // We print `WithOptConstParam` values as tuples to make them shorter
175         // and more readable, without losing information:
176         //
177         // "WithOptConstParam { did: foo::bar, const_param_did: Some(foo::baz) }"
178         // becomes "(foo::bar, foo::baz)" and
179         // "WithOptConstParam { did: foo::bar, const_param_did: None }"
180         // becomes "(foo::bar, _)".
181
182         let did = StringComponent::Ref(self.did.to_self_profile_string(builder));
183
184         let const_param_did = if let Some(const_param_did) = self.const_param_did {
185             let const_param_did = builder.def_id_to_string_id(const_param_did);
186             StringComponent::Ref(const_param_did)
187         } else {
188             StringComponent::Value("_")
189         };
190
191         let components = [
192             StringComponent::Value("("),
193             did,
194             StringComponent::Value(", "),
195             const_param_did,
196             StringComponent::Value(")"),
197         ];
198
199         builder.profiler.alloc_string(&components[..])
200     }
201 }
202
203 impl<T0, T1> SpecIntoSelfProfilingString for (T0, T1)
204 where
205     T0: SpecIntoSelfProfilingString,
206     T1: SpecIntoSelfProfilingString,
207 {
208     fn spec_to_self_profile_string(
209         &self,
210         builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
211     ) -> StringId {
212         let val0 = self.0.to_self_profile_string(builder);
213         let val1 = self.1.to_self_profile_string(builder);
214
215         let components = &[
216             StringComponent::Value("("),
217             StringComponent::Ref(val0),
218             StringComponent::Value(","),
219             StringComponent::Ref(val1),
220             StringComponent::Value(")"),
221         ];
222
223         builder.profiler.alloc_string(components)
224     }
225 }
226
227 /// Allocate the self-profiling query strings for a single query cache. This
228 /// method is called from `alloc_self_profile_query_strings` which knows all
229 /// the queries via macro magic.
230 pub(crate) fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
231     tcx: TyCtxt<'tcx>,
232     query_name: &'static str,
233     query_cache: &C,
234     string_cache: &mut QueryKeyStringCache,
235 ) where
236     C: QueryCache,
237     C::Key: Debug + Clone,
238 {
239     tcx.prof.with_profiler(|profiler| {
240         let event_id_builder = profiler.event_id_builder();
241
242         // Walk the entire query cache and allocate the appropriate
243         // string representations. Each cache entry is uniquely
244         // identified by its dep_node_index.
245         if profiler.query_key_recording_enabled() {
246             let mut query_string_builder = QueryKeyStringBuilder::new(profiler, tcx, string_cache);
247
248             let query_name = profiler.get_or_alloc_cached_string(query_name);
249
250             // Since building the string representation of query keys might
251             // need to invoke queries itself, we cannot keep the query caches
252             // locked while doing so. Instead we copy out the
253             // `(query_key, dep_node_index)` pairs and release the lock again.
254             let mut query_keys_and_indices = Vec::new();
255             query_cache.iter(&mut |k, _, i| query_keys_and_indices.push((k.clone(), i)));
256
257             // Now actually allocate the strings. If allocating the strings
258             // generates new entries in the query cache, we'll miss them but
259             // we don't actually care.
260             for (query_key, dep_node_index) in query_keys_and_indices {
261                 // Translate the DepNodeIndex into a QueryInvocationId
262                 let query_invocation_id = dep_node_index.into();
263
264                 // Create the string version of the query-key
265                 let query_key = query_key.to_self_profile_string(&mut query_string_builder);
266                 let event_id = event_id_builder.from_label_and_arg(query_name, query_key);
267
268                 // Doing this in bulk might be a good idea:
269                 profiler.map_query_invocation_id_to_string(
270                     query_invocation_id,
271                     event_id.to_string_id(),
272                 );
273             }
274         } else {
275             // In this branch we don't allocate query keys
276             let query_name = profiler.get_or_alloc_cached_string(query_name);
277             let event_id = event_id_builder.from_label(query_name).to_string_id();
278
279             // FIXME(eddyb) make this O(1) by using a pre-cached query name `EventId`,
280             // instead of passing the `DepNodeIndex` to `finish_with_query_invocation_id`,
281             // when recording the event in the first place.
282             let mut query_invocation_ids = Vec::new();
283             query_cache.iter(&mut |_, _, i| {
284                 query_invocation_ids.push(i.into());
285             });
286
287             profiler.bulk_map_query_invocation_id_to_single_string(
288                 query_invocation_ids.into_iter(),
289                 event_id,
290             );
291         }
292     });
293 }
294
295 /// All self-profiling events generated by the query engine use
296 /// virtual `StringId`s for their `event_id`. This method makes all
297 /// those virtual `StringId`s point to actual strings.
298 ///
299 /// If we are recording only summary data, the ids will point to
300 /// just the query names. If we are recording query keys too, we
301 /// allocate the corresponding strings here.
302 pub fn alloc_self_profile_query_strings<'tcx>(tcx: TyCtxt<'tcx>) {
303     if !tcx.prof.enabled() {
304         return;
305     }
306
307     let mut string_cache = QueryKeyStringCache::new();
308     let queries = QueryCtxt::from_tcx(tcx);
309
310     for query in &queries.queries.query_structs {
311         (query.alloc_self_profile_query_strings)(tcx, &mut string_cache);
312     }
313 }