]>
Commit | Line | Data |
---|---|---|
dfeec247 XL |
1 | use measureme::{StringComponent, StringId}; |
2 | use rustc_data_structures::fx::FxHashMap; | |
3 | use rustc_data_structures::profiling::SelfProfiler; | |
04454e1e | 4 | use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE}; |
ba9703b0 | 5 | use rustc_hir::definitions::DefPathData; |
6a06907d | 6 | use rustc_middle::ty::{TyCtxt, WithOptConstParam}; |
5e7ed085 | 7 | use rustc_query_system::query::QueryCache; |
dfeec247 XL |
8 | use std::fmt::Debug; |
9 | use std::io::Write; | |
10 | ||
6a06907d | 11 | struct QueryKeyStringCache { |
dfeec247 XL |
12 | def_id_cache: FxHashMap<DefId, StringId>, |
13 | } | |
14 | ||
15 | impl QueryKeyStringCache { | |
6a06907d | 16 | fn new() -> QueryKeyStringCache { |
dfeec247 XL |
17 | QueryKeyStringCache { def_id_cache: Default::default() } |
18 | } | |
19 | } | |
20 | ||
6a06907d | 21 | struct QueryKeyStringBuilder<'p, 'c, 'tcx> { |
dfeec247 XL |
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> { | |
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 => { | |
a2a8927a XL |
64 | crate_name = self.tcx.crate_name(def_id.krate); |
65 | name = crate_name.as_str(); | |
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 | 100 | trait 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. | |
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 | ||
f035d41b | 118 | impl<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 | 125 | trait SpecIntoSelfProfilingString: Debug { |
f035d41b XL |
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 { | |
dfeec247 XL |
137 | builder.def_id_to_string_id(*self) |
138 | } | |
139 | } | |
140 | ||
f035d41b XL |
141 | impl SpecIntoSelfProfilingString for CrateNum { |
142 | fn spec_to_self_profile_string( | |
143 | &self, | |
144 | builder: &mut QueryKeyStringBuilder<'_, '_, '_>, | |
145 | ) -> StringId { | |
04454e1e | 146 | builder.def_id_to_string_id(self.as_def_id()) |
dfeec247 XL |
147 | } |
148 | } | |
149 | ||
f035d41b XL |
150 | impl 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 |
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 | ||
f035d41b | 202 | impl<T0, T1> SpecIntoSelfProfilingString for (T0, T1) |
dfeec247 | 203 | where |
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 | 229 | fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>( |
dfeec247 XL |
230 | tcx: TyCtxt<'tcx>, |
231 | query_name: &'static str, | |
5e7ed085 | 232 | query_cache: &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. | |
cdc7bbd5 | 253 | let mut query_keys_and_indices = Vec::new(); |
5e7ed085 | 254 | query_cache.iter(&mut |k, _, i| query_keys_and_indices.push((k.clone(), i))); |
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 | ||
923072b8 FG |
278 | // FIXME(eddyb) make this O(1) by using a pre-cached query name `EventId`, |
279 | // instead of passing the `DepNodeIndex` to `finish_with_query_invocation_id`, | |
280 | // when recording the event in the first place. | |
cdc7bbd5 | 281 | let mut query_invocation_ids = Vec::new(); |
5e7ed085 | 282 | query_cache.iter(&mut |_, _, i| { |
cdc7bbd5 | 283 | query_invocation_ids.push(i.into()); |
74b04a01 | 284 | }); |
cdc7bbd5 XL |
285 | |
286 | profiler.bulk_map_query_invocation_id_to_single_string( | |
287 | query_invocation_ids.into_iter(), | |
288 | event_id, | |
289 | ); | |
dfeec247 XL |
290 | } |
291 | }); | |
292 | } | |
6a06907d XL |
293 | |
294 | /// All self-profiling events generated by the query engine use | |
295 | /// virtual `StringId`s for their `event_id`. This method makes all | |
296 | /// those virtual `StringId`s point to actual strings. | |
297 | /// | |
298 | /// If we are recording only summary data, the ids will point to | |
299 | /// just the query names. If we are recording query keys too, we | |
300 | /// allocate the corresponding strings here. | |
a2a8927a | 301 | pub fn alloc_self_profile_query_strings(tcx: TyCtxt<'_>) { |
6a06907d XL |
302 | if !tcx.prof.enabled() { |
303 | return; | |
304 | } | |
305 | ||
306 | let mut string_cache = QueryKeyStringCache::new(); | |
307 | ||
308 | macro_rules! alloc_once { | |
f2b60f7d FG |
309 | ( |
310 | $($(#[$attr:meta])* | |
311 | [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => { | |
312 | $( | |
6a06907d XL |
313 | alloc_self_profile_query_strings_for_query_cache( |
314 | tcx, | |
315 | stringify!($name), | |
316 | &tcx.query_caches.$name, | |
317 | &mut string_cache, | |
318 | ); | |
f2b60f7d | 319 | )+ |
6a06907d XL |
320 | } |
321 | } | |
322 | ||
f2b60f7d | 323 | rustc_query_append! { alloc_once! } |
6a06907d | 324 | } |