Skip to content

Commit

Permalink
incr.comp.: Use a more efficient encoding for the on-disk dependency …
Browse files Browse the repository at this point in the history
…graph.
  • Loading branch information
michaelwoerister committed Jun 1, 2017
1 parent 0cbb8b5 commit a3417bf
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 58 deletions.
41 changes: 34 additions & 7 deletions src/librustc_incremental/persist/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,20 @@ use rustc::ich::Fingerprint;
use rustc::middle::cstore::EncodedMetadataHash;
use std::sync::Arc;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::{IndexVec, Idx};

/// Data for use when recompiling the **current crate**.
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct SerializedDepGraph {
pub edges: Vec<SerializedEdgeSet>,
/// The set of all DepNodes in the graph
pub nodes: IndexVec<DepNodeIndex, DepNode<DefPathHash>>,
/// For each DepNode, stores the list of edges originating from that
/// DepNode. Encoded as a [start, end) pair indexing into edge_list_data,
/// which holds the actual DepNodeIndices of the target nodes.
pub edge_list_indices: Vec<(u32, u32)>,
/// A flattened list of all edge targets in the graph. Edge sources are
/// implicit in edge_list_indices.
pub edge_list_data: Vec<DepNodeIndex>,

/// These are output nodes that have no incoming edges. We track
/// these separately so that when we reload all edges, we don't
Expand Down Expand Up @@ -50,12 +59,30 @@ pub struct SerializedDepGraph {
pub hashes: Vec<SerializedHash>,
}

/// Represents a set of "reduced" dependency edge. We group the
/// outgoing edges from a single source together.
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct SerializedEdgeSet {
pub source: DepNode<DefPathHash>,
pub targets: Vec<DepNode<DefPathHash>>
/// The index of a DepNode in the SerializedDepGraph::nodes array.
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug,
RustcEncodable, RustcDecodable)]
pub struct DepNodeIndex(pub u32);

impl DepNodeIndex {
#[inline]
pub fn new(idx: usize) -> DepNodeIndex {
assert!(idx <= ::std::u32::MAX as usize);
DepNodeIndex(idx as u32)
}
}

