Skip to content

Commit ef9ae85

Browse files
committed
make dirty process O(dirty)
The old algorithm was O(graph)
1 parent d848f1d commit ef9ae85

File tree

3 files changed

+66
-50
lines changed

3 files changed

+66
-50
lines changed

src/librustc_incremental/persist/data.rs

+8-9
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use super::directory::DefPathIndex;
2121
/// Data for use when recompiling the **current crate**.
2222
#[derive(Debug, RustcEncodable, RustcDecodable)]
2323
pub struct SerializedDepGraph {
24-
pub edges: Vec<SerializedEdge>,
24+
pub edges: Vec<SerializedEdgeSet>,
2525

2626
/// These are hashes of two things:
2727
/// - the HIR nodes in this crate
@@ -45,14 +45,13 @@ pub struct SerializedDepGraph {
4545
pub hashes: Vec<SerializedHash>,
4646
}
4747

48-
/// Represents a "reduced" dependency edge. Unlike the full dep-graph,
49-
/// the dep-graph we serialize contains only edges `S -> T` where the
50-
/// source `S` is something hashable (a HIR node or foreign metadata)
51-
/// and the target `T` is something significant, like a work-product.
52-
/// Normally, significant nodes are only those that have saved data on
53-
/// disk, but in unit-testing the set of significant nodes can be
54-
/// increased.
55-
pub type SerializedEdge = (DepNode<DefPathIndex>, DepNode<DefPathIndex>);
48+
/// Represents a set of "reduced" dependency edge. We group the
49+
/// outgoing edges from a single source together.
50+
#[derive(Debug, RustcEncodable, RustcDecodable)]
51+
pub struct SerializedEdgeSet {
52+
pub source: DepNode<DefPathIndex>,
53+
pub targets: Vec<DepNode<DefPathIndex>>
54+
}
5655

5756
#[derive(Debug, RustcEncodable, RustcDecodable)]
5857
pub struct SerializedHash {

src/librustc_incremental/persist/load.rs

+53-39
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,11 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
152152
let directory = DefIdDirectory::decode(&mut dep_graph_decoder)?;
153153
let serialized_dep_graph = SerializedDepGraph::decode(&mut dep_graph_decoder)?;
154154

155+
let edge_map: FxHashMap<_, _> = serialized_dep_graph.edges
156+
.into_iter()
157+
.map(|s| (s.source, s.targets))
158+
.collect();
159+
155160
// Retrace the paths in the directory to find their current location (if any).
156161
let retraced = directory.retrace(tcx);
157162

@@ -166,46 +171,48 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
166171
incremental_hashes_map,
167172
&serialized_dep_graph.hashes,
168173
&retraced);
169-
let dirty_raw_nodes = transitive_dirty_nodes(&serialized_dep_graph.edges, dirty_raw_nodes);
174+
let dirty_raw_nodes = transitive_dirty_nodes(&edge_map, dirty_raw_nodes);
170175

171176
// Recreate the edges in the graph that are still clean.
172177
let mut clean_work_products = FxHashSet();
173178
let mut dirty_work_products = FxHashSet(); // incomplete; just used to suppress debug output
174-
for edge in &serialized_dep_graph.edges {
175-
// If the target is dirty, skip the edge. If this is an edge
176-
// that targets a work-product, we can print the blame
177-
// information now.
178-
if let Some(blame) = dirty_raw_nodes.get(&edge.1) {
179-
if let DepNode::WorkProduct(ref wp) = edge.1 {
180-
if tcx.sess.opts.debugging_opts.incremental_info {
181-
if dirty_work_products.insert(wp.clone()) {
182-
// It'd be nice to pretty-print these paths better than just
183-
// using the `Debug` impls, but wev.
184-
println!("incremental: module {:?} is dirty because {:?} \
185-
changed or was removed",
186-
wp,
187-
blame.map_def(|&index| {
188-
Some(directory.def_path_string(tcx, index))
189-
}).unwrap());
179+
for (source, targets) in &edge_map {
180+
for target in targets {
181+
// If the target is dirty, skip the edge. If this is an edge
182+
// that targets a work-product, we can print the blame
183+
// information now.
184+
if let Some(blame) = dirty_raw_nodes.get(target) {
185+
if let DepNode::WorkProduct(ref wp) = *target {
186+
if tcx.sess.opts.debugging_opts.incremental_info {
187+
if dirty_work_products.insert(wp.clone()) {
188+
// It'd be nice to pretty-print these paths better than just
189+
// using the `Debug` impls, but wev.
190+
println!("incremental: module {:?} is dirty because {:?} \
191+
changed or was removed",
192+
wp,
193+
blame.map_def(|&index| {
194+
Some(directory.def_path_string(tcx, index))
195+
}).unwrap());
196+
}
190197
}
191198
}
199+
continue;
192200
}
193-
continue;
194-
}
195201

196-
// If the source is dirty, the target will be dirty.
197-
assert!(!dirty_raw_nodes.contains_key(&edge.0));
198-
199-
// Retrace the source -> target edges to def-ids and then
200-
// create an edge in the graph. Retracing may yield none if
201-
// some of the data happens to have been removed; this ought
202-
// to be impossible unless it is dirty, so we can unwrap.
203-
let source_node = retraced.map(&edge.0).unwrap();
204-
let target_node = retraced.map(&edge.1).unwrap();
205-
let _task = tcx.dep_graph.in_task(target_node);
206-
tcx.dep_graph.read(source_node);
207-
if let DepNode::WorkProduct(ref wp) = edge.1 {
208-
clean_work_products.insert(wp.clone());
202+
// If the source is dirty, the target will be dirty.
203+
assert!(!dirty_raw_nodes.contains_key(source));
204+
205+
// Retrace the source -> target edges to def-ids and then
206+
// create an edge in the graph. Retracing may yield none if
207+
// some of the data happens to have been removed; this ought
208+
// to be impossible unless it is dirty, so we can unwrap.
209+
let source_node = retraced.map(source).unwrap();
210+
let target_node = retraced.map(target).unwrap();
211+
let _task = tcx.dep_graph.in_task(target_node);
212+
tcx.dep_graph.read(source_node);
213+
if let DepNode::WorkProduct(ref wp) = *target {
214+
clean_work_products.insert(wp.clone());
215+
}
209216
}
210217
}
211218

@@ -268,16 +275,23 @@ fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
268275
dirty_nodes
269276
}
270277

271-
fn transitive_dirty_nodes(edges: &[SerializedEdge],
278+
fn transitive_dirty_nodes(edge_map: &FxHashMap<DepNode<DefPathIndex>, Vec<DepNode<DefPathIndex>>>,
272279
mut dirty_nodes: DirtyNodes)
273280
-> DirtyNodes
274281
{
275-
let mut len = 0;
276-
while len != dirty_nodes.len() {
277-
len = dirty_nodes.len();
278-
for edge in edges {
279-
if let Some(n) = dirty_nodes.get(&edge.0).cloned() {
280-
dirty_nodes.insert(edge.1.clone(), n);
282+
let mut stack: Vec<(DepNode<DefPathIndex>, DepNode<DefPathIndex>)> = vec![];
283+
stack.extend(dirty_nodes.iter().map(|(s, b)| (s.clone(), b.clone())));
284+
while let Some((source, blame)) = stack.pop() {
285+
// we know the source is dirty (because of the node `blame`)...
286+
assert!(dirty_nodes.contains_key(&source));
287+
288+
// ...so we dirty all the targets (with the same blame)
289+
if let Some(targets) = edge_map.get(&source) {
290+
for target in targets {
291+
if !dirty_nodes.contains_key(target) {
292+
dirty_nodes.insert(target.clone(), blame.clone());
293+
stack.push((target.clone(), blame.clone()));
294+
}
281295
}
282296
}
283297
}

src/librustc_incremental/persist/save.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ pub fn encode_dep_graph(preds: &Predecessors,
178178

179179
// Create a flat list of (Input, WorkProduct) edges for
180180
// serialization.
181-
let mut edges = vec![];
181+
let mut edges = FxHashMap();
182182
for edge in preds.reduced_graph.all_edges() {
183183
let source = *preds.reduced_graph.node_data(edge.source());
184184
let target = *preds.reduced_graph.node_data(edge.target());
@@ -194,7 +194,7 @@ pub fn encode_dep_graph(preds: &Predecessors,
194194
debug!("serialize edge: {:?} -> {:?}", source, target);
195195
let source = builder.map(source);
196196
let target = builder.map(target);
197-
edges.push((source, target));
197+
edges.entry(source).or_insert(vec![]).push(target);
198198
}
199199

200200
if tcx.sess.opts.debugging_opts.incremental_dump_hash {
@@ -204,6 +204,9 @@ pub fn encode_dep_graph(preds: &Predecessors,
204204
}
205205

206206
// Create the serialized dep-graph.
207+
let edges = edges.into_iter()
208+
.map(|(k, v)| SerializedEdgeSet { source: k, targets: v })
209+
.collect();
207210
let graph = SerializedDepGraph {
208211
edges: edges,
209212
hashes: preds.hashes

0 commit comments

Comments
 (0)