Skip to content

Commit d3ea035

Browse files
committed
Auto merge of #158059 - xmakro:perf/lexer-ascii-symbolgallery, r=cjgillot
Skip query machinery when promoting disk-cached values At the end of an incremental session, exec_cache_promotions walks the green nodes and, for queries that were never used this session, loads their value from the previous session's disk cache into memory so it gets written into the new cache. This load currently goes through the full query execution path and shows up in profiles of incremental builds with few or no changes, which is the motivation for this PR. Instead, this PR only loads the value directly and puts it in the in-memory cache. Perf improvement: -1.3% mean instructions, mostly in incr-unchanged, -0.36% in incr-patched, no regressions, see #158059 (comment). Behavior change: A missing disk value is now a bug instead of a silent recompute.
2 parents 09ee43b + 1d85e59 commit d3ea035

5 files changed

Lines changed: 75 additions & 36 deletions

File tree

compiler/rustc_middle/src/dep_graph/dep_node.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ use rustc_hir::definitions::DefPathHash;
5757
use rustc_macros::{Decodable, Encodable, StableHash};
5858
use rustc_span::Symbol;
5959

60-
use super::{KeyFingerprintStyle, SerializedDepNodeIndex};
60+
use super::{DepNodeIndex, KeyFingerprintStyle, SerializedDepNodeIndex};
6161
use crate::dep_graph::DepNodeKey;
6262
use crate::mono::MonoItem;
6363
use crate::ty::{TyCtxt, tls};
@@ -208,8 +208,17 @@ pub struct DepKindVTable<'tcx> {
208208
fn(tcx: TyCtxt<'tcx>, dep_node: DepNode, prev_index: SerializedDepNodeIndex) -> bool,
209209
>,
210210

211-
/// Invoke a query to put the on-disk cached value in memory.
212-
pub promote_from_disk_fn: Option<fn(TyCtxt<'tcx>, DepNode)>,
211+
/// Load the on-disk cached value of a query into memory. The node is known
212+
/// to be green, with `prev_index` its index in the previous session's dep
213+
/// graph and `dep_node_index` its index in the current session's dep graph.
214+
pub promote_from_disk_fn: Option<
215+
fn(
216+
tcx: TyCtxt<'tcx>,
217+
dep_node: DepNode,
218+
prev_index: SerializedDepNodeIndex,
219+
dep_node_index: DepNodeIndex,
220+
),
221+
>,
213222
}
214223

215224
/// A "work product" corresponds to a `.o` (or other) file that we

compiler/rustc_middle/src/dep_graph/graph.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,12 +1064,12 @@ impl DepGraph {
10641064
let data = self.data.as_ref().unwrap();
10651065
for prev_index in data.colors.values.indices() {
10661066
match data.colors.get(prev_index) {
1067-
DepNodeColor::Green(_) => {
1067+
DepNodeColor::Green(dep_node_index) => {
10681068
let dep_node = data.previous.index_to_node(prev_index);
10691069
if let Some(promote_fn) =
10701070
tcx.dep_kind_vtable(dep_node.kind).promote_from_disk_fn
10711071
{
1072-
promote_fn(tcx, *dep_node)
1072+
promote_fn(tcx, *dep_node, prev_index, dep_node_index)
10731073
};
10741074
}
10751075
DepNodeColor::Unknown | DepNodeColor::Red => {

compiler/rustc_query_impl/src/dep_kind_vtables.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,12 @@ where
117117
crate::execution::force_query_dep_node(tcx, query, dep_node)
118118
},
119119
),
120-
promote_from_disk_fn: (can_recover && is_cache_on_disk).then_some(|tcx, dep_node| {
121-
let query = Q::query_vtable(tcx);
122-
promote_from_disk_inner(tcx, query, dep_node)
123-
}),
120+
promote_from_disk_fn: (can_recover && is_cache_on_disk).then_some(
121+
|tcx, dep_node, prev_index, dep_node_index| {
122+
let query = Q::query_vtable(tcx);
123+
promote_from_disk_inner(tcx, query, dep_node, prev_index, dep_node_index)
124+
},
125+
),
124126
}
125127
}
126128

compiler/rustc_query_impl/src/execution.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::hash::Hash;
22
use std::mem::ManuallyDrop;
33

4+
use rustc_data_structures::fingerprint::Fingerprint;
45
use rustc_data_structures::hash_table::{Entry, HashTable};
56
use rustc_data_structures::stack::ensure_sufficient_stack;
67
use rustc_data_structures::sync::{DynSend, DynSync};
@@ -484,6 +485,20 @@ fn execute_job_incr<'tcx, C: QueryCache>(
484485
(result, dep_node_index)
485486
}
486487

488+
/// Whether a value loaded from the on-disk cache should have its fingerprint
489+
/// verified with `incremental_verify_ich`. If `-Zincremental-verify-ich` is
490+
/// specified, re-hash results from the cache and make sure that they have the
491+
/// expected fingerprint.
492+
///
493+
/// If not, we still seek to verify a subset of fingerprints loaded from disk.
494+
/// Re-hashing results is fairly expensive, so we can't currently afford to
495+
/// verify every hash. This subset should still give us some coverage of
496+
/// potential bugs.
497+
pub(crate) fn should_verify_loaded_value(tcx: TyCtxt<'_>, prev_fingerprint: Fingerprint) -> bool {
498+
prev_fingerprint.split().1.as_u64().is_multiple_of(32)
499+
|| tcx.sess.opts.unstable_opts.incremental_verify_ich
500+
}
501+
487502
/// Given that the dep node for this query+key is green, obtain a value for it
488503
/// by loading one from disk if possible, or by invoking its query provider if
489504
/// necessary.
@@ -518,15 +533,7 @@ fn load_from_disk_or_invoke_provider_green<'tcx, C: QueryCache>(
518533
}
519534

