]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_middle/src/ty/query/profiling_support.rs
New upstream version 1.51.0+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, QueryContext, QueryState};
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 crate_name;
58 let other_name;
59 let name;
60 let dis;
61 let end_index;
62
63 match def_key.disambiguated_data.data {
64 DefPathData::CrateRoot => {
65 crate_name = self.tcx.original_crate_name(def_id.krate).as_str();
66 name = &*crate_name;
67 dis = "";
68 end_index = 3;
69 }
70 other => {
71 other_name = other.to_string();
72 name = other_name.as_str();
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("::"),
89 StringComponent::Value(name),
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
101 pub trait IntoSelfProfilingString {
102 fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId;
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,
112 builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
113 ) -> StringId {
114 let s = format!("{:?}", self);
115 builder.profiler.alloc_string(&s[..])
116 }
117 }
118
119 impl<T: SpecIntoSelfProfilingString> IntoSelfProfilingString for T {
120 fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId {
121 self.spec_to_self_profile_string(builder)
122 }
123 }
124
125 #[rustc_specialization_trait]
126 pub trait SpecIntoSelfProfilingString: Debug {
127 fn spec_to_self_profile_string(
128 &self,
129 builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
130 ) -> StringId;
131 }
132
133 impl SpecIntoSelfProfilingString for DefId {
134 fn spec_to_self_profile_string(
135 &self,
136 builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
137 ) -> StringId {
138 builder.def_id_to_string_id(*self)
139 }
140 }
141
142 impl SpecIntoSelfProfilingString for CrateNum {
143 fn spec_to_self_profile_string(
144 &self,
145 builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
146 ) -> StringId {
147 builder.def_id_to_string_id(DefId { krate: *self, index: CRATE_DEF_INDEX })
148 }
149 }
150
151 impl SpecIntoSelfProfilingString for DefIndex {
152 fn spec_to_self_profile_string(
153 &self,
154 builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
155 ) -> StringId {
156 builder.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: *self })
157 }
158 }
159
160 impl SpecIntoSelfProfilingString for LocalDefId {
161 fn spec_to_self_profile_string(
162 &self,
163 builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
164 ) -> StringId {
165 builder.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: self.local_def_index })
166 }
167 }
168
169 impl<T: SpecIntoSelfProfilingString> SpecIntoSelfProfilingString for WithOptConstParam<T> {
170 fn spec_to_self_profile_string(
171 &self,
172 builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
173 ) -> StringId {
174 // We print `WithOptConstParam` values as tuples to make them shorter
175 // and more readable, without losing information:
176 //
177 // "WithOptConstParam { did: foo::bar, const_param_did: Some(foo::baz) }"
178 // becomes "(foo::bar, foo::baz)" and
179 // "WithOptConstParam { did: foo::bar, const_param_did: None }"
180 // becomes "(foo::bar, _)".
181
182 let did = StringComponent::Ref(self.did.to_self_profile_string(builder));
183
184 let const_param_did = if let Some(const_param_did) = self.const_param_did {
185 let const_param_did = builder.def_id_to_string_id(const_param_did);
186 StringComponent::Ref(const_param_did)
187 } else {
188 StringComponent::Value("_")
189 };
190
191 let components = [
192 StringComponent::Value("("),
193 did,
194 StringComponent::Value(", "),
195 const_param_did,
196 StringComponent::Value(")"),
197 ];
198
199 builder.profiler.alloc_string(&components[..])
200 }
201 }
202
203 impl<T0, T1> SpecIntoSelfProfilingString for (T0, T1)
204 where
205 T0: SpecIntoSelfProfilingString,
206 T1: SpecIntoSelfProfilingString,
207 {
208 fn spec_to_self_profile_string(
209 &self,
210 builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
211 ) -> StringId {
212 let val0 = self.0.to_self_profile_string(builder);
213 let val1 = self.1.to_self_profile_string(builder);
214
215 let components = &[
216 StringComponent::Value("("),
217 StringComponent::Ref(val0),
218 StringComponent::Value(","),
219 StringComponent::Ref(val1),
220 StringComponent::Value(")"),
221 ];
222
223 builder.profiler.alloc_string(components)
224 }
225 }
226
227 /// Allocate the self-profiling query strings for a single query cache. This
228 /// method is called from `alloc_self_profile_query_strings` which knows all
229 /// the queries via macro magic.
230 pub(super) fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
231 tcx: TyCtxt<'tcx>,
232 query_name: &'static str,
233 query_state: &QueryState<crate::dep_graph::DepKind, <TyCtxt<'tcx> as QueryContext>::Query, C>,
234 string_cache: &mut QueryKeyStringCache,
235 ) where
236 C: QueryCache,
237 C::Key: Debug + Clone,
238 {
239 tcx.prof.with_profiler(|profiler| {
240 let event_id_builder = profiler.event_id_builder();
241
242 // Walk the entire query cache and allocate the appropriate
243 // string representations. Each cache entry is uniquely
244 // identified by its dep_node_index.
245 if profiler.query_key_recording_enabled() {
246 let mut query_string_builder = QueryKeyStringBuilder::new(profiler, tcx, string_cache);
247
248 let query_name = profiler.get_or_alloc_cached_string(query_name);
249
250 // Since building the string representation of query keys might
251 // need to invoke queries itself, we cannot keep the query caches
252 // locked while doing so. Instead we copy out the
253 // `(query_key, dep_node_index)` pairs and release the lock again.
254 let query_keys_and_indices: Vec<_> = query_state
255 .iter_results(|results| results.map(|(k, _, i)| (k.clone(), i)).collect());
256
257 // Now actually allocate the strings. If allocating the strings
258 // generates new entries in the query cache, we'll miss them but
259 // we don't actually care.
260 for (query_key, dep_node_index) in query_keys_and_indices {
261 // Translate the DepNodeIndex into a QueryInvocationId
262 let query_invocation_id = dep_node_index.into();
263
264 // Create the string version of the query-key
265 let query_key = query_key.to_self_profile_string(&mut query_string_builder);
266 let event_id = event_id_builder.from_label_and_arg(query_name, query_key);
267
268 // Doing this in bulk might be a good idea:
269 profiler.map_query_invocation_id_to_string(
270 query_invocation_id,
271 event_id.to_string_id(),
272 );
273 }
274 } else {
275 // In this branch we don't allocate query keys
276 let query_name = profiler.get_or_alloc_cached_string(query_name);
277 let event_id = event_id_builder.from_label(query_name).to_string_id();
278
279 query_state.iter_results(|results| {
280 let query_invocation_ids: Vec<_> = results.map(|v| v.2.into()).collect();
281
282 profiler.bulk_map_query_invocation_id_to_single_string(
283 query_invocation_ids.into_iter(),
284 event_id,
285 );
286 });
287 }
288 });
289 }