Skip to content

Commit 26c5129

Browse files
committed
Create the previous dep graph index on a background thread
1 parent 93257e2 commit 26c5129

File tree

2 files changed

+113
-21
lines changed

2 files changed

+113
-21
lines changed

compiler/rustc_incremental/src/persist/load.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ fn load_dep_graph(sess: &Session) -> LoadResult<(Arc<SerializedDepGraph>, WorkPr
171171
return LoadResult::DataOutOfDate;
172172
}
173173

174-
let dep_graph = SerializedDepGraph::decode::<DepsType>(&mut decoder);
174+
let dep_graph = SerializedDepGraph::decode::<DepsType>(&mut decoder, sess);
175175

176176
LoadResult::Ok { data: (dep_graph, prev_work_products) }
177177
}

compiler/rustc_query_system/src/dep_graph/serialized.rs

+112-20
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,20 @@
3535
//! If the number of edges in this node does not fit in the bits available in the header, we
3636
//! store it directly after the header with leb128.
3737
38-
use std::iter;
3938
use std::marker::PhantomData;
40-
use std::sync::Arc;
39+
use std::sync::{Arc, OnceLock};
40+
use std::{iter, thread};
4141

4242
use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint};
4343
use rustc_data_structures::fx::FxHashMap;
44-
use rustc_data_structures::outline;
4544
use rustc_data_structures::profiling::SelfProfilerRef;
4645
use rustc_data_structures::sync::Lock;
4746
use rustc_data_structures::unhash::UnhashMap;
47+
use rustc_data_structures::{jobserver, outline};
4848
use rustc_index::{Idx, IndexVec};
4949
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder};
5050
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
51+
use rustc_session::Session;
5152
use tracing::{debug, instrument};
5253

5354
use super::query::DepGraphQuery;
@@ -74,23 +75,47 @@ const DEP_NODE_PAD: usize = DEP_NODE_SIZE - 1;
7475
const DEP_NODE_WIDTH_BITS: usize = DEP_NODE_SIZE / 2;
7576

7677
/// Data for use when recompiling the **current crate**.
77-
#[derive(Debug, Default)]
7878
pub struct SerializedDepGraph {
7979
/// The set of all DepNodes in the graph
8080
nodes: IndexVec<SerializedDepNodeIndex, DepNode>,
81+
8182
/// The set of all Fingerprints in the graph. Each Fingerprint corresponds to
8283
/// the DepNode at the same index in the nodes vector.
8384
fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>,
85+
8486
/// For each DepNode, stores the list of edges originating from that
8587
/// DepNode. Encoded as a [start, end) pair indexing into edge_list_data,
8688
/// which holds the actual DepNodeIndices of the target nodes.
8789
edge_list_indices: IndexVec<SerializedDepNodeIndex, EdgeHeader>,
90+
8891
/// A flattened list of all edge targets in the graph, stored in the same
8992
/// varint encoding that we use on disk. Edge sources are implicit in edge_list_indices.
9093
edge_list_data: Vec<u8>,
94+
9195
/// Stores a map from fingerprints to nodes per dep node kind.
92-
/// This is the reciprocal of `nodes`.
93-
index: Vec<UnhashMap<PackedFingerprint, SerializedDepNodeIndex>>,
96+
/// This is the reciprocal of `nodes`. This is computed on demand for each dep kind.
97+
/// The entire index is also computed in a background thread.
98+
index: Vec<OnceLock<UnhashMap<PackedFingerprint, SerializedDepNodeIndex>>>,
99+
100+
/// Stores the number of node for each dep node kind.
101+
index_sizes: Vec<usize>,
102+
103+
/// A profiler reference for used in the index prefetching thread.
104+
prof: SelfProfilerRef,
105+
}
106+
107+
impl Default for SerializedDepGraph {
108+
fn default() -> Self {
109+
SerializedDepGraph {
110+
nodes: Default::default(),
111+
fingerprints: Default::default(),
112+
edge_list_indices: Default::default(),
113+
edge_list_data: Default::default(),
114+
index: Default::default(),
115+
index_sizes: Default::default(),
116+
prof: SelfProfilerRef::new(None, None),
117+
}
118+
}
94119
}
95120

