From 623d6e8ca423e37daf435136da32697e3cdd605b Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 3 Feb 2025 21:31:06 +1100 Subject: [PATCH] Notes on types/traits used for in-memory query caching When the word "cache" appears in the context of the query system, it often isn't obvious whether that is referring to the in-memory query cache or the on-disk incremental cache. For these types, we can assure the reader that they are for in-memory caching. --- .../rustc_data_structures/src/vec_cache.rs | 13 ++++++++++++ compiler/rustc_middle/src/query/keys.rs | 6 ++++++ .../rustc_query_system/src/query/caches.rs | 20 ++++++++++++++++++- .../rustc_query_system/src/query/plumbing.rs | 8 ++++---- 4 files changed, 42 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_data_structures/src/vec_cache.rs b/compiler/rustc_data_structures/src/vec_cache.rs index eb251b587c804..2ff60ab7f36f9 100644 --- a/compiler/rustc_data_structures/src/vec_cache.rs +++ b/compiler/rustc_data_structures/src/vec_cache.rs @@ -206,6 +206,19 @@ impl SlotIndex { } } +/// In-memory cache for queries whose keys are densely-numbered IDs +/// (e.g `CrateNum`, `LocalDefId`), and can therefore be used as indices +/// into a dense vector of cached values. +/// +/// (As of [#124780] the underlying storage is not an actual `Vec`, but rather +/// a series of increasingly-large buckets, for improved performance when the +/// parallel frontend is using multiple threads.) +/// +/// Each entry in the cache stores the query's return value (`V`), and also +/// an associated index (`I`), which in practice is a `DepNodeIndex` used for +/// query dependency tracking. +/// +/// [#124780]: https://github.com/rust-lang/rust/pull/124780 pub struct VecCache { // Entries per bucket: // Bucket 0: 4096 2^12 diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 949d8303385cb..1489d57aba645 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -20,6 +20,12 @@ pub struct LocalCrate; /// The `Key` trait controls what types can legally be used as the key /// for a query. pub trait Key: Sized { + /// The type of in-memory cache to use for queries with this key type. + /// + /// In practice the cache type must implement [`QueryCache`], though that + /// constraint is not enforced here. + /// + /// [`QueryCache`]: rustc_query_system::query::QueryCache // N.B. Most of the keys down below have `type Cache = DefaultCache;`, // it would be reasonable to use associated type defaults, to remove the duplication... // diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs index e6f3d97742d31..e11123dff26a7 100644 --- a/compiler/rustc_query_system/src/query/caches.rs +++ b/compiler/rustc_query_system/src/query/caches.rs @@ -11,18 +11,30 @@ use rustc_span::def_id::{DefId, DefIndex}; use crate::dep_graph::DepNodeIndex; +/// Trait for types that serve as an in-memory cache for query results, +/// for a given key (argument) type and value (return) type. +/// +/// Types implementing this trait are associated with actual key/value types +/// by the `Cache` associated type of the `rustc_middle::query::Key` trait. pub trait QueryCache: Sized { type Key: Hash + Eq + Copy + Debug; type Value: Copy; - /// Checks if the query is already computed and in the cache. + /// Returns the cached value (and other information) associated with the + /// given key, if it is present in the cache. fn lookup(&self, key: &Self::Key) -> Option<(Self::Value, DepNodeIndex)>; + /// Adds a key/value entry to this cache. + /// + /// Called by some part of the query system, after having obtained the + /// value by executing the query or loading a cached value from disk. fn complete(&self, key: Self::Key, value: Self::Value, index: DepNodeIndex); fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)); } +/// In-memory cache for queries whose keys aren't suitable for any of the +/// more specialized kinds of cache. Backed by a sharded hashmap. pub struct DefaultCache { cache: Sharded>, } @@ -67,6 +79,8 @@ where } } +/// In-memory cache for queries whose key type only has one value (e.g. `()`). +/// The cache therefore only needs to store one query return value. pub struct SingleCache { cache: OnceLock<(V, DepNodeIndex)>, } @@ -101,6 +115,10 @@ where } } +/// In-memory cache for queries whose key is a [`DefId`]. +/// +/// Selects between one of two internal caches, depending on whether the key +/// is a local ID or foreign-crate ID. pub struct DefIdCache { /// Stores the local DefIds in a dense map. Local queries are much more often dense, so this is /// a win over hashing query keys at marginal memory cost (~5% at most) compared to FxHashMap. diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 6fb5e37d2d066..18aae8c00b247 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -222,10 +222,10 @@ pub struct CycleError { pub cycle: Vec, } -/// Checks if the query is already computed and in the cache. -/// It returns the shard index and a lock guard to the shard, -/// which will be used if the query is not in the cache and we need -/// to compute it. +/// Checks whether there is already a value for this key in the in-memory +/// query cache, returning that value if present. +/// +/// (Also performs some associated bookkeeping, if a value was found.) #[inline(always)] pub fn try_get_cached(tcx: Tcx, cache: &C, key: &C::Key) -> Option where