]> git.proxmox.com Git - rustc.git/blame - src/librustc_middle/ty/query/profiling_support.rs
New upstream version 1.46.0~beta.2+dfsg1
[rustc.git] / src / librustc_middle / ty / query / profiling_support.rs
CommitLineData
dfeec247 1use crate::ty::context::TyCtxt;
dfeec247
XL
2use measureme::{StringComponent, StringId};
3use rustc_data_structures::fx::FxHashMap;
4use rustc_data_structures::profiling::SelfProfiler;
dfeec247 5use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
ba9703b0
XL
6use rustc_hir::definitions::DefPathData;
7use rustc_query_system::query::QueryCache;
8use rustc_query_system::query::QueryState;
dfeec247
XL
9use std::fmt::Debug;
10use std::io::Write;
11
12pub struct QueryKeyStringCache {
13 def_id_cache: FxHashMap<DefId, StringId>,
14}
15
16impl QueryKeyStringCache {
17 pub fn new() -> QueryKeyStringCache {
18 QueryKeyStringCache { def_id_cache: Default::default() }
19 }
20}
21
22pub struct QueryKeyStringBuilder<'p, 'c, 'tcx> {
23 profiler: &'p SelfProfiler,
24 tcx: TyCtxt<'tcx>,
25 string_cache: &'c mut QueryKeyStringCache,
26}
27
28impl<'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
97pub 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.
105impl<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 115impl<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]
122pub trait SpecIntoSelfProfilingString: Debug {
123 fn spec_to_self_profile_string(
124 &self,
125 builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
126 ) -> StringId;
127}
128
129impl 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
138impl 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
147impl 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 156impl<T0, T1> SpecIntoSelfProfilingString for (T0, T1)
dfeec247 157where
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 183pub(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}