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