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