]>
Commit | Line | Data |
---|---|---|
dfeec247 | 1 | use crate::ty::context::TyCtxt; |
dfeec247 XL |
2 | use measureme::{StringComponent, StringId}; |
3 | use rustc_data_structures::fx::FxHashMap; | |
4 | use rustc_data_structures::profiling::SelfProfiler; | |
dfeec247 | 5 | use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; |
ba9703b0 XL |
6 | use rustc_hir::definitions::DefPathData; |
7 | use rustc_query_system::query::QueryCache; | |
8 | use rustc_query_system::query::QueryState; | |
dfeec247 XL |
9 | use std::fmt::Debug; |
10 | use std::io::Write; | |
11 | ||
12 | pub struct QueryKeyStringCache { | |
13 | def_id_cache: FxHashMap<DefId, StringId>, | |
14 | } | |
15 | ||
16 | impl QueryKeyStringCache { | |
17 | pub fn new() -> QueryKeyStringCache { | |
18 | QueryKeyStringCache { def_id_cache: Default::default() } | |
19 | } | |
20 | } | |
21 | ||
22 | pub struct QueryKeyStringBuilder<'p, 'c, 'tcx> { | |
23 | profiler: &'p SelfProfiler, | |
24 | tcx: TyCtxt<'tcx>, | |
25 | string_cache: &'c mut QueryKeyStringCache, | |
26 | } | |
27 | ||
28 | impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> { | |
29 | pub fn new( | |
30 | profiler: &'p SelfProfiler, | |
31 | tcx: TyCtxt<'tcx>, | |
32 | string_cache: &'c mut QueryKeyStringCache, | |
33 | ) -> QueryKeyStringBuilder<'p, 'c, 'tcx> { | |
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]; | |
57 | let name; | |
58 | let dis; | |
59 | let end_index; | |
60 | ||
61 | match def_key.disambiguated_data.data { | |
62 | DefPathData::CrateRoot => { | |
63 | name = self.tcx.original_crate_name(def_id.krate).as_str(); | |
64 | dis = ""; | |
65 | end_index = 3; | |
66 | } | |
67 | other => { | |
68 | name = other.as_symbol().as_str(); | |
69 | if def_key.disambiguated_data.disambiguator == 0 { | |
70 | dis = ""; | |
71 | end_index = 3; | |
72 | } else { | |
73 | write!(&mut dis_buffer[..], "[{}]", def_key.disambiguated_data.disambiguator) | |
74 | .unwrap(); | |
75 | let end_of_dis = dis_buffer.iter().position(|&c| c == b']').unwrap(); | |
76 | dis = std::str::from_utf8(&dis_buffer[..end_of_dis + 1]).unwrap(); | |
77 | end_index = 4; | |
78 | } | |
79 | } | |
80 | } | |
81 | ||
82 | let components = [ | |
83 | StringComponent::Ref(parent_string_id), | |
84 | StringComponent::Value("::"), | |
85 | StringComponent::Value(&name[..]), | |
86 | StringComponent::Value(dis), | |
87 | ]; | |
88 | ||
89 | let string_id = self.profiler.alloc_string(&components[start_index..end_index]); | |
90 | ||
91 | self.string_cache.def_id_cache.insert(def_id, string_id); | |
92 | ||
93 | string_id | |
94 | } | |
95 | } | |
96 | ||
97 | pub trait IntoSelfProfilingString { | |
98 | fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId; | |
99 | } | |
100 | ||
101 | // The default implementation of `IntoSelfProfilingString` just uses `Debug` | |
102 | // which is slow and causes lots of duplication of string data. | |
103 | // The specialized impls below take care of making the `DefId` case more | |
104 | // efficient. | |
105 | impl<T: Debug> IntoSelfProfilingString for T { | |
106 | default fn to_self_profile_string( | |
107 | &self, | |
108 | builder: &mut QueryKeyStringBuilder<'_, '_, '_>, | |
109 | ) -> StringId { | |
110 | let s = format!("{:?}", self); | |
111 | builder.profiler.alloc_string(&s[..]) | |
112 | } | |
113 | } | |
114 | ||
f035d41b | 115 | impl<T: SpecIntoSelfProfilingString> IntoSelfProfilingString for T { |
dfeec247 | 116 | fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId { |
f035d41b XL |
117 | self.spec_to_self_profile_string(builder) |
118 | } | |
119 | } | |
120 | ||
121 | #[rustc_specialization_trait] | |
122 | pub trait SpecIntoSelfProfilingString: Debug { | |
123 | fn spec_to_self_profile_string( | |
124 | &self, | |
125 | builder: &mut QueryKeyStringBuilder<'_, '_, '_>, | |
126 | ) -> StringId; | |
127 | } | |
128 | ||
129 | impl SpecIntoSelfProfilingString for DefId { | |
130 | fn spec_to_self_profile_string( | |
131 | &self, | |
132 | builder: &mut QueryKeyStringBuilder<'_, '_, '_>, | |
133 | ) -> StringId { | |
dfeec247 XL |
134 | builder.def_id_to_string_id(*self) |
135 | } | |
136 | } | |
137 | ||
f035d41b XL |
138 | impl SpecIntoSelfProfilingString for CrateNum { |
139 | fn spec_to_self_profile_string( | |
140 | &self, | |
141 | builder: &mut QueryKeyStringBuilder<'_, '_, '_>, | |
142 | ) -> StringId { | |
dfeec247 XL |
143 | builder.def_id_to_string_id(DefId { krate: *self, index: CRATE_DEF_INDEX }) |
144 | } | |
145 | } | |
146 | ||
f035d41b XL |
147 | impl SpecIntoSelfProfilingString for DefIndex { |
148 | fn spec_to_self_profile_string( | |
149 | &self, | |
150 | builder: &mut QueryKeyStringBuilder<'_, '_, '_>, | |
151 | ) -> StringId { | |
dfeec247 XL |
152 | builder.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: *self }) |
153 | } | |
154 | } | |
155 | ||
f035d41b | 156 | impl<T0, T1> SpecIntoSelfProfilingString for (T0, T1) |
dfeec247 | 157 | where |
f035d41b XL |
158 | T0: SpecIntoSelfProfilingString, |
159 | T1: SpecIntoSelfProfilingString, | |
dfeec247 | 160 | { |
f035d41b | 161 | fn spec_to_self_profile_string( |
dfeec247 XL |
162 | &self, |
163 | builder: &mut QueryKeyStringBuilder<'_, '_, '_>, | |
164 | ) -> StringId { | |
165 | let val0 = self.0.to_self_profile_string(builder); | |
166 | let val1 = self.1.to_self_profile_string(builder); | |
167 | ||
168 | let components = &[ | |
169 | StringComponent::Value("("), | |
170 | StringComponent::Ref(val0), | |
171 | StringComponent::Value(","), | |
172 | StringComponent::Ref(val1), | |
173 | StringComponent::Value(")"), | |
174 | ]; | |
175 | ||
176 | builder.profiler.alloc_string(components) | |
177 | } | |
178 | } | |
179 | ||
180 | /// Allocate the self-profiling query strings for a single query cache. This | |
181 | /// method is called from `alloc_self_profile_query_strings` which knows all | |
182 | /// the queries via macro magic. | |
ba9703b0 | 183 | pub(super) fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>( |
dfeec247 XL |
184 | tcx: TyCtxt<'tcx>, |
185 | query_name: &'static str, | |
ba9703b0 | 186 | query_state: &QueryState<TyCtxt<'tcx>, C>, |
dfeec247 XL |
187 | string_cache: &mut QueryKeyStringCache, |
188 | ) where | |
ba9703b0 XL |
189 | C: QueryCache, |
190 | C::Key: Debug + Clone, | |
dfeec247 XL |
191 | { |
192 | tcx.prof.with_profiler(|profiler| { | |
193 | let event_id_builder = profiler.event_id_builder(); | |
194 | ||
195 | // Walk the entire query cache and allocate the appropriate | |
196 | // string representations. Each cache entry is uniquely | |
197 | // identified by its dep_node_index. | |
198 | if profiler.query_key_recording_enabled() { | |
199 | let mut query_string_builder = QueryKeyStringBuilder::new(profiler, tcx, string_cache); | |
200 | ||
201 | let query_name = profiler.get_or_alloc_cached_string(query_name); | |
202 | ||
203 | // Since building the string representation of query keys might | |
204 | // need to invoke queries itself, we cannot keep the query caches | |
205 | // locked while doing so. Instead we copy out the | |
206 | // `(query_key, dep_node_index)` pairs and release the lock again. | |
74b04a01 XL |
207 | let query_keys_and_indices: Vec<_> = query_state |
208 | .iter_results(|results| results.map(|(k, _, i)| (k.clone(), i)).collect()); | |
dfeec247 XL |
209 | |
210 | // Now actually allocate the strings. If allocating the strings | |
211 | // generates new entries in the query cache, we'll miss them but | |
212 | // we don't actually care. | |
213 | for (query_key, dep_node_index) in query_keys_and_indices { | |
214 | // Translate the DepNodeIndex into a QueryInvocationId | |
215 | let query_invocation_id = dep_node_index.into(); | |
216 | ||
217 | // Create the string version of the query-key | |
218 | let query_key = query_key.to_self_profile_string(&mut query_string_builder); | |
219 | let event_id = event_id_builder.from_label_and_arg(query_name, query_key); | |
220 | ||
221 | // Doing this in bulk might be a good idea: | |
222 | profiler.map_query_invocation_id_to_string( | |
223 | query_invocation_id, | |
224 | event_id.to_string_id(), | |
225 | ); | |
226 | } | |
227 | } else { | |
228 | // In this branch we don't allocate query keys | |
229 | let query_name = profiler.get_or_alloc_cached_string(query_name); | |
230 | let event_id = event_id_builder.from_label(query_name).to_string_id(); | |
231 | ||
74b04a01 XL |
232 | query_state.iter_results(|results| { |
233 | let query_invocation_ids: Vec<_> = results.map(|v| v.2.into()).collect(); | |
dfeec247 | 234 | |
74b04a01 XL |
235 | profiler.bulk_map_query_invocation_id_to_single_string( |
236 | query_invocation_ids.into_iter(), | |
237 | event_id, | |
238 | ); | |
239 | }); | |
dfeec247 XL |
240 | } |
241 | }); | |
242 | } |