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