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, QueryContext, QueryState}
;
12 pub struct QueryKeyStringCache
{
13 def_id_cache
: FxHashMap
<DefId
, StringId
>,
16 impl QueryKeyStringCache
{
17 pub fn new() -> QueryKeyStringCache
{
18 QueryKeyStringCache { def_id_cache: Default::default() }
22 pub struct QueryKeyStringBuilder
<'p
, 'c
, 'tcx
> {
23 profiler
: &'p SelfProfiler
,
25 string_cache
: &'c
mut QueryKeyStringCache
,
28 impl<'p
, 'c
, 'tcx
> QueryKeyStringBuilder
<'p
, 'c
, 'tcx
> {
30 profiler
: &'p SelfProfiler
,
32 string_cache
: &'c
mut QueryKeyStringCache
,
33 ) -> QueryKeyStringBuilder
<'p
, 'c
, 'tcx
> {
34 QueryKeyStringBuilder { profiler, tcx, string_cache }
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
) {
45 let def_key
= self.tcx
.def_key(def_id
);
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 }
;
51 (self.def_id_to_string_id(parent_def_id
), 0)
53 None
=> (StringId
::INVALID
, 2),
56 let dis_buffer
= &mut [0u8; 16];
63 match def_key
.disambiguated_data
.data
{
64 DefPathData
::CrateRoot
=> {
65 crate_name
= self.tcx
.original_crate_name(def_id
.krate
).as_str();
71 other_name
= other
.to_string();
72 name
= other_name
.as_str();
73 if def_key
.disambiguated_data
.disambiguator
== 0 {
77 write
!(&mut dis_buffer
[..], "[{}]", def_key
.disambiguated_data
.disambiguator
)
79 let end_of_dis
= dis_buffer
.iter().position(|&c
| c
== b'
]'
).unwrap();
80 dis
= std
::str::from_utf8(&dis_buffer
[..end_of_dis
+ 1]).unwrap();
87 StringComponent
::Ref(parent_string_id
),
88 StringComponent
::Value("::"),
89 StringComponent
::Value(name
),
90 StringComponent
::Value(dis
),
93 let string_id
= self.profiler
.alloc_string(&components
[start_index
..end_index
]);
95 self.string_cache
.def_id_cache
.insert(def_id
, string_id
);
101 pub trait IntoSelfProfilingString
{
102 fn to_self_profile_string(&self, builder
: &mut QueryKeyStringBuilder
<'_
, '_
, '_
>) -> StringId
;
105 // The default implementation of `IntoSelfProfilingString` just uses `Debug`
106 // which is slow and causes lots of duplication of string data.
107 // The specialized impls below take care of making the `DefId` case more
109 impl<T
: Debug
> IntoSelfProfilingString
for T
{
110 default fn to_self_profile_string(
112 builder
: &mut QueryKeyStringBuilder
<'_
, '_
, '_
>,
114 let s
= format
!("{:?}", self);
115 builder
.profiler
.alloc_string(&s
[..])
119 impl<T
: SpecIntoSelfProfilingString
> IntoSelfProfilingString
for T
{
120 fn to_self_profile_string(&self, builder
: &mut QueryKeyStringBuilder
<'_
, '_
, '_
>) -> StringId
{
121 self.spec_to_self_profile_string(builder
)
125 #[rustc_specialization_trait]
126 pub trait SpecIntoSelfProfilingString
: Debug
{
127 fn spec_to_self_profile_string(
129 builder
: &mut QueryKeyStringBuilder
<'_
, '_
, '_
>,
133 impl SpecIntoSelfProfilingString
for DefId
{
134 fn spec_to_self_profile_string(
136 builder
: &mut QueryKeyStringBuilder
<'_
, '_
, '_
>,
138 builder
.def_id_to_string_id(*self)
142 impl SpecIntoSelfProfilingString
for CrateNum
{
143 fn spec_to_self_profile_string(
145 builder
: &mut QueryKeyStringBuilder
<'_
, '_
, '_
>,
147 builder
.def_id_to_string_id(DefId { krate: *self, index: CRATE_DEF_INDEX }
)
151 impl SpecIntoSelfProfilingString
for DefIndex
{
152 fn spec_to_self_profile_string(
154 builder
: &mut QueryKeyStringBuilder
<'_
, '_
, '_
>,
156 builder
.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: *self }
)
160 impl SpecIntoSelfProfilingString
for LocalDefId
{
161 fn spec_to_self_profile_string(
163 builder
: &mut QueryKeyStringBuilder
<'_
, '_
, '_
>,
165 builder
.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: self.local_def_index }
)
169 impl<T
: SpecIntoSelfProfilingString
> SpecIntoSelfProfilingString
for WithOptConstParam
<T
> {
170 fn spec_to_self_profile_string(
172 builder
: &mut QueryKeyStringBuilder
<'_
, '_
, '_
>,
174 // We print `WithOptConstParam` values as tuples to make them shorter
175 // and more readable, without losing information:
177 // "WithOptConstParam { did: foo::bar, const_param_did: Some(foo::baz) }"
178 // becomes "(foo::bar, foo::baz)" and
179 // "WithOptConstParam { did: foo::bar, const_param_did: None }"
180 // becomes "(foo::bar, _)".
182 let did
= StringComponent
::Ref(self.did
.to_self_profile_string(builder
));
184 let const_param_did
= if let Some(const_param_did
) = self.const_param_did
{
185 let const_param_did
= builder
.def_id_to_string_id(const_param_did
);
186 StringComponent
::Ref(const_param_did
)
188 StringComponent
::Value("_")
192 StringComponent
::Value("("),
194 StringComponent
::Value(", "),
196 StringComponent
::Value(")"),
199 builder
.profiler
.alloc_string(&components
[..])
203 impl<T0
, T1
> SpecIntoSelfProfilingString
for (T0
, T1
)
205 T0
: SpecIntoSelfProfilingString
,
206 T1
: SpecIntoSelfProfilingString
,
208 fn spec_to_self_profile_string(
210 builder
: &mut QueryKeyStringBuilder
<'_
, '_
, '_
>,
212 let val0
= self.0.to_self_profile_string(builder
);
213 let val1
= self.1.to_self_profile_string(builder
);
216 StringComponent
::Value("("),
217 StringComponent
::Ref(val0
),
218 StringComponent
::Value(","),
219 StringComponent
::Ref(val1
),
220 StringComponent
::Value(")"),
223 builder
.profiler
.alloc_string(components
)
227 /// Allocate the self-profiling query strings for a single query cache. This
228 /// method is called from `alloc_self_profile_query_strings` which knows all
229 /// the queries via macro magic.
230 pub(super) fn alloc_self_profile_query_strings_for_query_cache
<'tcx
, C
>(
232 query_name
: &'
static str,
233 query_state
: &QueryState
<crate::dep_graph
::DepKind
, <TyCtxt
<'tcx
> as QueryContext
>::Query
, C
>,
234 string_cache
: &mut QueryKeyStringCache
,
237 C
::Key
: Debug
+ Clone
,
239 tcx
.prof
.with_profiler(|profiler
| {
240 let event_id_builder
= profiler
.event_id_builder();
242 // Walk the entire query cache and allocate the appropriate
243 // string representations. Each cache entry is uniquely
244 // identified by its dep_node_index.
245 if profiler
.query_key_recording_enabled() {
246 let mut query_string_builder
= QueryKeyStringBuilder
::new(profiler
, tcx
, string_cache
);
248 let query_name
= profiler
.get_or_alloc_cached_string(query_name
);
250 // Since building the string representation of query keys might
251 // need to invoke queries itself, we cannot keep the query caches
252 // locked while doing so. Instead we copy out the
253 // `(query_key, dep_node_index)` pairs and release the lock again.
254 let query_keys_and_indices
: Vec
<_
> = query_state
255 .iter_results(|results
| results
.map(|(k
, _
, i
)| (k
.clone(), i
)).collect());
257 // Now actually allocate the strings. If allocating the strings
258 // generates new entries in the query cache, we'll miss them but
259 // we don't actually care.
260 for (query_key
, dep_node_index
) in query_keys_and_indices
{
261 // Translate the DepNodeIndex into a QueryInvocationId
262 let query_invocation_id
= dep_node_index
.into();
264 // Create the string version of the query-key
265 let query_key
= query_key
.to_self_profile_string(&mut query_string_builder
);
266 let event_id
= event_id_builder
.from_label_and_arg(query_name
, query_key
);
268 // Doing this in bulk might be a good idea:
269 profiler
.map_query_invocation_id_to_string(
271 event_id
.to_string_id(),
275 // In this branch we don't allocate query keys
276 let query_name
= profiler
.get_or_alloc_cached_string(query_name
);
277 let event_id
= event_id_builder
.from_label(query_name
).to_string_id();
279 query_state
.iter_results(|results
| {
280 let query_invocation_ids
: Vec
<_
> = results
.map(|v
| v
.2.into
()).collect();
282 profiler
.bulk_map_query_invocation_id_to_single_string(
283 query_invocation_ids
.into_iter(),