]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/query/profiling_support.rs
256bd86a3de383fb3b8b443cb8c68cda7f0f0ade
[rust.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::caches::QueryCache;
4 use crate::ty::query::plumbing::QueryStateImpl;
5 use measureme::{StringComponent, StringId};
6 use rustc_data_structures::fx::FxHashMap;
7 use rustc_data_structures::profiling::SelfProfiler;
8 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
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
115 impl IntoSelfProfilingString for DefId {
116     fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId {
117         builder.def_id_to_string_id(*self)
118     }
119 }
120
121 impl IntoSelfProfilingString for CrateNum {
122     fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId {
123         builder.def_id_to_string_id(DefId { krate: *self, index: CRATE_DEF_INDEX })
124     }
125 }
126
127 impl IntoSelfProfilingString for DefIndex {
128     fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId {
129         builder.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: *self })
130     }
131 }
132
133 impl<T0, T1> IntoSelfProfilingString for (T0, T1)
134 where
135     T0: IntoSelfProfilingString + Debug,
136     T1: IntoSelfProfilingString + Debug,
137 {
138     default fn to_self_profile_string(
139         &self,
140         builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
141     ) -> StringId {
142         let val0 = self.0.to_self_profile_string(builder);
143         let val1 = self.1.to_self_profile_string(builder);
144
145         let components = &[
146             StringComponent::Value("("),
147             StringComponent::Ref(val0),
148             StringComponent::Value(","),
149             StringComponent::Ref(val1),
150             StringComponent::Value(")"),
151         ];
152
153         builder.profiler.alloc_string(components)
154     }
155 }
156
157 /// Allocate the self-profiling query strings for a single query cache. This
158 /// method is called from `alloc_self_profile_query_strings` which knows all
159 /// the queries via macro magic.
160 pub(super) fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
161     tcx: TyCtxt<'tcx>,
162     query_name: &'static str,
163     query_state: &QueryStateImpl<'tcx, C>,
164     string_cache: &mut QueryKeyStringCache,
165 ) where
166     C: QueryCache,
167     C::Key: Debug + Clone,
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: Vec<_> = query_state
185                 .iter_results(|results| results.map(|(k, _, i)| (k.clone(), i)).collect());
186
187             // Now actually allocate the strings. If allocating the strings
188             // generates new entries in the query cache, we'll miss them but
189             // we don't actually care.
190             for (query_key, dep_node_index) in query_keys_and_indices {
191                 // Translate the DepNodeIndex into a QueryInvocationId
192                 let query_invocation_id = dep_node_index.into();
193
194                 // Create the string version of the query-key
195                 let query_key = query_key.to_self_profile_string(&mut query_string_builder);
196                 let event_id = event_id_builder.from_label_and_arg(query_name, query_key);
197
198                 // Doing this in bulk might be a good idea:
199                 profiler.map_query_invocation_id_to_string(
200                     query_invocation_id,
201                     event_id.to_string_id(),
202                 );
203             }
204         } else {
205             // In this branch we don't allocate query keys
206             let query_name = profiler.get_or_alloc_cached_string(query_name);
207             let event_id = event_id_builder.from_label(query_name).to_string_id();
208
209             query_state.iter_results(|results| {
210                 let query_invocation_ids: Vec<_> = results.map(|v| v.2.into()).collect();
211
212                 profiler.bulk_map_query_invocation_id_to_single_string(
213                     query_invocation_ids.into_iter(),
214                     event_id,
215                 );
216             });
217         }
218     });
219 }