Skip to content

Commit 7f48280

Browse files
incr.comp.: Clean up and optimize dep-graph loading.
1 parent 3607174 commit 7f48280

File tree

4 files changed

+116
-89
lines changed

4 files changed

+116
-89
lines changed

src/librustc_incremental/persist/data.rs

+9-12
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub struct SerializedDepGraph {
2626
/// For each DepNode, stores the list of edges originating from that
2727
/// DepNode. Encoded as a [start, end) pair indexing into edge_list_data,
2828
/// which holds the actual DepNodeIndices of the target nodes.
29-
pub edge_list_indices: Vec<(u32, u32)>,
29+
pub edge_list_indices: IndexVec<DepNodeIndex, (u32, u32)>,
3030
/// A flattened list of all edge targets in the graph. Edge sources are
3131
/// implicit in edge_list_indices.
3232
pub edge_list_data: Vec<DepNodeIndex>,
@@ -55,7 +55,14 @@ pub struct SerializedDepGraph {
5555
/// will be different when we next compile) related to each node,
5656
/// but rather the `DefPathIndex`. This can then be retraced
5757
/// to find the current def-id.
58-
pub hashes: Vec<SerializedHash>,
58+
pub hashes: Vec<(DepNodeIndex, Fingerprint)>,
59+
}
60+
61+
impl SerializedDepGraph {
62+
pub fn edge_targets_from(&self, source: DepNodeIndex) -> &[DepNodeIndex] {
63+
let targets = self.edge_list_indices[source];
64+
&self.edge_list_data[targets.0 as usize .. targets.1 as usize]
65+
}
5966
}
6067

6168
/// The index of a DepNode in the SerializedDepGraph::nodes array.
@@ -84,16 +91,6 @@ impl Idx for DepNodeIndex {
8491
}
8592
}
8693