96121
impl SerializedDepGraph {
@@ -131,9 +156,35 @@ impl SerializedDepGraph {
131156
self.nodes[dep_node_index]
132157
}
133158

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

139190
#[inline]
@@ -145,6 +196,48 @@ impl SerializedDepGraph {
145196
pub fn node_count(&self) -> usize {
146197
self.nodes.len()
147198
}
199+
200+
fn prefetch(&self) {
201+
let _timer = self.prof.generic_activity("incr_comp_prefetch_dep_graph_index");
202+
203+
let mut index: Vec<_> = self
204+
.index_sizes
205+
.iter()
206+
.map(|&n| UnhashMap::with_capacity_and_hasher(n, Default::default()))
207+
.collect();
208+
209+
// Use a single loop to build indices for all kinds, unlike `setup_index` which builds
210+
// a single index for each loop over the nodes.
211+
for (idx, node) in self.nodes.iter_enumerated() {
212+
index[node.kind.as_usize()].insert(node.hash, idx);
213+
}
214+
215+
for (i, index) in index.into_iter().enumerate() {
216+
// This may race with `setup_index`, but that will set the same value.
217+
self.index[i].set(index).ok();
218+
}
219+
}
220+
221+
/// This spawns a thread that prefetches the index.
222+
fn spawn_prefetch_thread(self: &Arc<Self>) {
223+
if !self.index.is_empty() {
224+
let client = jobserver::client();
225+
// This should ideally use `try_acquire` to avoid races on the tokens,
226+
// but the jobserver crate doesn't support that operation.
227+
if let Ok(tokens) = client.available()
228+
&& tokens > 0
229+
{
230+
let this = self.clone();
231+
thread::spawn(move || {
232+
let _token = client.acquire();
233+
this.prefetch();
234+
});
235+
} else {
236+
// Prefetch the index on the current thread if we don't have a token available.
237+
self.prefetch();
238+
}
239+
}
240+
}
148241
}
149242

150243
/// A packed representation of an edge's start index and byte width.
@@ -179,8 +272,8 @@ fn mask(bits: usize) -> usize {
179272
}
180273

181274
impl SerializedDepGraph {
182-
#[instrument(level = "debug", skip(d))]
183-
pub fn decode<D: Deps>(d: &mut MemDecoder<'_>) -> Arc<SerializedDepGraph> {
275+
#[instrument(level = "debug", skip(d, sess))]
276+
pub fn decode<D: Deps>(d: &mut MemDecoder<'_>, sess: &Session) -> Arc<SerializedDepGraph> {
184277
// The last 16 bytes are the node count and edge count.
185278
debug!("position: {:?}", d.position());
186279
let (node_count, edge_count) =
@@ -246,22 +339,21 @@ impl SerializedDepGraph {
246339
// end of the array. This padding ensure it doesn't.
247340
edge_list_data.extend(&[0u8; DEP_NODE_PAD]);
248341

249-
// Read the number of each dep kind and use it to create an hash map with a suitable size.
250-
let mut index: Vec<_> = (0..(D::DEP_KIND_MAX + 1))
251-
.map(|_| UnhashMap::with_capacity_and_hasher(d.read_u32() as usize, Default::default()))
252-
.collect();
342+
// Read the number of nodes for each dep kind.
343+
let index_sizes: Vec<_> =
344+
(0..(D::DEP_KIND_MAX + 1)).map(|_| d.read_u32() as usize).collect();
253345

254-
for (idx, node) in nodes.iter_enumerated() {
255-
index[node.kind.as_usize()].insert(node.hash, idx);
256-
}
257-
258-
Arc::new(SerializedDepGraph {
346+
let result = Arc::new(SerializedDepGraph {
259347
nodes,
260348
fingerprints,
261349
edge_list_indices,
262350
edge_list_data,
263-
index,
264-
})
351+
index: (0..index_sizes.len()).map(|_| OnceLock::new()).collect(),
352+
index_sizes,
353+
prof: sess.prof.clone(),
354+
});
355+
result.spawn_prefetch_thread();
356+
result
265357
}
266358
}
267359

0 commit comments

Comments
 (0)