• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use measureme::{StringComponent, StringId};
2 use rustc_data_structures::profiling::SelfProfiler;
3 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE};
4 use rustc_hir::definitions::DefPathData;
5 use rustc_middle::query::plumbing::QueryKeyStringCache;
6 use rustc_middle::ty::TyCtxt;
7 use rustc_query_system::query::QueryCache;
8 use std::fmt::Debug;
9 use std::io::Write;
10 
11 struct QueryKeyStringBuilder<'p, 'tcx> {
12     profiler: &'p SelfProfiler,
13     tcx: TyCtxt<'tcx>,
14     string_cache: &'p mut QueryKeyStringCache,
15 }
16 
17 impl<'p, 'tcx> QueryKeyStringBuilder<'p, 'tcx> {
new( profiler: &'p SelfProfiler, tcx: TyCtxt<'tcx>, string_cache: &'p mut QueryKeyStringCache, ) -> QueryKeyStringBuilder<'p, 'tcx>18     fn new(
19         profiler: &'p SelfProfiler,
20         tcx: TyCtxt<'tcx>,
21         string_cache: &'p mut QueryKeyStringCache,
22     ) -> QueryKeyStringBuilder<'p, 'tcx> {
23         QueryKeyStringBuilder { profiler, tcx, string_cache }
24     }
25 
26     // The current implementation is rather crude. In the future it might be a
27     // good idea to base this on `ty::print` in order to get nicer and more
28     // efficient query keys.
def_id_to_string_id(&mut self, def_id: DefId) -> StringId29     fn def_id_to_string_id(&mut self, def_id: DefId) -> StringId {
30         if let Some(&string_id) = self.string_cache.def_id_cache.get(&def_id) {
31             return string_id;
32         }
33 
34         let def_key = self.tcx.def_key(def_id);
35 
36         let (parent_string_id, start_index) = match def_key.parent {
37             Some(parent_index) => {
38                 let parent_def_id = DefId { index: parent_index, krate: def_id.krate };
39 
40                 (self.def_id_to_string_id(parent_def_id), 0)
41             }
42             None => (StringId::INVALID, 2),
43         };
44 
45         let dis_buffer = &mut [0u8; 16];
46         let crate_name;
47         let other_name;
48         let name;
49         let dis;
50         let end_index;
51 
52         match def_key.disambiguated_data.data {
53             DefPathData::CrateRoot => {
54                 crate_name = self.tcx.crate_name(def_id.krate);
55                 name = crate_name.as_str();
56                 dis = "";
57                 end_index = 3;
58             }
59             other => {
60                 other_name = other.to_string();
61                 name = other_name.as_str();
62                 if def_key.disambiguated_data.disambiguator == 0 {
63                     dis = "";
64                     end_index = 3;
65                 } else {
66                     write!(&mut dis_buffer[..], "[{}]", def_key.disambiguated_data.disambiguator)
67                         .unwrap();
68                     let end_of_dis = dis_buffer.iter().position(|&c| c == b']').unwrap();
69                     dis = std::str::from_utf8(&dis_buffer[..end_of_dis + 1]).unwrap();
70                     end_index = 4;
71                 }
72             }
73         }
74 
75         let components = [
76             StringComponent::Ref(parent_string_id),
77             StringComponent::Value("::"),
78             StringComponent::Value(name),
79             StringComponent::Value(dis),
80         ];
81 
82         let string_id = self.profiler.alloc_string(&components[start_index..end_index]);
83 
84         self.string_cache.def_id_cache.insert(def_id, string_id);
85 
86         string_id
87     }
88 }
89 
90 trait IntoSelfProfilingString {
to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId91     fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId;
92 }
93 
94 // The default implementation of `IntoSelfProfilingString` just uses `Debug`
95 // which is slow and causes lots of duplication of string data.
96 // The specialized impls below take care of making the `DefId` case more
97 // efficient.
98 impl<T: Debug> IntoSelfProfilingString for T {
to_self_profile_string( &self, builder: &mut QueryKeyStringBuilder<'_, '_>, ) -> StringId99     default fn to_self_profile_string(
100         &self,
101         builder: &mut QueryKeyStringBuilder<'_, '_>,
102     ) -> StringId {
103         let s = format!("{self:?}");
104         builder.profiler.alloc_string(&s[..])
105     }
106 }
107 
108 impl<T: SpecIntoSelfProfilingString> IntoSelfProfilingString for T {
to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId109     fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId {
110         self.spec_to_self_profile_string(builder)
111     }
112 }
113 
114 #[rustc_specialization_trait]
115 trait SpecIntoSelfProfilingString: Debug {
spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId116     fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId;
117 }
118 
119 impl SpecIntoSelfProfilingString for DefId {
spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId120     fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId {
121         builder.def_id_to_string_id(*self)
122     }
123 }
124 
125 impl SpecIntoSelfProfilingString for CrateNum {
spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId126     fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId {
127         builder.def_id_to_string_id(self.as_def_id())
128     }
129 }
130 
131 impl SpecIntoSelfProfilingString for DefIndex {
spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId132     fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId {
133         builder.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: *self })
134     }
135 }
136 
137 impl SpecIntoSelfProfilingString for LocalDefId {
spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId138     fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId {
139         builder.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: self.local_def_index })
140     }
141 }
142 
143 impl<T0, T1> SpecIntoSelfProfilingString for (T0, T1)
144 where
145     T0: SpecIntoSelfProfilingString,
146     T1: SpecIntoSelfProfilingString,
147 {
spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId148     fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId {
149         let val0 = self.0.to_self_profile_string(builder);
150         let val1 = self.1.to_self_profile_string(builder);
151 
152         let components = &[
153             StringComponent::Value("("),
154             StringComponent::Ref(val0),
155             StringComponent::Value(","),
156             StringComponent::Ref(val1),
157             StringComponent::Value(")"),
158         ];
159 
160         builder.profiler.alloc_string(components)
161     }
162 }
163 
164 /// Allocate the self-profiling query strings for a single query cache. This
165 /// method is called from `alloc_self_profile_query_strings` which knows all
166 /// the queries via macro magic.
alloc_self_profile_query_strings_for_query_cache<'tcx, C>( tcx: TyCtxt<'tcx>, query_name: &'static str, query_cache: &C, string_cache: &mut QueryKeyStringCache, ) where C: QueryCache, C::Key: Debug + Clone,167 pub(crate) fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
168     tcx: TyCtxt<'tcx>,
169     query_name: &'static str,
170     query_cache: &C,
171     string_cache: &mut QueryKeyStringCache,
172 ) where
173     C: QueryCache,
174     C::Key: Debug + Clone,
175 {
176     tcx.prof.with_profiler(|profiler| {
177         let event_id_builder = profiler.event_id_builder();
178 
179         // Walk the entire query cache and allocate the appropriate
180         // string representations. Each cache entry is uniquely
181         // identified by its dep_node_index.
182         if profiler.query_key_recording_enabled() {
183             let mut query_string_builder = QueryKeyStringBuilder::new(profiler, tcx, string_cache);
184 
185             let query_name = profiler.get_or_alloc_cached_string(query_name);
186 
187             // Since building the string representation of query keys might
188             // need to invoke queries itself, we cannot keep the query caches
189             // locked while doing so. Instead we copy out the
190             // `(query_key, dep_node_index)` pairs and release the lock again.
191             let mut query_keys_and_indices = Vec::new();
192             query_cache.iter(&mut |k, _, i| query_keys_and_indices.push((*k, i)));
193 
194             // Now actually allocate the strings. If allocating the strings
195             // generates new entries in the query cache, we'll miss them but
196             // we don't actually care.
197             for (query_key, dep_node_index) in query_keys_and_indices {
198                 // Translate the DepNodeIndex into a QueryInvocationId
199                 let query_invocation_id = dep_node_index.into();
200 
201                 // Create the string version of the query-key
202                 let query_key = query_key.to_self_profile_string(&mut query_string_builder);
203                 let event_id = event_id_builder.from_label_and_arg(query_name, query_key);
204 
205                 // Doing this in bulk might be a good idea:
206                 profiler.map_query_invocation_id_to_string(
207                     query_invocation_id,
208                     event_id.to_string_id(),
209                 );
210             }
211         } else {
212             // In this branch we don't allocate query keys
213             let query_name = profiler.get_or_alloc_cached_string(query_name);
214             let event_id = event_id_builder.from_label(query_name).to_string_id();
215 
216             // FIXME(eddyb) make this O(1) by using a pre-cached query name `EventId`,
217             // instead of passing the `DepNodeIndex` to `finish_with_query_invocation_id`,
218             // when recording the event in the first place.
219             let mut query_invocation_ids = Vec::new();
220             query_cache.iter(&mut |_, _, i| {
221                 query_invocation_ids.push(i.into());
222             });
223 
224             profiler.bulk_map_query_invocation_id_to_single_string(
225                 query_invocation_ids.into_iter(),
226                 event_id,
227             );
228         }
229     });
230 }
231 
232 /// All self-profiling events generated by the query engine use
233 /// virtual `StringId`s for their `event_id`. This method makes all
234 /// those virtual `StringId`s point to actual strings.
235 ///
236 /// If we are recording only summary data, the ids will point to
237 /// just the query names. If we are recording query keys too, we
238 /// allocate the corresponding strings here.
alloc_self_profile_query_strings(tcx: TyCtxt<'_>)239 pub fn alloc_self_profile_query_strings(tcx: TyCtxt<'_>) {
240     if !tcx.prof.enabled() {
241         return;
242     }
243 
244     let mut string_cache = QueryKeyStringCache::new();
245 
246     for alloc in super::ALLOC_SELF_PROFILE_QUERY_STRINGS.iter() {
247         alloc(tcx, &mut string_cache)
248     }
249 }
250