520535
let prev_fingerprint = dep_graph_data.prev_value_fingerprint_of(prev_index);
521-
// If `-Zincremental-verify-ich` is specified, re-hash results from
522-
// the cache and make sure that they have the expected fingerprint.
523-
//
524-
// If not, we still seek to verify a subset of fingerprints loaded
525-
// from disk. Re-hashing results is fairly expensive, so we can't
526-
// currently afford to verify every hash. This subset should still
527-
// give us some coverage of potential bugs.
528-
let verify = prev_fingerprint.split().1.as_u64().is_multiple_of(32)
529-
|| tcx.sess.opts.unstable_opts.incremental_verify_ich;
536+
let verify = should_verify_loaded_value(tcx, prev_fingerprint);
530537

531538
(value, verify)
532539
}

compiler/rustc_query_impl/src/plumbing.rs

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
use std::num::NonZero;
22

33
use rustc_data_structures::Limit;
4+
use rustc_data_structures::stack::ensure_sufficient_stack;
45
use rustc_data_structures::unord::UnordMap;
56
use rustc_middle::bug;
67
#[expect(unused_imports, reason = "used by doc comments")]
78
use rustc_middle::dep_graph::DepKindVTable;
8-
use rustc_middle::dep_graph::{DepNode, DepNodeKey, SerializedDepNodeIndex};
9+
use rustc_middle::dep_graph::{DepNode, DepNodeIndex, DepNodeKey, SerializedDepNodeIndex};
910
use rustc_middle::query::erase::{Erasable, Erased};
1011
use rustc_middle::query::on_disk_cache::{CacheDecoder, CacheEncoder};
11-
use rustc_middle::query::{QueryCache, QueryJobId, QueryMode, QueryVTable, erase};
12+
use rustc_middle::query::{QueryCache, QueryJobId, QueryVTable, erase};
1213
use rustc_middle::ty::TyCtxt;
1314
use rustc_middle::ty::tls::{self, ImplicitCtxt};
15+
use rustc_middle::verify_ich::incremental_verify_ich;
1416
use rustc_serialize::{Decodable, Encodable};
15-
use rustc_span::DUMMY_SP;
1617
use rustc_span::def_id::LOCAL_CRATE;
1718

1819
use crate::error::{QueryOverflow, QueryOverflowNote};
19-
use crate::execution::all_inactive;
20+
use crate::execution::{all_inactive, should_verify_loaded_value};
2021
use crate::job::find_dep_kind_root;
2122
use crate::query_impl::for_each_query_vtable;
2223
use crate::{CollectActiveJobsKind, collect_active_query_jobs};
@@ -140,6 +141,8 @@ pub(crate) fn promote_from_disk_inner<'tcx, C: QueryCache>(
140141
tcx: TyCtxt<'tcx>,
141142
query: &'tcx QueryVTable<'tcx, C>,
142143
dep_node: DepNode,
144+
prev_index: SerializedDepNodeIndex,
145+
dep_node_index: DepNodeIndex,
143146
) {
144147
debug_assert!(tcx.dep_graph.is_green(&dep_node));
145148

@@ -156,21 +159,39 @@ pub(crate) fn promote_from_disk_inner<'tcx, C: QueryCache>(
156159
return;
157160
}
158161

159-
match query.cache.lookup(&key) {
160-
// If the value is already in memory, then promotion isn't needed.
161-
Some(_) => {}
162-
163-
// "Execute" the query to load its disk-cached value into memory.
164-
//
165-
// We know that the key is cache-on-disk and its node is green,
166-
// so there _must_ be a value on disk to load.
167-
//
168-
// FIXME(Zalathar): Is there a reasonable way to skip more of the
169-
// query bookkeeping when doing this?
170-
None => {
171-
(query.execute_query_fn)(tcx, DUMMY_SP, key, QueryMode::Get);
172-
}
162+
// If the value is already in memory, then promotion isn't needed.
163+
if query.cache.lookup(&key).is_some() {
164+
return;
165+
}
166+
167+
// Load the disk-cached value into memory.
168+
let dep_graph_data =
169+
tcx.dep_graph.data().expect("should always be present in incremental mode");
170+
171+
let prof_timer = tcx.prof.incr_cache_loading();
172+
let value = ensure_sufficient_stack(|| (query.try_load_from_disk_fn)(tcx, prev_index));
173+
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
174+
175+
let Some(value) = value else {
176+
// The key is cache-on-disk and its node is green, so a value must be on disk.
177+
bug!("failed to load disk-cached value for green node {dep_node:?}");
178+
};
179+
180+
// Verify the fingerprints of the same subset of loaded values as
181+
// `load_from_disk_or_invoke_provider_green` does.
182+
let prev_fingerprint = dep_graph_data.prev_value_fingerprint_of(prev_index);
183+
if should_verify_loaded_value(tcx, prev_fingerprint) {
184+
incremental_verify_ich(
185+
tcx,
186+
dep_graph_data,
187+
&value,
188+
prev_index,
189+
query.hash_value_fn,
190+
query.format_value,
191+
);
173192
}
193+
194+
query.cache.complete(key, value, dep_node_index);
174195
}
175196

176197
pub(crate) fn try_load_from_disk<'tcx, V>(

0 commit comments

Comments
 (0)