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}
;
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];
62 match def_key
.disambiguated_data
.data
{
63 DefPathData
::CrateRoot
=> {
64 name
= self.tcx
.original_crate_name(def_id
.krate
).as_str();
69 name
= other
.as_symbol().as_str();
70 if def_key
.disambiguated_data
.disambiguator
== 0 {
74 write
!(&mut dis_buffer
[..], "[{}]", def_key
.disambiguated_data
.disambiguator
)
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();
84 StringComponent
::Ref(parent_string_id
),
85 StringComponent
::Value("::"),
86 StringComponent
::Value(&name
[..]),
87 StringComponent
::Value(dis
),
90 let string_id
= self.profiler
.alloc_string(&components
[start_index
..end_index
]);
92 self.string_cache
.def_id_cache
.insert(def_id
, string_id
);
98 pub trait IntoSelfProfilingString
{
99 fn to_self_profile_string(&self, builder
: &mut QueryKeyStringBuilder
<'_
, '_
, '_
>) -> StringId
;
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
106 impl<T
: Debug
> IntoSelfProfilingString
for T
{
107 default fn to_self_profile_string(
109 builder
: &mut QueryKeyStringBuilder
<'_
, '_
, '_
>,
111 let s
= format
!("{:?}", self);
112 builder
.profiler
.alloc_string(&s
[..])
116 impl IntoSelfProfilingString
for DefId
{
117 fn to_self_profile_string(&self, builder
: &mut QueryKeyStringBuilder
<'_
, '_
, '_
>) -> StringId
{
118 builder
.def_id_to_string_id(*self)
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 }
)
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 }
)
134 impl<T0
, T1
> IntoSelfProfilingString
for (T0
, T1
)
136 T0
: IntoSelfProfilingString
+ Debug
,
137 T1
: IntoSelfProfilingString
+ Debug
,
139 default fn to_self_profile_string(
141 builder
: &mut QueryKeyStringBuilder
<'_
, '_
, '_
>,
143 let val0
= self.0.to_self_profile_string(builder
);
144 let val1
= self.1.to_self_profile_string(builder
);
147 StringComponent
::Value("("),
148 StringComponent
::Ref(val0
),
149 StringComponent
::Value(","),
150 StringComponent
::Ref(val1
),
151 StringComponent
::Value(")"),
154 builder
.profiler
.alloc_string(components
)
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
>(
163 query_name
: &'
static str,
164 query_cache
: &Sharded
<QueryCache
<'tcx
, Q
>>,
165 string_cache
: &mut QueryKeyStringCache
,
167 Q
: QueryConfig
<'tcx
>,
169 tcx
.prof
.with_profiler(|profiler
| {
170 let event_id_builder
= profiler
.event_id_builder();
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
);
178 let query_name
= profiler
.get_or_alloc_cached_string(query_name
);
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();
188 let mut query_keys_and_indices
= Vec
::with_capacity(len
);
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
)),
196 query_keys_and_indices
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();
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
);
210 // Doing this in bulk might be a good idea:
211 profiler
.map_query_invocation_id_to_string(
213 event_id
.to_string_id(),
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();
221 let shards
= query_cache
.lock_shards();
223 for shard
in shards
.iter() {
224 let query_invocation_ids
= shard
228 .map(|dep_node_index
| dep_node_index
.into());
231 .bulk_map_query_invocation_id_to_single_string(query_invocation_ids
, event_id
);