]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_query_impl/src/profiling_support.rs
Merge tag 'debian/1.52.1+dfsg1-1_exp2' into proxmox/buster
[rustc.git] / compiler / rustc_query_impl / src / profiling_support.rs
CommitLineData
dfeec247
XL
1use measureme::{StringComponent, StringId};
2use rustc_data_structures::fx::FxHashMap;
3use rustc_data_structures::profiling::SelfProfiler;
3dfed10e 4use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
ba9703b0 5use rustc_hir::definitions::DefPathData;
6a06907d
XL
6use rustc_middle::ty::{TyCtxt, WithOptConstParam};
7use rustc_query_system::query::{QueryCache, QueryCacheStore};
dfeec247
XL
8use std::fmt::Debug;
9use std::io::Write;
10
6a06907d 11struct QueryKeyStringCache {
dfeec247
XL
12 def_id_cache: FxHashMap<DefId, StringId>,
13}
14
15impl QueryKeyStringCache {
6a06907d 16 fn new() -> QueryKeyStringCache {
dfeec247
XL
17 QueryKeyStringCache { def_id_cache: Default::default() }
18 }
19}
20
6a06907d 21struct QueryKeyStringBuilder<'p, 'c, 'tcx> {
dfeec247
XL
22 profiler: &'p SelfProfiler,
23 tcx: TyCtxt<'tcx>,
24 string_cache: &'c mut QueryKeyStringCache,
25}
26
27impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> {
6a06907d 28 fn new(
dfeec247
XL
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];
1b1a35ee
XL
56 let crate_name;
57 let other_name;
dfeec247
XL
58 let name;
59 let dis;
60 let end_index;
61
62 match def_key.disambiguated_data.data {
63 DefPathData::CrateRoot => {
1b1a35ee
XL
64 crate_name = self.tcx.original_crate_name(def_id.krate).as_str();
65 name = &*crate_name;
dfeec247
XL
66 dis = "";
67 end_index = 3;
68 }
69 other => {
1b1a35ee
XL
70 other_name = other.to_string();
71 name = other_name.as_str();
dfeec247
XL
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("::"),
3dfed10e 88 StringComponent::Value(name),
dfeec247
XL
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
6a06907d 100trait IntoSelfProfilingString {
dfeec247
XL
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.
108impl<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
f035d41b 118impl<T: SpecIntoSelfProfilingString> IntoSelfProfilingString for T {
dfeec247 119 fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId {
f035d41b
XL
120 self.spec_to_self_profile_string(builder)
121 }
122}
123
124#[rustc_specialization_trait]
6a06907d 125trait SpecIntoSelfProfilingString: Debug {
f035d41b
XL
126 fn spec_to_self_profile_string(
127 &self,
128 builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
129 ) -> StringId;
130}
131
132impl SpecIntoSelfProfilingString for DefId {
133 fn spec_to_self_profile_string(
134 &self,
135 builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
136 ) -> StringId {
dfeec247
XL
137 builder.def_id_to_string_id(*self)
138 }
139}
140
f035d41b
XL
141impl SpecIntoSelfProfilingString for CrateNum {
142 fn spec_to_self_profile_string(
143 &self,
144 builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
145 ) -> StringId {
dfeec247
XL
146 builder.def_id_to_string_id(DefId { krate: *self, index: CRATE_DEF_INDEX })
147 }
148}
149
f035d41b
XL
150impl SpecIntoSelfProfilingString for DefIndex {
151 fn spec_to_self_profile_string(
152 &self,
153 builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
154 ) -> StringId {
dfeec247
XL
155 builder.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: *self })
156 }
157}
158
3dfed10e
XL
159impl 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
168impl<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
f035d41b 202impl<T0, T1> SpecIntoSelfProfilingString for (T0, T1)
dfeec247 203where
f035d41b
XL
204 T0: SpecIntoSelfProfilingString,
205 T1: SpecIntoSelfProfilingString,
dfeec247 206{
f035d41b 207 fn spec_to_self_profile_string(
dfeec247
XL
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.
6a06907d 229fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
dfeec247
XL
230 tcx: TyCtxt<'tcx>,
231 query_name: &'static str,
6a06907d 232 query_cache: &QueryCacheStore<C>,
dfeec247
XL
233 string_cache: &mut QueryKeyStringCache,
234) where
ba9703b0
XL
235 C: QueryCache,
236 C::Key: Debug + Clone,
dfeec247
XL
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.
6a06907d 253 let query_keys_and_indices: Vec<_> = query_cache
74b04a01 254 .iter_results(|results| results.map(|(k, _, i)| (k.clone(), i)).collect());
dfeec247
XL
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
6a06907d 278 query_cache.iter_results(|results| {
74b04a01 279 let query_invocation_ids: Vec<_> = results.map(|v| v.2.into()).collect();
dfeec247 280
74b04a01
XL
281 profiler.bulk_map_query_invocation_id_to_single_string(
282 query_invocation_ids.into_iter(),
283 event_id,
284 );
285 });
dfeec247
XL
286 }
287 });
288}
6a06907d
XL
289
290/// All self-profiling events generated by the query engine use
291/// virtual `StringId`s for their `event_id`. This method makes all
292/// those virtual `StringId`s point to actual strings.
293///
294/// If we are recording only summary data, the ids will point to
295/// just the query names. If we are recording query keys too, we
296/// allocate the corresponding strings here.
297pub fn alloc_self_profile_query_strings(tcx: TyCtxt<'tcx>) {
298 if !tcx.prof.enabled() {
299 return;
300 }
301
302 let mut string_cache = QueryKeyStringCache::new();
303
304 macro_rules! alloc_once {
305 (<$tcx:tt>
306 $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident($K:ty) -> $V:ty,)*
307 ) => {
308 $({
309 alloc_self_profile_query_strings_for_query_cache(
310 tcx,
311 stringify!($name),
312 &tcx.query_caches.$name,
313 &mut string_cache,
314 );
315 })*
316 }
317 }
318
319 rustc_query_append! { [alloc_once!][<'tcx>] }
320}