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
;
9 use rustc_query_system
::query
::QueryState
;
13 pub struct QueryKeyStringCache
{
14 def_id_cache
: FxHashMap
<DefId
, StringId
>,
17 impl QueryKeyStringCache
{
18 pub fn new() -> QueryKeyStringCache
{
19 QueryKeyStringCache { def_id_cache: Default::default() }
23 pub struct QueryKeyStringBuilder
<'p
, 'c
, 'tcx
> {
24 profiler
: &'p SelfProfiler
,
26 string_cache
: &'c
mut QueryKeyStringCache
,
29 impl<'p
, 'c
, 'tcx
> QueryKeyStringBuilder
<'p
, 'c
, 'tcx
> {
31 profiler
: &'p SelfProfiler
,
33 string_cache
: &'c
mut QueryKeyStringCache
,
34 ) -> QueryKeyStringBuilder
<'p
, 'c
, 'tcx
> {
35 QueryKeyStringBuilder { profiler, tcx, string_cache }
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
) {
46 let def_key
= self.tcx
.def_key(def_id
);
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 }
;
52 (self.def_id_to_string_id(parent_def_id
), 0)
54 None
=> (StringId
::INVALID
, 2),
57 let dis_buffer
= &mut [0u8; 16];
64 match def_key
.disambiguated_data
.data
{
65 DefPathData
::CrateRoot
=> {
66 crate_name
= self.tcx
.original_crate_name(def_id
.krate
).as_str();
72 other_name
= other
.to_string();
73 name
= other_name
.as_str();
74 if def_key
.disambiguated_data
.disambiguator
== 0 {
78 write
!(&mut dis_buffer
[..], "[{}]", def_key
.disambiguated_data
.disambiguator
)
80 let end_of_dis
= dis_buffer
.iter().position(|&c
| c
== b'
]'
).unwrap();
81 dis
= std
::str::from_utf8(&dis_buffer
[..end_of_dis
+ 1]).unwrap();
88 StringComponent
::Ref(parent_string_id
),
89 StringComponent
::Value("::"),
90 StringComponent
::Value(name
),
91 StringComponent
::Value(dis
),
94 let string_id
= self.profiler
.alloc_string(&components
[start_index
..end_index
]);
96 self.string_cache
.def_id_cache
.insert(def_id
, string_id
);
102 pub trait IntoSelfProfilingString
{
103 fn to_self_profile_string(&self, builder
: &mut QueryKeyStringBuilder
<'_
, '_
, '_
>) -> StringId
;
106 // The default implementation of `IntoSelfProfilingString` just uses `Debug`
107 // which is slow and causes lots of duplication of string data.
108 // The specialized impls below take care of making the `DefId` case more
110 impl<T
: Debug
> IntoSelfProfilingString
for T
{
111 default fn to_self_profile_string(
113 builder
: &mut QueryKeyStringBuilder
<'_
, '_
, '_
>,
115 let s
= format
!("{:?}", self);
116 builder
.profiler
.alloc_string(&s
[..])
120 impl<T
: SpecIntoSelfProfilingString
> IntoSelfProfilingString
for T
{
121 fn to_self_profile_string(&self, builder
: &mut QueryKeyStringBuilder
<'_
, '_
, '_
>) -> StringId
{
122 self.spec_to_self_profile_string(builder
)
126 #[rustc_specialization_trait]
127 pub trait SpecIntoSelfProfilingString
: Debug
{
128 fn spec_to_self_profile_string(
130 builder
: &mut QueryKeyStringBuilder
<'_
, '_
, '_
>,
134 impl SpecIntoSelfProfilingString
for DefId
{
135 fn spec_to_self_profile_string(
137 builder
: &mut QueryKeyStringBuilder
<'_
, '_
, '_
>,
139 builder
.def_id_to_string_id(*self)
143 impl SpecIntoSelfProfilingString
for CrateNum
{
144 fn spec_to_self_profile_string(
146 builder
: &mut QueryKeyStringBuilder
<'_
, '_
, '_
>,
148 builder
.def_id_to_string_id(DefId { krate: *self, index: CRATE_DEF_INDEX }
)
152 impl SpecIntoSelfProfilingString
for DefIndex
{
153 fn spec_to_self_profile_string(
155 builder
: &mut QueryKeyStringBuilder
<'_
, '_
, '_
>,
157 builder
.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: *self }
)
161 impl SpecIntoSelfProfilingString
for LocalDefId
{
162 fn spec_to_self_profile_string(
164 builder
: &mut QueryKeyStringBuilder
<'_
, '_
, '_
>,
166 builder
.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: self.local_def_index }
)
170 impl<T
: SpecIntoSelfProfilingString
> SpecIntoSelfProfilingString
for WithOptConstParam
<T
> {
171 fn spec_to_self_profile_string(
173 builder
: &mut QueryKeyStringBuilder
<'_
, '_
, '_
>,
175 // We print `WithOptConstParam` values as tuples to make them shorter
176 // and more readable, without losing information:
178 // "WithOptConstParam { did: foo::bar, const_param_did: Some(foo::baz) }"
179 // becomes "(foo::bar, foo::baz)" and
180 // "WithOptConstParam { did: foo::bar, const_param_did: None }"
181 // becomes "(foo::bar, _)".
183 let did
= StringComponent
::Ref(self.did
.to_self_profile_string(builder
));
185 let const_param_did
= if let Some(const_param_did
) = self.const_param_did
{
186 let const_param_did
= builder
.def_id_to_string_id(const_param_did
);
187 StringComponent
::Ref(const_param_did
)
189 StringComponent
::Value("_")
193 StringComponent
::Value("("),
195 StringComponent
::Value(", "),
197 StringComponent
::Value(")"),
200 builder
.profiler
.alloc_string(&components
[..])
204 impl<T0
, T1
> SpecIntoSelfProfilingString
for (T0
, T1
)
206 T0
: SpecIntoSelfProfilingString
,
207 T1
: SpecIntoSelfProfilingString
,
209 fn spec_to_self_profile_string(
211 builder
: &mut QueryKeyStringBuilder
<'_
, '_
, '_
>,
213 let val0
= self.0.to_self_profile_string(builder
);
214 let val1
= self.1.to_self_profile_string(builder
);
217 StringComponent
::Value("("),
218 StringComponent
::Ref(val0
),
219 StringComponent
::Value(","),
220 StringComponent
::Ref(val1
),
221 StringComponent
::Value(")"),
224 builder
.profiler
.alloc_string(components
)
228 /// Allocate the self-profiling query strings for a single query cache. This
229 /// method is called from `alloc_self_profile_query_strings` which knows all
230 /// the queries via macro magic.
231 pub(super) fn alloc_self_profile_query_strings_for_query_cache
<'tcx
, C
>(
233 query_name
: &'
static str,
234 query_state
: &QueryState
<TyCtxt
<'tcx
>, C
>,
235 string_cache
: &mut QueryKeyStringCache
,
238 C
::Key
: Debug
+ Clone
,
240 tcx
.prof
.with_profiler(|profiler
| {
241 let event_id_builder
= profiler
.event_id_builder();
243 // Walk the entire query cache and allocate the appropriate
244 // string representations. Each cache entry is uniquely
245 // identified by its dep_node_index.
246 if profiler
.query_key_recording_enabled() {
247 let mut query_string_builder
= QueryKeyStringBuilder
::new(profiler
, tcx
, string_cache
);
249 let query_name
= profiler
.get_or_alloc_cached_string(query_name
);
251 // Since building the string representation of query keys might
252 // need to invoke queries itself, we cannot keep the query caches
253 // locked while doing so. Instead we copy out the
254 // `(query_key, dep_node_index)` pairs and release the lock again.
255 let query_keys_and_indices
: Vec
<_
> = query_state
256 .iter_results(|results
| results
.map(|(k
, _
, i
)| (k
.clone(), i
)).collect());
258 // Now actually allocate the strings. If allocating the strings
259 // generates new entries in the query cache, we'll miss them but
260 // we don't actually care.
261 for (query_key
, dep_node_index
) in query_keys_and_indices
{
262 // Translate the DepNodeIndex into a QueryInvocationId
263 let query_invocation_id
= dep_node_index
.into();
265 // Create the string version of the query-key
266 let query_key
= query_key
.to_self_profile_string(&mut query_string_builder
);
267 let event_id
= event_id_builder
.from_label_and_arg(query_name
, query_key
);
269 // Doing this in bulk might be a good idea:
270 profiler
.map_query_invocation_id_to_string(
272 event_id
.to_string_id(),
276 // In this branch we don't allocate query keys
277 let query_name
= profiler
.get_or_alloc_cached_string(query_name
);
278 let event_id
= event_id_builder
.from_label(query_name
).to_string_id();
280 query_state
.iter_results(|results
| {
281 let query_invocation_ids
: Vec
<_
> = results
.map(|v
| v
.2.into
()).collect();
283 profiler
.bulk_map_query_invocation_id_to_single_string(
284 query_invocation_ids
.into_iter(),