87-
#[derive(Debug, RustcEncodable, RustcDecodable)]
88-
pub struct SerializedHash {
89-
/// def-id of thing being hashed
90-
pub dep_node: DepNode,
91-
92-
/// the hash as of previous compilation, computed by code in
93-
/// `hash` module
94-
pub hash: Fingerprint,
95-
}
96-
9794
#[derive(Debug, RustcEncodable, RustcDecodable)]
9895
pub struct SerializedWorkProduct {
9996
/// node that produced the work-product

src/librustc_incremental/persist/dirty_clean.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
//! previous revision to compare things to.
4141
//!
4242

43+
use super::data::DepNodeIndex;
4344
use super::load::DirtyNodes;
4445
use rustc::dep_graph::{DepGraphQuery, DepNode, DepKind};
4546
use rustc::hir;
@@ -50,13 +51,15 @@ use rustc::ich::{Fingerprint, ATTR_DIRTY, ATTR_CLEAN, ATTR_DIRTY_METADATA,
5051
ATTR_CLEAN_METADATA};
5152
use syntax::ast::{self, Attribute, NestedMetaItem};
5253
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
54+
use rustc_data_structures::indexed_vec::IndexVec;
5355
use syntax_pos::Span;
5456
use rustc::ty::TyCtxt;
5557

5658
const LABEL: &'static str = "label";
5759
const CFG: &'static str = "cfg";
5860

5961
pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
62+
nodes: &IndexVec<DepNodeIndex, DepNode>,
6063
dirty_inputs: &DirtyNodes) {
6164
// can't add `#[rustc_dirty]` etc without opting in to this feature
6265
if !tcx.sess.features.borrow().rustc_attrs {
@@ -66,8 +69,14 @@ pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
6669
let _ignore = tcx.dep_graph.in_ignore();
6770
let dirty_inputs: FxHashSet<DepNode> =
6871
dirty_inputs.keys()
69-
.filter(|dep_node| dep_node.extract_def_id(tcx).is_some())
70-
.cloned()
72+
.filter_map(|dep_node_index| {
73+
let dep_node = nodes[*dep_node_index];
74+
if dep_node.extract_def_id(tcx).is_some() {
75+
Some(dep_node)
76+
} else {
77+
None
78+
}
79+
})
7180
.collect();
7281

7382
let query = tcx.dep_graph.query();

src/librustc_incremental/persist/load.rs

+53-61
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ use rustc::ich::Fingerprint;
1717
use rustc::session::Session;
1818
use rustc::ty::TyCtxt;
1919
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
20+
use rustc_data_structures::indexed_vec::IndexVec;
2021
use rustc_serialize::Decodable as RustcDecodable;
2122
use rustc_serialize::opaque::Decoder;
22-
use std::default::Default;
2323
use std::path::{Path};
2424

2525
use IncrementalHashesMap;
@@ -32,7 +32,7 @@ use super::work_product;
3232

3333
// The key is a dirty node. The value is **some** base-input that we
3434
// can blame it on.
35-
pub type DirtyNodes = FxHashMap<DepNode, DepNode>;
35+
pub type DirtyNodes = FxHashMap<DepNodeIndex, DepNodeIndex>;
3636

3737
/// If we are in incremental mode, and a previous dep-graph exists,
3838
/// then load up those nodes/edges that are still valid into the
@@ -166,48 +166,35 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
166166

167167
let serialized_dep_graph = SerializedDepGraph::decode(&mut dep_graph_decoder)?;
168168

169-
let edge_map: FxHashMap<DepNode, Vec<DepNode>> = {
170-
let capacity = serialized_dep_graph.edge_list_data.len();
171-
let mut edge_map = FxHashMap::with_capacity_and_hasher(capacity, Default::default());
172-
173-
for (node_index, source) in serialized_dep_graph.nodes.iter().enumerate() {
174-
let (start, end) = serialized_dep_graph.edge_list_indices[node_index];
175-
let targets =
176-
(&serialized_dep_graph.edge_list_data[start as usize .. end as usize])
177-
.into_iter()
178-
.map(|&node_index| serialized_dep_graph.nodes[node_index].clone())
179-
.collect();
180-
181-
edge_map.insert(source.clone(), targets);
182-
}
183-
184-
edge_map
185-
};
186-
187169
// Compute the set of nodes from the old graph where some input
188-
// has changed or been removed. These are "raw" source nodes,
189-
// which means that they still use the original `DefPathIndex`
190-
// values from the encoding, rather than having been retraced to a
191-
// `DefId`. The reason for this is that this way we can include
192-
// nodes that have been removed (which no longer have a `DefId` in
193-
// the current compilation).
170+
// has changed or been removed.
194171
let dirty_raw_nodes = initial_dirty_nodes(tcx,
195172
incremental_hashes_map,
173+
&serialized_dep_graph.nodes,
196174
&serialized_dep_graph.hashes);
197-
let dirty_raw_nodes = transitive_dirty_nodes(&edge_map, dirty_raw_nodes);
175+
let dirty_raw_nodes = transitive_dirty_nodes(&serialized_dep_graph,
176+
dirty_raw_nodes);
198177

199178
// Recreate the edges in the graph that are still clean.
200179
let mut clean_work_products = FxHashSet();
201180
let mut dirty_work_products = FxHashSet(); // incomplete; just used to suppress debug output
202-
for (source, targets) in &edge_map {
203-
for target in targets {
204-
process_edge(tcx, source, target, &dirty_raw_nodes,
205-
&mut clean_work_products, &mut dirty_work_products);
181+
for (source, targets) in serialized_dep_graph.edge_list_indices.iter_enumerated() {
182+
let target_begin = targets.0 as usize;
183+
let target_end = targets.1 as usize;
184+
185+
for &target in &serialized_dep_graph.edge_list_data[target_begin .. target_end] {
186+
process_edge(tcx,
187+
source,
188+
target,
189+
&serialized_dep_graph.nodes,
190+
&dirty_raw_nodes,
191+
&mut clean_work_products,
192+
&mut dirty_work_products);
206193
}
207194
}
208195

209-
// Recreate bootstrap outputs, which are outputs that have no incoming edges (and hence cannot
210-
// be dirty).
196+
// Recreate bootstrap outputs, which are outputs that have no incoming edges
197+
// (and hence cannot be dirty).
211198
for bootstrap_output in &serialized_dep_graph.bootstrap_outputs {
212199
if let DepKind::WorkProduct = bootstrap_output.kind {
213200
let wp_id = WorkProductId::from_fingerprint(bootstrap_output.hash);
@@ -225,7 +212,9 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
225212
// dirty.
226213
reconcile_work_products(tcx, work_products, &clean_work_products);
227214

228-
dirty_clean::check_dirty_clean_annotations(tcx, &dirty_raw_nodes);
215+
dirty_clean::check_dirty_clean_annotations(tcx,
216+
&serialized_dep_graph.nodes,
217+
&dirty_raw_nodes);
229218

230219
load_prev_metadata_hashes(tcx,
231220
&mut *incremental_hashes_map.prev_metadata_hashes.borrow_mut());
@@ -236,19 +225,20 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
236225
/// a bit vector where the index is the DefPathIndex.
237226
fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
238227
incremental_hashes_map: &IncrementalHashesMap,
239-
serialized_hashes: &[SerializedHash])
228+
nodes: &IndexVec<DepNodeIndex, DepNode>,
229+
serialized_hashes: &[(DepNodeIndex, Fingerprint)])
240230
-> DirtyNodes {
241231
let mut hcx = HashContext::new(tcx, incremental_hashes_map);
242232
let mut dirty_nodes = FxHashMap();
243233

244-
for hash in serialized_hashes {
245-
let dep_node = hash.dep_node;
234+
for &(dep_node_index, prev_hash) in serialized_hashes {
235+
let dep_node = nodes[dep_node_index];
246236
if does_still_exist(tcx, &dep_node) {
247237
let current_hash = hcx.hash(&dep_node).unwrap_or_else(|| {
248238
bug!("Cannot find current ICH for input that still exists?")
249239
});
250240

251-
if current_hash == hash.hash {
241+
if current_hash == prev_hash {
252242
debug!("initial_dirty_nodes: {:?} is clean (hash={:?})",
253243
dep_node,
254244
current_hash);
@@ -259,44 +249,41 @@ fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
259249
println!("node {:?} is dirty as hash is {:?}, was {:?}",
260250
dep_node,
261251
current_hash,
262-
hash.hash);
252+
prev_hash);
263253
}
264254

265255
debug!("initial_dirty_nodes: {:?} is dirty as hash is {:?}, was {:?}",
266256
dep_node,
267257
current_hash,
268-
hash.hash);
258+
prev_hash);
269259
} else {
270260
if tcx.sess.opts.debugging_opts.incremental_dump_hash {
271261
println!("node {:?} is dirty as it was removed", dep_node);
272262
}
273263

274264
debug!("initial_dirty_nodes: {:?} is dirty as it was removed", dep_node);
275265
}
276-
277-
dirty_nodes.insert(hash.dep_node.clone(), hash.dep_node.clone());
266+
dirty_nodes.insert(dep_node_index, dep_node_index);
278267
}
279268

280269
dirty_nodes
281270
}
282271

283-
fn transitive_dirty_nodes(edge_map: &FxHashMap<DepNode, Vec<DepNode>>,
272+
fn transitive_dirty_nodes(serialized_dep_graph: &SerializedDepGraph,
284273
mut dirty_nodes: DirtyNodes)
285274
-> DirtyNodes
286275
{
287-
let mut stack: Vec<(DepNode, DepNode)> = vec![];
288-
stack.extend(dirty_nodes.iter().map(|(s, b)| (s.clone(), b.clone())));
276+
let mut stack: Vec<(DepNodeIndex, DepNodeIndex)> = vec![];
277+
stack.extend(dirty_nodes.iter().map(|(&s, &b)| (s, b)));
289278
while let Some((source, blame)) = stack.pop() {
290279
// we know the source is dirty (because of the node `blame`)...
291-
assert!(dirty_nodes.contains_key(&source));
280+
debug_assert!(dirty_nodes.contains_key(&source));
292281

293282
// ...so we dirty all the targets (with the same blame)
294-
if let Some(targets) = edge_map.get(&source) {
295-
for target in targets {
296-
if !dirty_nodes.contains_key(target) {
297-
dirty_nodes.insert(target.clone(), blame.clone());
298-
stack.push((target.clone(), blame.clone()));
299-
}
283+
for &target in serialized_dep_graph.edge_targets_from(source) {
284+
if !dirty_nodes.contains_key(&target) {
285+
dirty_nodes.insert(target, blame);
286+
stack.push((target, blame));
300287
}
301288
}
302289
}
@@ -402,16 +389,18 @@ fn load_prev_metadata_hashes(tcx: TyCtxt,
402389

403390
fn process_edge<'a, 'tcx, 'edges>(
404391
tcx: TyCtxt<'a, 'tcx, 'tcx>,
405-
source: &'edges DepNode,
406-
target: &'edges DepNode,
392+
source: DepNodeIndex,
393+
target: DepNodeIndex,
394+
nodes: &IndexVec<DepNodeIndex, DepNode>,
407395
dirty_raw_nodes: &DirtyNodes,
408396
clean_work_products: &mut FxHashSet<WorkProductId>,
409397
dirty_work_products: &mut FxHashSet<WorkProductId>)
410398
{
411399
// If the target is dirty, skip the edge. If this is an edge
412400
// that targets a work-product, we can print the blame
413401
// information now.
414-
if let Some(blame) = dirty_raw_nodes.get(target) {
402+
if let Some(&blame) = dirty_raw_nodes.get(&target) {
403+
let target = nodes[target];
415404
if let DepKind::WorkProduct = target.kind {
416405
if tcx.sess.opts.debugging_opts.incremental_info {
417406
let wp_id = WorkProductId::from_fingerprint(target.hash);
@@ -420,6 +409,7 @@ fn process_edge<'a, 'tcx, 'edges>(
420409
// Try to reconstruct the human-readable version of the
421410
// DepNode. This cannot be done for things that where
422411
// removed.
412+
let blame = nodes[blame];
423413
let blame_str = if let Some(def_id) = blame.extract_def_id(tcx) {
424414
format!("{:?}({})",
425415
blame.kind,
@@ -444,21 +434,23 @@ fn process_edge<'a, 'tcx, 'edges>(
444434

445435
// We should never have an edge where the target is clean but the source
446436
// was dirty. Otherwise something was wrong with the dirtying pass above:
447-
debug_assert!(!dirty_raw_nodes.contains_key(source));
437+
debug_assert!(!dirty_raw_nodes.contains_key(&source));
448438

449439
// We also never should encounter an edge going from a removed input to a
450440
// clean target because removing the input would have dirtied the input
451441
// node and transitively dirtied the target.
452-
debug_assert!(match source.kind {
442+
debug_assert!(match nodes[source].kind {
453443
DepKind::Hir | DepKind::HirBody | DepKind::MetaData => {
454-
does_still_exist(tcx, source)
444+
does_still_exist(tcx, &nodes[source])
455445
}
456446
_ => true,
457447
});
458448

459-
if !dirty_raw_nodes.contains_key(target) {
460-
let _task = tcx.dep_graph.in_task(*target);
461-
tcx.dep_graph.read(*source);
449+
if !dirty_raw_nodes.contains_key(&target) {
450+
let target = nodes[target];
451+
let source = nodes[source];
452+
let _task = tcx.dep_graph.in_task(target);
453+
tcx.dep_graph.read(source);
462454

463455
if let DepKind::WorkProduct = target.kind {
464456
let wp_id = WorkProductId::from_fingerprint(target.hash);

0 commit comments

Comments
 (0)