Skip to content

Commit a550f2d

Browse files
committed
Auto merge of rust-lang#46111 - michaelwoerister:promote-green, r=nikomatsakis
incr.comp.: Make sure we don't lose unused green results from the query cache. In its current implementation, the query result cache works by bulk-writing the results of all cacheable queries into a monolithic binary file on disk. Prior to this PR, we would potentially lose query results during this process because only results that had already been loaded into memory were serialized. In contrast, results that were not needed during the given compilation session were not serialized again. This PR will do one pass over all green `DepNodes` that represent a cacheable query and execute the corresponding query in order to make sure that the query result gets loaded into memory before cache serialization. In the future we might want to look into a serialization format the can be updated in-place so that we don't have to load unchanged results just for immediately storing them again. r? @nikomatsakis
2 parents 5f44c65 + 0ea4b47 commit a550f2d

File tree

3 files changed

+92
-0
lines changed

3 files changed

+92
-0
lines changed

src/librustc/dep_graph/graph.rs

+33
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,39 @@ impl DepGraph {
659659
}).unwrap_or(false)
660660
}
661661

662+
// This method loads all on-disk cacheable query results into memory, so
663+
// they can be written out to the new cache file again. Most query results
664+
// will already be in memory but in the case where we marked something as
665+
// green but then did not need the value, that value will never have been
666+
// loaded from disk.
667+
//
668+
// This method will only load queries that will end up in the disk cache.
669+
// Other queries will not be executed.
670+
pub fn exec_cache_promotions<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) {
671+
let green_nodes: Vec<DepNode> = {
672+
let data = self.data.as_ref().unwrap();
673+
data.colors.borrow().iter().filter_map(|(dep_node, color)| match color {
674+
DepNodeColor::Green(_) => {
675+
if dep_node.cache_on_disk(tcx) {
676+
Some(*dep_node)
677+
} else {
678+
None
679+
}
680+
}
681+
DepNodeColor::Red => {
682+
// We can skip red nodes because a node can only be marked
683+
// as red if the query result was recomputed and thus is
684+
// already in memory.
685+
None
686+
}
687+
}).collect()
688+
};
689+
690+
for dep_node in green_nodes {
691+
dep_node.load_from_on_disk_cache(tcx);
692+
}
693+
}
694+
662695
pub fn mark_loaded_from_cache(&self, dep_node_index: DepNodeIndex, state: bool) {
663696
debug!("mark_loaded_from_cache({:?}, {})",
664697
self.data.as_ref().unwrap().current.borrow().nodes[dep_node_index],

src/librustc/ty/maps/on_disk_cache.rs

+4
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,10 @@ impl<'sess> OnDiskCache<'sess> {
197197

198198
encoder.encode_tagged(PREV_DIAGNOSTICS_TAG, &diagnostics)?;
199199

200+
// Load everything into memory so we can write it out to the on-disk
201+
// cache. The vast majority of cacheable query results should already
202+
// be in memory, so this should be a cheap operation.
203+
tcx.dep_graph.exec_cache_promotions(tcx);
200204

201205
// Encode query results
202206
let mut query_result_index = EncodedQueryResultIndex::new();

src/librustc/ty/maps/plumbing.rs

+55
Original file line numberDiff line numberDiff line change
@@ -898,3 +898,58 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
898898

899899
true
900900
}
901+
902+
903+
// FIXME(#45015): Another piece of boilerplate code that could be generated in
904+
// a combined define_dep_nodes!()/define_maps!() macro.
905+
macro_rules! impl_load_from_cache {
906+
($($dep_kind:ident => $query_name:ident,)*) => {
907+
impl DepNode {
908+
// Check whether the query invocation corresponding to the given
909+
// DepNode is eligible for on-disk-caching.
910+
pub fn cache_on_disk(&self, tcx: TyCtxt) -> bool {
911+
use ty::maps::queries;
912+
use ty::maps::QueryDescription;
913+
914+
match self.kind {
915+
$(DepKind::$dep_kind => {
916+
let def_id = self.extract_def_id(tcx).unwrap();
917+
queries::$query_name::cache_on_disk(def_id)
918+
})*
919+
_ => false
920+
}
921+
}
922+
923+
// This is method will execute the query corresponding to the given
924+
// DepNode. It is only expected to work for DepNodes where the
925+
// above `cache_on_disk` methods returns true.
926+
// Also, as a sanity check, it expects that the corresponding query
927+
// invocation has been marked as green already.
928+
pub fn load_from_on_disk_cache(&self, tcx: TyCtxt) {
929+
match self.kind {
930+
$(DepKind::$dep_kind => {
931+
debug_assert!(tcx.dep_graph
932+
.node_color(self)
933+
.map(|c| c.is_green())
934+
.unwrap_or(false));
935+
936+
let def_id = self.extract_def_id(tcx).unwrap();
937+
let _ = tcx.$query_name(def_id);
938+
})*
939+
_ => {
940+
bug!()
941+
}
942+
}
943+
}
944+
}
945+
}
946+
}
947+
948+
impl_load_from_cache!(
949+
TypeckTables => typeck_tables_of,
950+
MirOptimized => optimized_mir,
951+
UnsafetyCheckResult => unsafety_check_result,
952+
BorrowCheck => borrowck,
953+
MirBorrowCheck => mir_borrowck,
954+
MirConstQualif => mir_const_qualif,
955+
);

0 commit comments

Comments
 (0)