Skip to content

Commit d1206f9

Browse files
committed
Auto merge of #81855 - cjgillot:ensure-cache, r=oli-obk
Check the result cache before the DepGraph when ensuring queries Split out of #70951 Calling `ensure` on already forced queries is a common operation. Looking at the results cache first is faster than checking the DepGraph for a green node.
2 parents 9503ea1 + 3fc8ed6 commit d1206f9

File tree

9 files changed

+298
-237
lines changed

9 files changed

+298
-237
lines changed

Diff for: compiler/rustc_data_structures/src/sharded.rs

+15-15
Original file line numberDiff line numberDiff line change
@@ -63,23 +63,9 @@ impl<T> Sharded<T> {
6363
if SHARDS == 1 { &self.shards[0].0 } else { self.get_shard_by_hash(make_hash(val)) }
6464
}
6565

66-
/// Get a shard with a pre-computed hash value. If `get_shard_by_value` is
67-
/// ever used in combination with `get_shard_by_hash` on a single `Sharded`
68-
/// instance, then `hash` must be computed with `FxHasher`. Otherwise,
69-
/// `hash` can be computed with any hasher, so long as that hasher is used
70-
/// consistently for each `Sharded` instance.
71-
#[inline]
72-
pub fn get_shard_index_by_hash(&self, hash: u64) -> usize {
73-
let hash_len = mem::size_of::<usize>();
74-
// Ignore the top 7 bits as hashbrown uses these and get the next SHARD_BITS highest bits.
75-
// hashbrown also uses the lowest bits, so we can't use those
76-
let bits = (hash >> (hash_len * 8 - 7 - SHARD_BITS)) as usize;
77-
bits % SHARDS
78-
}
79-
8066
#[inline]
8167
pub fn get_shard_by_hash(&self, hash: u64) -> &Lock<T> {
82-
&self.shards[self.get_shard_index_by_hash(hash)].0
68+
&self.shards[get_shard_index_by_hash(hash)].0
8369
}
8470

8571
#[inline]
@@ -166,3 +152,17 @@ fn make_hash<K: Hash + ?Sized>(val: &K) -> u64 {
166152
val.hash(&mut state);
167153
state.finish()
168154
}
155+
156+
/// Get a shard with a pre-computed hash value. If `get_shard_by_value` is
157+
/// ever used in combination with `get_shard_by_hash` on a single `Sharded`
158+
/// instance, then `hash` must be computed with `FxHasher`. Otherwise,
159+
/// `hash` can be computed with any hasher, so long as that hasher is used
160+
/// consistently for each `Sharded` instance.
161+
#[inline]
162+
pub fn get_shard_index_by_hash(hash: u64) -> usize {
163+
let hash_len = mem::size_of::<usize>();
164+
// Ignore the top 7 bits as hashbrown uses these and get the next SHARD_BITS highest bits.
165+
// hashbrown also uses the lowest bits, so we can't use those
166+
let bits = (hash >> (hash_len * 8 - 7 - SHARD_BITS)) as usize;
167+
bits % SHARDS
168+
}

Diff for: compiler/rustc_middle/src/ty/context.rs

+2
Original file line numberDiff line numberDiff line change
@@ -963,6 +963,7 @@ pub struct GlobalCtxt<'tcx> {
963963
pub(crate) definitions: &'tcx Definitions,
964964

965965
pub queries: query::Queries<'tcx>,
966+
pub query_caches: query::QueryCaches<'tcx>,
966967

