Skip to content

Commit d99efc8

Browse files
committed
Create the previous dep graph index on a background thread
1 parent d3c9082 commit d99efc8

File tree

4 files changed

+121
-22
lines changed

4 files changed

+121
-22
lines changed

compiler/rustc_incremental/src/persist/load.rs

+3-2
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;
@@ -88,7 +89,7 @@ fn delete_dirty_work_product(sess: &Session, swp: SerializedWorkProduct) {
8889
work_product::delete_workproduct_files(sess, &swp.work_product);
8990
}
9091

91-
fn load_dep_graph(sess: &Session) -> LoadResult<(SerializedDepGraph, WorkProductMap)> {
92+
fn load_dep_graph(sess: &Session) -> LoadResult<(Arc<SerializedDepGraph>, WorkProductMap)> {
9293
let prof = sess.prof.clone();
9394

9495
if sess.opts.incremental.is_none() {
@@ -161,7 +162,7 @@ fn load_dep_graph(sess: &Session) -> LoadResult<(SerializedDepGraph, WorkProduct
161162
return LoadResult::DataOutOfDate;
162163
}
163164

164-
let dep_graph = SerializedDepGraph::decode::<DepsType>(&mut decoder);
165+
let dep_graph = SerializedDepGraph::decode::<DepsType>(&mut decoder, sess);
165166

166167
LoadResult::Ok { data: (dep_graph, prev_work_products) }
167168
}

compiler/rustc_incremental/src/persist/save.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
1010
use rustc_serialize::Encodable as RustcEncodable;
1111
use rustc_session::Session;
1212
use std::fs;
13+
use std::sync::Arc;
1314

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

compiler/rustc_query_system/src/dep_graph/graph.rs

+3-2
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;
17+
use std::sync::Arc;
1718

1819
use super::query::DepGraphQuery;
1920
use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex};
@@ -82,7 +83,7 @@ pub(crate) struct DepGraphData<D: Deps> {
8283

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

8788
colors: DepNodeColorMap,
8889

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

compiler/rustc_query_system/src/dep_graph/serialized.rs

+113-17
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,14 @@ use rustc_data_structures::fx::FxHashMap;
4444
use rustc_data_structures::profiling::SelfProfilerRef;
4545
use rustc_data_structures::sync::Lock;
4646
use rustc_data_structures::unhash::UnhashMap;
47+
use rustc_data_structures::{jobserver, outline};
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`,
@@ -70,23 +73,47 @@ const DEP_NODE_PAD: usize = DEP_NODE_SIZE - 1;
7073
const DEP_NODE_WIDTH_BITS: usize = DEP_NODE_SIZE / 2;
7174

7275
/// Data for use when recompiling the **current crate**.
73-
#[derive(Debug, Default)]
7476
pub struct SerializedDepGraph {
7577
/// The set of all DepNodes in the graph
7678
nodes: IndexVec<SerializedDepNodeIndex, DepNode>,
79+
7780
/// The set of all Fingerprints in the graph. Each Fingerprint corresponds to
7881
/// the DepNode at the same index in the nodes vector.
7982
fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>,
83+
8084
/// For each DepNode, stores the list of edges originating from that
8185
/// DepNode. Encoded as a [start, end) pair indexing into edge_list_data,
8286
/// which holds the actual DepNodeIndices of the target nodes.
8387
edge_list_indices: IndexVec<SerializedDepNodeIndex, EdgeHeader>,
88+
8489
/// A flattened list of all edge targets in the graph, stored in the same
8590
/// varint encoding that we use on disk. Edge sources are implicit in edge_list_indices.
8691
edge_list_data: Vec<u8>,
92+
8793
/// Stores a map from fingerprints to nodes per dep node kind.
88-
/// This is the reciprocal of `nodes`.
89-
index: Vec<UnhashMap<PackedFingerprint, SerializedDepNodeIndex>>,
94+
/// This is the reciprocal of `nodes`. This is computed on demand for each dep kind.
95+
/// The entire index is also computed in a background thread.
96+
index: Vec<OnceLock<UnhashMap<PackedFingerprint, SerializedDepNodeIndex>>>,
97+
98+
/// Stores the number of node for each dep node kind.
99+
index_sizes: Vec<usize>,
100+
101+
/// A profiler reference for used in the index prefetching thread.
102+
prof: SelfProfilerRef,
103+
}
104+
105+
impl Default for SerializedDepGraph {
106+
fn default() -> Self {
107+
SerializedDepGraph {
108+
nodes: Default::default(),
109+
fingerprints: Default::default(),
110+
edge_list_indices: Default::default(),
111+
edge_list_data: Default::default(),
112+
index: Default::default(),
113+
index_sizes: Default::default(),
114+
prof: SelfProfilerRef::new(None, None),
115+
}
116+
}
90117
}
91118

92119
impl SerializedDepGraph {
@@ -127,9 +154,35 @@ impl SerializedDepGraph {
127154
self.nodes[dep_node_index]
128155
}
129156

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

135188
#[inline]
@@ -141,6 +194,44 @@ impl SerializedDepGraph {
141194
pub fn node_count(&self) -> usize {
142195
self.nodes.len()
143196
}
197+
198+
fn prefetch(&self) {
199+
let _timer = self.prof.generic_activity("incr_comp_prefetch_dep_graph_index");
200+
201+
let mut index: Vec<_> = self
202+
.index_sizes
203+
.iter()
204+
.map(|&n| UnhashMap::with_capacity_and_hasher(n, Default::default()))
205+
.collect();
206+
207+
for (idx, node) in self.nodes.iter_enumerated() {
208+
index[node.kind.as_usize()].insert(node.hash, idx);
209+
}
210+
211+
for (i, index) in index.into_iter().enumerate() {
212+
// This may race with `setup_index`, but that will set the same value.
213+
self.index[i].set(index).ok();
214+
}
215+
}
216+
217+
/// This spawns a thread that prefetches the index.
218+
fn spawn_prefetch_thread(self: &Arc<Self>) {
219+
if !self.index.is_empty() {
220+
let client = jobserver::client();
221+
if let Ok(true) = client.available().map(|tokens| tokens > 0) {
222+
if let Ok(token) = client.acquire() {
223+
let this = self.clone();
224+
thread::spawn(move || {
225+
this.prefetch();
226+
});
227+
return;
228+
}
229+
}
230+
231+
// Prefetch the index on the current thread if we don't have a token available.
232+
self.prefetch();
233+
}
234+
}
144235
}
145236

146237
/// A packed representation of an edge's start index and byte width.
@@ -175,8 +266,8 @@ fn mask(bits: usize) -> usize {
175266
}
176267

177268
impl SerializedDepGraph {
178-
#[instrument(level = "debug", skip(d))]
179-
pub fn decode<D: Deps>(d: &mut MemDecoder<'_>) -> SerializedDepGraph {
269+
#[instrument(level = "debug", skip(d, sess))]
270+
pub fn decode<D: Deps>(d: &mut MemDecoder<'_>, sess: &Session) -> Arc<SerializedDepGraph> {
180271
// The last 16 bytes are the node count and edge count.
181272
debug!("position: {:?}", d.position());
182273
let (node_count, edge_count) =
@@ -243,16 +334,21 @@ impl SerializedDepGraph {
243334
// end of the array. This padding ensure it doesn't.
244335
edge_list_data.extend(&[0u8; DEP_NODE_PAD]);
245336

246-
// Read the number of each dep kind and use it to create an hash map with a suitable size.
247-
let mut index: Vec<_> = (0..(D::DEP_KIND_MAX + 1))
248-
.map(|_| UnhashMap::with_capacity_and_hasher(d.read_u32() as usize, Default::default()))
249-
.collect();
250-
251-
for (idx, node) in nodes.iter_enumerated() {
252-
index[node.kind.as_usize()].insert(node.hash, idx);
253-
}
254-
255-
SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data, index }
337+
// Read the number of nodes for each dep kind.
338+
let index_sizes: Vec<_> =
339+
(0..(D::DEP_KIND_MAX + 1)).map(|_| d.read_u32() as usize).collect();
340+
341+
let result = Arc::new(SerializedDepGraph {
342+
nodes,
343+
fingerprints,
344+
edge_list_indices,
345+
edge_list_data,
346+
index: (0..index_sizes.len()).map(|_| OnceLock::new()).collect(),
347+
index_sizes,
348+
prof: sess.prof.clone(),
349+
});
350+
result.prefetch();
351+
result
256352
}
257353
}
258354

0 commit comments

Comments
 (0)