]>
Commit | Line | Data |
---|---|---|
2b03887a | 1 | use crate::QueryCtxt; |
dfeec247 XL |
2 | use measureme::{StringComponent, StringId}; |
3 | use rustc_data_structures::fx::FxHashMap; | |
4 | use rustc_data_structures::profiling::SelfProfiler; | |
04454e1e | 5 | use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE}; |
ba9703b0 | 6 | use rustc_hir::definitions::DefPathData; |
6a06907d | 7 | use rustc_middle::ty::{TyCtxt, WithOptConstParam}; |
5e7ed085 | 8 | use rustc_query_system::query::QueryCache; |
dfeec247 XL |
9 | use std::fmt::Debug; |
10 | use std::io::Write; | |
11 | ||
2b03887a | 12 | pub(crate) struct QueryKeyStringCache { |
dfeec247 XL |
13 | def_id_cache: FxHashMap<DefId, StringId>, |
14 | } | |
15 | ||
16 | impl QueryKeyStringCache { | |
6a06907d | 17 | fn new() -> QueryKeyStringCache { |
dfeec247 XL |
18 | QueryKeyStringCache { def_id_cache: Default::default() } |
19 | } | |
20 | } | |
21 | ||
487cf647 | 22 | struct QueryKeyStringBuilder<'p, 'tcx> { |
dfeec247 XL |
23 | profiler: &'p SelfProfiler, |
24 | tcx: TyCtxt<'tcx>, | |
487cf647 | 25 | string_cache: &'p mut QueryKeyStringCache, |
dfeec247 XL |
26 | } |
27 | ||
487cf647 | 28 | impl<'p, 'tcx> QueryKeyStringBuilder<'p, 'tcx> { |
6a06907d | 29 | fn new( |
dfeec247 XL |
30 | profiler: &'p SelfProfiler, |
31 | tcx: TyCtxt<'tcx>, | |
487cf647 FG |
32 | string_cache: &'p mut QueryKeyStringCache, |
33 | ) -> QueryKeyStringBuilder<'p, 'tcx> { | |
dfeec247 XL |
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]; | |
1b1a35ee XL |
57 | let crate_name; |
58 | let other_name; | |
dfeec247 XL |
59 | let name; |
60 | let dis; | |
61 | let end_index; | |
62 | ||
63 | match def_key.disambiguated_data.data { | |
64 | DefPathData::CrateRoot => { | |
a2a8927a XL |
65 | crate_name = self.tcx.crate_name(def_id.krate); |
66 | name = crate_name.as_str(); | |
dfeec247 XL |
67 | dis = ""; |
68 | end_index = 3; | |
69 | } | |
70 | other => { | |
1b1a35ee XL |
71 | other_name = other.to_string(); |
72 | name = other_name.as_str(); | |
dfeec247 XL |
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("::"), | |
3dfed10e | 89 | StringComponent::Value(name), |
dfeec247 XL |
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 | ||
6a06907d | 101 | trait IntoSelfProfilingString { |
487cf647 | 102 | fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId; |
dfeec247 XL |
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, | |
487cf647 | 112 | builder: &mut QueryKeyStringBuilder<'_, '_>, |
dfeec247 | 113 | ) -> StringId { |
9c376795 | 114 | let s = format!("{self:?}"); |
dfeec247 XL |
115 | builder.profiler.alloc_string(&s[..]) |
116 | } | |
117 | } | |
118 | ||
f035d41b | 119 | impl<T: SpecIntoSelfProfilingString> IntoSelfProfilingString for T { |
487cf647 | 120 | fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId { |
f035d41b XL |
121 | self.spec_to_self_profile_string(builder) |
122 | } | |
123 | } | |
124 | ||
125 | #[rustc_specialization_trait] | |
6a06907d | 126 | trait SpecIntoSelfProfilingString: Debug { |
487cf647 | 127 | fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId; |
f035d41b XL |
128 | } |
129 | ||
130 | impl SpecIntoSelfProfilingString for DefId { | |
487cf647 | 131 | fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId { |
dfeec247 XL |
132 | builder.def_id_to_string_id(*self) |
133 | } | |
134 | } | |
135 | ||
f035d41b | 136 | impl SpecIntoSelfProfilingString for CrateNum { |
487cf647 | 137 | fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId { |
04454e1e | 138 | builder.def_id_to_string_id(self.as_def_id()) |
dfeec247 XL |
139 | } |
140 | } | |
141 | ||
f035d41b | 142 | impl SpecIntoSelfProfilingString for DefIndex { |
487cf647 | 143 | fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId { |
dfeec247 XL |
144 | builder.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: *self }) |
145 | } | |
146 | } | |
147 | ||
3dfed10e | 148 | impl SpecIntoSelfProfilingString for LocalDefId { |
487cf647 | 149 | fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId { |
3dfed10e XL |
150 | builder.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: self.local_def_index }) |
151 | } | |
152 | } | |
153 | ||
154 | impl<T: SpecIntoSelfProfilingString> SpecIntoSelfProfilingString for WithOptConstParam<T> { | |
487cf647 | 155 | fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId { |
3dfed10e XL |
156 | // We print `WithOptConstParam` values as tuples to make them shorter |
157 | // and more readable, without losing information: | |
158 | // | |
159 | // "WithOptConstParam { did: foo::bar, const_param_did: Some(foo::baz) }" | |
160 | // becomes "(foo::bar, foo::baz)" and | |
161 | // "WithOptConstParam { did: foo::bar, const_param_did: None }" | |
162 | // becomes "(foo::bar, _)". | |
163 | ||
164 | let did = StringComponent::Ref(self.did.to_self_profile_string(builder)); | |
165 | ||
166 | let const_param_did = if let Some(const_param_did) = self.const_param_did { | |
167 | let const_param_did = builder.def_id_to_string_id(const_param_did); | |
168 | StringComponent::Ref(const_param_did) | |
169 | } else { | |
170 | StringComponent::Value("_") | |
171 | }; | |
172 | ||
173 | let components = [ | |
174 | StringComponent::Value("("), | |
175 | did, | |
176 | StringComponent::Value(", "), | |
177 | const_param_did, | |
178 | StringComponent::Value(")"), | |
179 | ]; | |
180 | ||
181 | builder.profiler.alloc_string(&components[..]) | |
182 | } | |
183 | } | |
184 | ||
f035d41b | 185 | impl<T0, T1> SpecIntoSelfProfilingString for (T0, T1) |
dfeec247 | 186 | where |
f035d41b XL |
187 | T0: SpecIntoSelfProfilingString, |
188 | T1: SpecIntoSelfProfilingString, | |
dfeec247 | 189 | { |
487cf647 | 190 | fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId { |
dfeec247 XL |
191 | let val0 = self.0.to_self_profile_string(builder); |
192 | let val1 = self.1.to_self_profile_string(builder); | |
193 | ||
194 | let components = &[ | |
195 | StringComponent::Value("("), | |
196 | StringComponent::Ref(val0), | |
197 | StringComponent::Value(","), | |
198 | StringComponent::Ref(val1), | |
199 | StringComponent::Value(")"), | |
200 | ]; | |
201 | ||
202 | builder.profiler.alloc_string(components) | |
203 | } | |
204 | } | |
205 | ||
206 | /// Allocate the self-profiling query strings for a single query cache. This | |
207 | /// method is called from `alloc_self_profile_query_strings` which knows all | |
208 | /// the queries via macro magic. | |
2b03887a | 209 | pub(crate) fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>( |
dfeec247 XL |
210 | tcx: TyCtxt<'tcx>, |
211 | query_name: &'static str, | |
5e7ed085 | 212 | query_cache: &C, |
dfeec247 XL |
213 | string_cache: &mut QueryKeyStringCache, |
214 | ) where | |
ba9703b0 XL |
215 | C: QueryCache, |
216 | C::Key: Debug + Clone, | |
dfeec247 XL |
217 | { |
218 | tcx.prof.with_profiler(|profiler| { | |
219 | let event_id_builder = profiler.event_id_builder(); | |
220 | ||
221 | // Walk the entire query cache and allocate the appropriate | |
222 | // string representations. Each cache entry is uniquely | |
223 | // identified by its dep_node_index. | |
224 | if profiler.query_key_recording_enabled() { | |
225 | let mut query_string_builder = QueryKeyStringBuilder::new(profiler, tcx, string_cache); | |
226 | ||
227 | let query_name = profiler.get_or_alloc_cached_string(query_name); | |
228 | ||
229 | // Since building the string representation of query keys might | |
230 | // need to invoke queries itself, we cannot keep the query caches | |
231 | // locked while doing so. Instead we copy out the | |
232 | // `(query_key, dep_node_index)` pairs and release the lock again. | |
cdc7bbd5 | 233 | let mut query_keys_and_indices = Vec::new(); |
5e7ed085 | 234 | query_cache.iter(&mut |k, _, i| query_keys_and_indices.push((k.clone(), i))); |
dfeec247 XL |
235 | |
236 | // Now actually allocate the strings. If allocating the strings | |
237 | // generates new entries in the query cache, we'll miss them but | |
238 | // we don't actually care. | |
239 | for (query_key, dep_node_index) in query_keys_and_indices { | |
240 | // Translate the DepNodeIndex into a QueryInvocationId | |
241 | let query_invocation_id = dep_node_index.into(); | |
242 | ||
243 | // Create the string version of the query-key | |
244 | let query_key = query_key.to_self_profile_string(&mut query_string_builder); | |
245 | let event_id = event_id_builder.from_label_and_arg(query_name, query_key); | |
246 | ||
247 | // Doing this in bulk might be a good idea: | |
248 | profiler.map_query_invocation_id_to_string( | |
249 | query_invocation_id, | |
250 | event_id.to_string_id(), | |
251 | ); | |
252 | } | |
253 | } else { | |
254 | // In this branch we don't allocate query keys | |
255 | let query_name = profiler.get_or_alloc_cached_string(query_name); | |
256 | let event_id = event_id_builder.from_label(query_name).to_string_id(); | |
257 | ||
923072b8 FG |
258 | // FIXME(eddyb) make this O(1) by using a pre-cached query name `EventId`, |
259 | // instead of passing the `DepNodeIndex` to `finish_with_query_invocation_id`, | |
260 | // when recording the event in the first place. | |
cdc7bbd5 | 261 | let mut query_invocation_ids = Vec::new(); |
5e7ed085 | 262 | query_cache.iter(&mut |_, _, i| { |
cdc7bbd5 | 263 | query_invocation_ids.push(i.into()); |
74b04a01 | 264 | }); |
cdc7bbd5 XL |
265 | |
266 | profiler.bulk_map_query_invocation_id_to_single_string( | |
267 | query_invocation_ids.into_iter(), | |
268 | event_id, | |
269 | ); | |
dfeec247 XL |
270 | } |
271 | }); | |
272 | } | |
6a06907d XL |
273 | |
274 | /// All self-profiling events generated by the query engine use | |
275 | /// virtual `StringId`s for their `event_id`. This method makes all | |
276 | /// those virtual `StringId`s point to actual strings. | |
277 | /// | |
278 | /// If we are recording only summary data, the ids will point to | |
279 | /// just the query names. If we are recording query keys too, we | |
280 | /// allocate the corresponding strings here. | |
9c376795 | 281 | pub fn alloc_self_profile_query_strings(tcx: TyCtxt<'_>) { |
6a06907d XL |
282 | if !tcx.prof.enabled() { |
283 | return; | |
284 | } | |
285 | ||
286 | let mut string_cache = QueryKeyStringCache::new(); | |
2b03887a | 287 | let queries = QueryCtxt::from_tcx(tcx); |
6a06907d | 288 | |
2b03887a FG |
289 | for query in &queries.queries.query_structs { |
290 | (query.alloc_self_profile_query_strings)(tcx, &mut string_cache); | |
6a06907d | 291 | } |
6a06907d | 292 | } |