967968
maybe_unused_trait_imports: FxHashSet<LocalDefId>,
968969
maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
@@ -1154,6 +1155,7 @@ impl<'tcx> TyCtxt<'tcx> {
11541155
untracked_crate: krate,
11551156
definitions,
11561157
queries: query::Queries::new(providers, extern_providers, on_disk_query_result_cache),
1158+
query_caches: query::QueryCaches::default(),
11571159
ty_rcache: Default::default(),
11581160
pred_rcache: Default::default(),
11591161
selection_cache: Default::default(),

Diff for: compiler/rustc_middle/src/ty/query/on_disk_cache.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -1244,10 +1244,9 @@ where
12441244
.prof
12451245
.extra_verbose_generic_activity("encode_query_results_for", std::any::type_name::<Q>());
12461246

1247-
let state = Q::query_state(tcx);
1248-
assert!(state.all_inactive());
1249-
1250-
state.iter_results(|results| {
1247+
assert!(Q::query_state(tcx).all_inactive());
1248+
let cache = Q::query_cache(tcx);
1249+
cache.iter_results(|results| {
12511250
for (key, value, dep_node) in results {
12521251
if Q::cache_on_disk(tcx, &key, Some(value)) {
12531252
let dep_node = SerializedDepNodeIndex::new(dep_node.index());

Diff for: compiler/rustc_middle/src/ty/query/plumbing.rs

+53-16
Original file line numberDiff line numberDiff line change
@@ -342,14 +342,28 @@ macro_rules! define_queries {
342342

343343
$(pub type $name<$tcx> = $V;)*
344344
}
345+
#[allow(nonstandard_style, unused_lifetimes)]
346+
pub mod query_storage {
347+
use super::*;
348+
349+
$(pub type $name<$tcx> = query_storage!([$($modifiers)*][$($K)*, $V]);)*
350+
}
351+
#[allow(nonstandard_style, unused_lifetimes)]
352+
pub mod query_stored {
353+
use super::*;
354+
355+
$(pub type $name<$tcx> = <query_storage::$name<$tcx> as QueryStorage>::Stored;)*
356+
}
357+
358+
#[derive(Default)]
359+
pub struct QueryCaches<$tcx> {
360+
$($(#[$attr])* $name: QueryCacheStore<query_storage::$name<$tcx>>,)*
361+
}
345362

346363
$(impl<$tcx> QueryConfig for queries::$name<$tcx> {
347364
type Key = $($K)*;
348365
type Value = $V;
349-
type Stored = <
350-
query_storage!([$($modifiers)*][$($K)*, $V])
351-
as QueryStorage
352-
>::Stored;
366+
type Stored = query_stored::$name<$tcx>;
353367
const NAME: &'static str = stringify!($name);
354368
}
355369

@@ -358,13 +372,20 @@ macro_rules! define_queries {
358372
const EVAL_ALWAYS: bool = is_eval_always!([$($modifiers)*]);
359373
const DEP_KIND: dep_graph::DepKind = dep_graph::DepKind::$name;
360374

361-
type Cache = query_storage!([$($modifiers)*][$($K)*, $V]);
375+
type Cache = query_storage::$name<$tcx>;
362376

363377
#[inline(always)]
364-
fn query_state<'a>(tcx: TyCtxt<$tcx>) -> &'a QueryState<crate::dep_graph::DepKind, <TyCtxt<$tcx> as QueryContext>::Query, Self::Cache> {
378+
fn query_state<'a>(tcx: TyCtxt<$tcx>) -> &'a QueryState<crate::dep_graph::DepKind, Query<$tcx>, Self::Key> {
365379
&tcx.queries.$name
366380
}
367381

382+
#[inline(always)]
383+
fn query_cache<'a>(tcx: TyCtxt<$tcx>) -> &'a QueryCacheStore<Self::Cache>
384+
where 'tcx:'a
385+
{
386+
&tcx.query_caches.$name
387+
}
388+
368389
#[inline]
369390
fn compute(tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Value {
370391
let provider = tcx.queries.providers.get(key.query_crate())
@@ -401,7 +422,15 @@ macro_rules! define_queries {
401422
$($(#[$attr])*
402423
#[inline(always)]
403424
pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
404-
ensure_query::<queries::$name<'_>, _>(self.tcx, key.into_query_param())
425+
let key = key.into_query_param();
426+
let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, |_| {});
427+
428+
let lookup = match cached {
429+
Ok(()) => return,
430+
Err(lookup) => lookup,
431+
};
432+
433+
get_query::<queries::$name<'_>, _>(self.tcx, DUMMY_SP, key, lookup, QueryMode::Ensure);
405434
})*
406435
}
407436

@@ -442,10 +471,9 @@ macro_rules! define_queries {
442471
$($(#[$attr])*
443472
#[inline(always)]
444473
#[must_use]
445-
pub fn $name(self, key: query_helper_param_ty!($($K)*))
446-
-> <queries::$name<$tcx> as QueryConfig>::Stored
474+
pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<$tcx>
447475
{
448-
self.at(DUMMY_SP).$name(key.into_query_param())
476+
self.at(DUMMY_SP).$name(key)
449477
})*
450478

451479
/// All self-profiling events generated by the query engine use
@@ -471,7 +499,7 @@ macro_rules! define_queries {
471499
alloc_self_profile_query_strings_for_query_cache(
472500
self,
473501
stringify!($name),
474-
&self.queries.$name,
502+
&self.query_caches.$name,
475503
&mut string_cache,
476504
);
477505
})*
@@ -481,10 +509,19 @@ macro_rules! define_queries {
481509
impl TyCtxtAt<$tcx> {
482510
$($(#[$attr])*
483511
#[inline(always)]
484-
pub fn $name(self, key: query_helper_param_ty!($($K)*))
485-
-> <queries::$name<$tcx> as QueryConfig>::Stored
512+
pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<$tcx>
486513
{
487-
get_query::<queries::$name<'_>, _>(self.tcx, self.span, key.into_query_param())
514+
let key = key.into_query_param();
515+
let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, |value| {
516+
value.clone()
517+
});
518+
519+
let lookup = match cached {
520+
Ok(value) => return value,
521+
Err(lookup) => lookup,
522+
};
523+
524+
get_query::<queries::$name<'_>, _>(self.tcx, self.span, key, lookup, QueryMode::Get).unwrap()
488525
})*
489526
}
490527

@@ -518,8 +555,8 @@ macro_rules! define_queries_struct {
518555

519556
$($(#[$attr])* $name: QueryState<
520557
crate::dep_graph::DepKind,
521-
<TyCtxt<$tcx> as QueryContext>::Query,
522-
<queries::$name<$tcx> as QueryAccessors<TyCtxt<'tcx>>>::Cache,
558+
Query<$tcx>,
559+
query_keys::$name<$tcx>,
523560
>,)*
524561
}
525562

Diff for: compiler/rustc_middle/src/ty/query/profiling_support.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_data_structures::fx::FxHashMap;
55
use rustc_data_structures::profiling::SelfProfiler;
66
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
77
use rustc_hir::definitions::DefPathData;
8-
use rustc_query_system::query::{QueryCache, QueryContext, QueryState};
8+
use rustc_query_system::query::{QueryCache, QueryCacheStore};
99
use std::fmt::Debug;
1010
use std::io::Write;
1111

@@ -230,7 +230,7 @@ where
230230
pub(super) fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
231231
tcx: TyCtxt<'tcx>,
232232
query_name: &'static str,
233-
query_state: &QueryState<crate::dep_graph::DepKind, <TyCtxt<'tcx> as QueryContext>::Query, C>,
233+
query_cache: &QueryCacheStore<C>,
234234
string_cache: &mut QueryKeyStringCache,
235235
) where
236236
C: QueryCache,
@@ -251,7 +251,7 @@ pub(super) fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
251251
// need to invoke queries itself, we cannot keep the query caches
252252
// locked while doing so. Instead we copy out the
253253
// `(query_key, dep_node_index)` pairs and release the lock again.
254-
let query_keys_and_indices: Vec<_> = query_state
254+
let query_keys_and_indices: Vec<_> = query_cache
255255
.iter_results(|results| results.map(|(k, _, i)| (k.clone(), i)).collect());
256256

257257
// Now actually allocate the strings. If allocating the strings
@@ -276,7 +276,7 @@ pub(super) fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
276276
let query_name = profiler.get_or_alloc_cached_string(query_name);
277277
let event_id = event_id_builder.from_label(query_name).to_string_id();
278278

279-
query_state.iter_results(|results| {
279+
query_cache.iter_results(|results| {
280280
let query_invocation_ids: Vec<_> = results.map(|v| v.2.into()).collect();
281281

282282
profiler.bulk_map_query_invocation_id_to_single_string(

Diff for: compiler/rustc_middle/src/ty/query/stats.rs

+3-8
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
use crate::ty::query::queries;
22
use crate::ty::TyCtxt;
33
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
4-
use rustc_query_system::query::{QueryAccessors, QueryCache, QueryContext, QueryState};
4+
use rustc_query_system::query::{QueryAccessors, QueryCache, QueryCacheStore};
55

66
use std::any::type_name;
7-
use std::hash::Hash;
87
use std::mem;
98
#[cfg(debug_assertions)]
109
use std::sync::atomic::Ordering;
@@ -37,10 +36,8 @@ struct QueryStats {
3736
local_def_id_keys: Option<usize>,
3837
}
3938

40-
fn stats<D, Q, C>(name: &'static str, map: &QueryState<D, Q, C>) -> QueryStats
39+
fn stats<C>(name: &'static str, map: &QueryCacheStore<C>) -> QueryStats
4140
where
42-
D: Copy + Clone + Eq + Hash,
43-
Q: Clone,
4441
C: QueryCache,
4542
{
4643
let mut stats = QueryStats {
@@ -128,12 +125,10 @@ macro_rules! print_stats {
128125

129126
$(
130127
queries.push(stats::<
131-
crate::dep_graph::DepKind,
132-
<TyCtxt<'_> as QueryContext>::Query,
133128
<queries::$name<'_> as QueryAccessors<TyCtxt<'_>>>::Cache,
134129
>(
135130
stringify!($name),
136-
&tcx.queries.$name,
131+
&tcx.query_caches.$name,
137132
));
138133
)*
139134

Diff for: compiler/rustc_query_system/src/query/caches.rs

+27-31
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::dep_graph::DepNodeIndex;
2-
use crate::query::plumbing::{QueryLookup, QueryState};
2+
use crate::query::plumbing::{QueryCacheStore, QueryLookup};
33

44
use rustc_arena::TypedArena;
55
use rustc_data_structures::fx::FxHashMap;
@@ -31,17 +31,15 @@ pub trait QueryCache: QueryStorage {
3131
/// It returns the shard index and a lock guard to the shard,
3232
/// which will be used if the query is not in the cache and we need
3333
/// to compute it.
34-
fn lookup<D, Q, R, OnHit, OnMiss>(
34+
fn lookup<'s, R, OnHit>(
3535
&self,
36-
state: &QueryState<D, Q, Self>,
37-
key: Self::Key,
36+
state: &'s QueryCacheStore<Self>,
37+
key: &Self::Key,
3838
// `on_hit` can be called while holding a lock to the query state shard.
3939
on_hit: OnHit,
40-
on_miss: OnMiss,
41-
) -> R
40+
) -> Result<R, QueryLookup>
4241
where
43-
OnHit: FnOnce(&Self::Stored, DepNodeIndex) -> R,
44-
OnMiss: FnOnce(Self::Key, QueryLookup<'_, D, Q, Self::Key, Self::Sharded>) -> R;
42+
OnHit: FnOnce(&Self::Stored, DepNodeIndex) -> R;
4543

4644
fn complete(
4745
&self,
@@ -95,23 +93,24 @@ where
9593
type Sharded = FxHashMap<K, (V, DepNodeIndex)>;
9694

9795
#[inline(always)]
98-
fn lookup<D, Q, R, OnHit, OnMiss>(
96+
fn lookup<'s, R, OnHit>(
9997
&self,
100-
state: &QueryState<D, Q, Self>,
101-
key: K,
98+
state: &'s QueryCacheStore<Self>,
99+
key: &K,
102100
on_hit: OnHit,
103-
on_miss: OnMiss,
104-
) -> R
101+
) -> Result<R, QueryLookup>
105102
where
106103
OnHit: FnOnce(&V, DepNodeIndex) -> R,
107-
OnMiss: FnOnce(K, QueryLookup<'_, D, Q, K, Self::Sharded>) -> R,
108104
{
109-
let mut lookup = state.get_lookup(&key);
110-
let lock = &mut *lookup.lock;
105+
let (lookup, lock) = state.get_lookup(key);
106+
let result = lock.raw_entry().from_key_hashed_nocheck(lookup.key_hash, key);
111107

112-
let result = lock.cache.raw_entry().from_key_hashed_nocheck(lookup.key_hash, &key);
113-
114-
if let Some((_, value)) = result { on_hit(&value.0, value.1) } else { on_miss(key, lookup) }
108+
if let Some((_, value)) = result {
109+
let hit_result = on_hit(&value.0, value.1);
110+
Ok(hit_result)
111+
} else {
112+
Err(lookup)
113+
}
115114
}
116115

117116
#[inline]
@@ -177,26 +176,23 @@ where
177176
type Sharded = FxHashMap<K, &'tcx (V, DepNodeIndex)>;
178177

179178
#[inline(always)]
180-
fn lookup<D, Q, R, OnHit, OnMiss>(
179+
fn lookup<'s, R, OnHit>(
181180
&self,
182-
state: &QueryState<D, Q, Self>,
183-
key: K,
181+
state: &'s QueryCacheStore<Self>,
182+
key: &K,
184183
on_hit: OnHit,
185-
on_miss: OnMiss,
186-
) -> R
184+
) -> Result<R, QueryLookup>
187185
where
188186
OnHit: FnOnce(&&'tcx V, DepNodeIndex) -> R,
189-
OnMiss: FnOnce(K, QueryLookup<'_, D, Q, K, Self::Sharded>) -> R,
190187
{
191-
let mut lookup = state.get_lookup(&key);
192-
let lock = &mut *lookup.lock;
193-
194-
let result = lock.cache.raw_entry().from_key_hashed_nocheck(lookup.key_hash, &key);
188+
let (lookup, lock) = state.get_lookup(key);
189+
let result = lock.raw_entry().from_key_hashed_nocheck(lookup.key_hash, key);
195190

196191
if let Some((_, value)) = result {
197-
on_hit(&&value.0, value.1)
192+
let hit_result = on_hit(&&value.0, value.1);
193+
Ok(hit_result)
198194
} else {
199-
on_miss(key, lookup)
195+
Err(lookup)
200196
}
201197
}
202198

0 commit comments

Comments
 (0)