Skip to content

Commit 2c65d52

Browse files
committed
Create the previous dep graph index on a background thread
1 parent 4f75af9 commit 2c65d52

File tree

4 files changed

+96
-22
lines changed

4 files changed

+96
-22
lines changed

compiler/rustc_incremental/src/persist/load.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use rustc_session::config::IncrementalStateAssertion;
1111
use rustc_session::{Session, StableCrateId};
1212
use rustc_span::{ErrorGuaranteed, Symbol};
1313
use std::path::{Path, PathBuf};
14+
use std::sync::Arc;
1415

1516
use super::data::*;
1617
use super::file_format;
@@ -95,7 +96,7 @@ fn delete_dirty_work_product(sess: &Session, swp: SerializedWorkProduct) {
9596
work_product::delete_workproduct_files(sess, &swp.work_product);
9697
}
9798

98-
fn load_dep_graph(sess: &Session) -> LoadResult<(SerializedDepGraph, WorkProductMap)> {
99+
fn load_dep_graph(sess: &Session) -> LoadResult<(Arc<SerializedDepGraph>, WorkProductMap)> {
99100
let prof = sess.prof.clone();
100101

101102
if sess.opts.incremental.is_none() {
@@ -169,7 +170,7 @@ fn load_dep_graph(sess: &Session) -> LoadResult<(SerializedDepGraph, WorkProduct
169170
return LoadResult::DataOutOfDate;
170171
}
171172

172-
let dep_graph = SerializedDepGraph::decode::<DepsType>(&mut decoder);
173+
let dep_graph = SerializedDepGraph::decode::<DepsType>(&mut decoder, sess);
173174

174175
LoadResult::Ok { data: (dep_graph, prev_work_products) }
175176
}

compiler/rustc_incremental/src/persist/save.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
99
use rustc_serialize::Encodable as RustcEncodable;
1010
use rustc_session::Session;
1111
use std::fs;
12+
use std::sync::Arc;
1213

1314
use super::data::*;
1415
use super::dirty_clean;
@@ -149,7 +150,7 @@ fn encode_query_cache(tcx: TyCtxt<'_>, encoder: FileEncoder) -> FileEncodeResult
149150
/// and moves it to the permanent dep-graph path
150151
pub(crate) fn build_dep_graph(
151152
sess: &Session,
152-
prev_graph: SerializedDepGraph,
153+
prev_graph: Arc<SerializedDepGraph>,
153154
prev_work_products: WorkProductMap,
154155
) -> Option<DepGraph> {
155156
if sess.opts.incremental.is_none() {

compiler/rustc_query_system/src/dep_graph/graph.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use std::fmt::Debug;
1414
use std::hash::Hash;
1515
use std::marker::PhantomData;
1616
use std::sync::atomic::Ordering::Relaxed;
17+
use std::sync::Arc;
1718

1819
use super::query::DepGraphQuery;
1920
use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex};
@@ -83,7 +84,7 @@ pub struct DepGraphData<D: Deps> {
8384

8485
/// The dep-graph from the previous compilation session. It contains all
8586
/// nodes and edges as well as all fingerprints of nodes that have them.
86-
previous: SerializedDepGraph,
87+
previous: Arc<SerializedDepGraph>,
8788

8889
colors: DepNodeColorMap,
8990

@@ -115,7 +116,7 @@ where
115116
impl<D: Deps> DepGraph<D> {
116117
pub fn new(
117118
profiler: &SelfProfilerRef,
118-
prev_graph: SerializedDepGraph,
119+
prev_graph: Arc<SerializedDepGraph>,
119120
prev_work_products: WorkProductMap,
120121
encoder: FileEncoder,
121122
record_graph: bool,

compiler/rustc_query_system/src/dep_graph/serialized.rs

Lines changed: 88 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,17 @@ use crate::dep_graph::EdgesVec;
4141
use rustc_data_structures::fingerprint::Fingerprint;
4242
use rustc_data_structures::fingerprint::PackedFingerprint;
4343
use rustc_data_structures::fx::FxHashMap;
44+
use rustc_data_structures::outline;
4445
use rustc_data_structures::profiling::SelfProfilerRef;
4546
use rustc_data_structures::sync::Lock;
4647
use rustc_data_structures::unhash::UnhashMap;
4748
use rustc_index::{Idx, IndexVec};
4849
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder};
4950
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
50-
use std::iter;
51+
use rustc_session::Session;
5152
use std::marker::PhantomData;
53+
use std::sync::{Arc, OnceLock};
54+
use std::{iter, thread};
5255

5356
// The maximum value of `SerializedDepNodeIndex` leaves the upper two bits
5457
// unused so that we can store multiple index types in `CompressedHybridIndex`,
@@ -69,23 +72,33 @@ const DEP_NODE_PAD: usize = DEP_NODE_SIZE - 1;
6972
const DEP_NODE_WIDTH_BITS: usize = DEP_NODE_SIZE / 2;
7073

7174
/// Data for use when recompiling the **current crate**.
72-
#[derive(Debug)]
7375
pub struct SerializedDepGraph {
7476
/// The set of all DepNodes in the graph
7577
nodes: IndexVec<SerializedDepNodeIndex, DepNode>,
78+
7679
/// The set of all Fingerprints in the graph. Each Fingerprint corresponds to
7780
/// the DepNode at the same index in the nodes vector.
7881
fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>,
82+
7983
/// For each DepNode, stores the list of edges originating from that
8084
/// DepNode. Encoded as a [start, end) pair indexing into edge_list_data,
8185
/// which holds the actual DepNodeIndices of the target nodes.
8286
edge_list_indices: IndexVec<SerializedDepNodeIndex, EdgeHeader>,
87+
8388
/// A flattened list of all edge targets in the graph, stored in the same
8489
/// varint encoding that we use on disk. Edge sources are implicit in edge_list_indices.
8590
edge_list_data: Vec<u8>,
91+
8692
/// Stores a map from fingerprints to nodes per dep node kind.
87-
/// This is the reciprocal of `nodes`.
88-
index: Vec<UnhashMap<PackedFingerprint, SerializedDepNodeIndex>>,
93+
/// This is the reciprocal of `nodes`. This is computed on demand for each dep kind.
94+
/// The entire index is also computed in a background thread.
95+
index: Vec<OnceLock<UnhashMap<PackedFingerprint, SerializedDepNodeIndex>>>,
96+
97+
/// Stores the number of node for each dep node kind.
98+
index_sizes: Vec<usize>,
99+
100+
/// A profiler reference for used in the index prefetching thread.
101+
prof: SelfProfilerRef,
89102
}
90103

91104
impl Default for SerializedDepGraph {
@@ -96,6 +109,8 @@ impl Default for SerializedDepGraph {
96109
edge_list_indices: Default::default(),
97110
edge_list_data: Default::default(),
98111
index: Default::default(),
112+
index_sizes: Default::default(),
113+
prof: SelfProfilerRef::new(None, None),
99114
}
100115
}
101116
}
@@ -138,9 +153,35 @@ impl SerializedDepGraph {
138153
self.nodes[dep_node_index]
139154
}
140155

156+
/// This computes and sets up the index for just the specified `DepKind`.
157+
fn setup_index(&self, dep_kind: DepKind) {
158+
let _timer = self.prof.generic_activity("incr_comp_dep_graph_setup_index");
159+
160+
let mut index = UnhashMap::with_capacity_and_hasher(
161+
self.index_sizes[dep_kind.as_usize()],
162+
Default::default(),
163+
);
164+
165+
for (idx, node) in self.nodes.iter_enumerated() {
166+
if node.kind == dep_kind {
167+
index.insert(node.hash, idx);
168+
}
169+
}
170+
171+
// This may race with the prefetching thread, but that will set the same value.
172+
self.index[dep_kind.as_usize()].set(index).ok();
173+
}
174+
141175
#[inline]
142176
pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option<SerializedDepNodeIndex> {
143-
self.index.get(dep_node.kind.as_usize())?.get(&dep_node.hash).cloned()
177+
let index = self.index.get(dep_node.kind.as_usize())?;
178+
let index = index.get().unwrap_or_else(|| {
179+
outline(|| {
180+
self.setup_index(dep_node.kind);
181+
self.index[dep_node.kind.as_usize()].get().unwrap()
182+
})
183+
});
184+
index.get(&dep_node.hash).cloned()
144185
}
145186

146187
#[inline]
@@ -152,6 +193,31 @@ impl SerializedDepGraph {
152193
pub fn node_count(&self) -> usize {
153194
self.nodes.len()
154195
}
196+
197+
/// This spawns a thread that prefetches the index.
198+
fn prefetch(self: &Arc<Self>) {
199+
if !self.index.is_empty() {
200+
let this = self.clone();
201+
thread::spawn(move || {
202+
let _timer = this.prof.generic_activity("incr_comp_prefetch_dep_graph_index");
203+
204+
let mut index: Vec<_> = this
205+
.index_sizes
206+
.iter()
207+
.map(|&n| UnhashMap::with_capacity_and_hasher(n, Default::default()))
208+
.collect();
209+
210+
for (idx, node) in this.nodes.iter_enumerated() {
211+
index[node.kind.as_usize()].insert(node.hash, idx);
212+
}
213+
214+
for (i, index) in index.into_iter().enumerate() {
215+
// This may race with `setup_index`, but that will set the same value.
216+
this.index[i].set(index).ok();
217+
}
218+
});
219+
}
220+
}
155221
}
156222

157223
/// A packed representation of an edge's start index and byte width.
@@ -185,8 +251,8 @@ fn mask(bits: usize) -> usize {
185251
}
186252

187253
impl SerializedDepGraph {
188-
#[instrument(level = "debug", skip(d))]
189-
pub fn decode<D: Deps>(d: &mut MemDecoder<'_>) -> SerializedDepGraph {
254+
#[instrument(level = "debug", skip(d, sess))]
255+
pub fn decode<D: Deps>(d: &mut MemDecoder<'_>, sess: &Session) -> Arc<SerializedDepGraph> {
190256
// The last 16 bytes are the node count and edge count.
191257
debug!("position: {:?}", d.position());
192258
let (node_count, edge_count) =
@@ -253,16 +319,21 @@ impl SerializedDepGraph {
253319
// end of the array. This padding ensure it doesn't.
254320
edge_list_data.extend(&[0u8; DEP_NODE_PAD]);
255321

256-
// Read the number of each dep kind and use it to create an hash map with a suitable size.
257-
let mut index: Vec<_> = (0..(D::DEP_KIND_MAX + 1))
258-
.map(|_| UnhashMap::with_capacity_and_hasher(d.read_u32() as usize, Default::default()))
259-
.collect();
260-
261-
for (idx, node) in nodes.iter_enumerated() {
262-
index[node.kind.as_usize()].insert(node.hash, idx);
263-
}
264-
265-
SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data, index }
322+
// Read the number of nodes for each dep kind.
323+
let index_sizes: Vec<_> =
324+
(0..(D::DEP_KIND_MAX + 1)).map(|_| d.read_u32() as usize).collect();
325+
326+
let result = Arc::new(SerializedDepGraph {
327+
nodes,
328+
fingerprints,
329+
edge_list_indices,
330+
edge_list_data,
331+
index: (0..index_sizes.len()).map(|_| OnceLock::new()).collect(),
332+
index_sizes,
333+
prof: sess.prof.clone(),
334+
});
335+
result.prefetch();
336+
result
266337
}
267338
}
268339

0 commit comments

Comments
 (0)