impl Idx for DepNodeIndex {
#[inline]
fn new(idx: usize) -> Self {
assert!(idx <= ::std::u32::MAX as usize);
DepNodeIndex(idx as u32)
}

#[inline]
fn index(self) -> usize {
self.0 as usize
}
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
Expand Down
22 changes: 18 additions & 4 deletions src/librustc_incremental/persist/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use rustc::ty::TyCtxt;
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
use rustc_serialize::Decodable as RustcDecodable;
use rustc_serialize::opaque::Decoder;
use std::default::Default;
use std::path::{Path};
use std::sync::Arc;

Expand Down Expand Up @@ -161,10 +162,23 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,

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

let edge_map: FxHashMap<_, _> = serialized_dep_graph.edges
.into_iter()
.map(|s| (s.source, s.targets))
.collect();
let edge_map: FxHashMap<DepNode<DefPathHash>, Vec<DepNode<DefPathHash>>> = {
let capacity = serialized_dep_graph.edge_list_data.len();
let mut edge_map = FxHashMap::with_capacity_and_hasher(capacity, Default::default());

for (node_index, source) in serialized_dep_graph.nodes.iter().enumerate() {
let (start, end) = serialized_dep_graph.edge_list_indices[node_index];
let targets =
(&serialized_dep_graph.edge_list_data[start as usize .. end as usize])
.into_iter()
.map(|&node_index| serialized_dep_graph.nodes[node_index].clone())
.collect();

edge_map.insert(source.clone(), targets);
}

edge_map
};

// Compute the set of nodes from the old graph where some input
// has changed or been removed. These are "raw" source nodes,
Expand Down
105 changes: 58 additions & 47 deletions src/librustc_incremental/persist/save.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@
use rustc::dep_graph::DepNode;
use rustc::hir::def_id::DefId;
use rustc::hir::svh::Svh;
use rustc::hir::map::DefPathHash;
use rustc::ich::Fingerprint;
use rustc::middle::cstore::EncodedMetadataHashes;
use rustc::session::Session;
use rustc::ty::TyCtxt;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::graph;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_serialize::Encodable as RustcEncodable;
use rustc_serialize::opaque::Encoder;
use std::io::{self, Cursor, Write};
Expand Down Expand Up @@ -175,65 +178,73 @@ pub fn encode_dep_graph(tcx: TyCtxt,
dep_node.map_def(|&def_id| Some(tcx.def_path_hash(def_id))).unwrap()
};

// Create a flat list of (Input, WorkProduct) edges for
// serialization.
let mut edges = FxHashMap();
for edge in preds.reduced_graph.all_edges() {
let source = *preds.reduced_graph.node_data(edge.source());
let target = *preds.reduced_graph.node_data(edge.target());
match *target {
DepNode::MetaData(ref def_id) => {
// Metadata *targets* are always local metadata nodes. We have
// already handled those in `encode_metadata_hashes`.
assert!(def_id.is_local());
continue;
}
_ => (),
}
debug!("serialize edge: {:?} -> {:?}", source, target);
let source = to_hash_based_node(source);
let target = to_hash_based_node(target);
edges.entry(source).or_insert(vec![]).push(target);
}
// NB: We rely on this Vec being indexable by reduced_graph's NodeIndex.
let nodes: IndexVec<DepNodeIndex, DepNode<DefPathHash>> = preds
.reduced_graph
.all_nodes()
.iter()
.map(|node| to_hash_based_node(node.data))
.collect();

if tcx.sess.opts.debugging_opts.incremental_dump_hash {
for (dep_node, hash) in &preds.hashes {
println!("HIR hash for {:?} is {}", dep_node, hash);
let mut edge_list_indices = Vec::with_capacity(nodes.len());
let mut edge_list_data = Vec::with_capacity(preds.reduced_graph.len_edges());

for node_index in 0 .. nodes.len() {
let start = edge_list_data.len() as u32;

for target in preds.reduced_graph.successor_nodes(graph::NodeIndex(node_index)) {
edge_list_data.push(DepNodeIndex::new(target.node_id()));
}

let end = edge_list_data.len() as u32;
debug_assert_eq!(node_index, edge_list_indices.len());
edge_list_indices.push((start, end));
}

// Create the serialized dep-graph.
let bootstrap_outputs = preds.bootstrap_outputs
.iter()
.map(|n| to_hash_based_node(n))
.collect();
let edges = edges.into_iter()
.map(|(k, v)| SerializedEdgeSet { source: k, targets: v })
.collect();
// Let's make we had no overflow there.
assert!(edge_list_data.len() <= ::std::u32::MAX as usize);
// Check that we have a consistent number of edges.
assert_eq!(edge_list_data.len(), preds.reduced_graph.len_edges());

let bootstrap_outputs = preds
.bootstrap_outputs
.iter()
.map(|n| to_hash_based_node(n))
.collect();

let hashes = preds
.hashes
.iter()
.map(|(&dep_node, &hash)| {
SerializedHash {
dep_node: to_hash_based_node(dep_node),
hash: hash,
}
})
.collect();

let graph = SerializedDepGraph {
nodes,
edge_list_indices,
edge_list_data,
bootstrap_outputs,
edges,
hashes: preds.hashes
.iter()
.map(|(&dep_node, &hash)| {
SerializedHash {
dep_node: to_hash_based_node(dep_node),
hash: hash,
}
})
.collect(),
hashes,
};

// Encode the graph data.
graph.encode(encoder)?;

if tcx.sess.opts.debugging_opts.incremental_info {
println!("incremental: {} nodes in reduced dep-graph", preds.reduced_graph.len_nodes());
println!("incremental: {} edges in serialized dep-graph", graph.edges.len());
println!("incremental: {} nodes in reduced dep-graph", graph.nodes.len());
println!("incremental: {} edges in serialized dep-graph", graph.edge_list_data.len());
println!("incremental: {} hashes in serialized dep-graph", graph.hashes.len());
}

debug!("graph = {:#?}", graph);

// Encode the graph data.
graph.encode(encoder)?;
if tcx.sess.opts.debugging_opts.incremental_dump_hash {
for (dep_node, hash) in &preds.hashes {
println!("ICH for {:?} is {}", dep_node, hash);
}
}

Ok(())
}
Expand Down

0 comments on commit a3417bf

Please sign in to comment.