mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-15 21:47:04 +00:00
incr.comp.: Initial implemenation of append-only dep-graph.
This commit is contained in:
parent
a83c3e7771
commit
fecd92a7fe
@ -17,7 +17,7 @@ use std::mem;
|
||||
use super::{DepGraphQuery, DepKind, DepNode};
|
||||
use super::debug::EdgeFilter;
|
||||
|
||||
pub struct DepGraphEdges {
|
||||
pub(super) struct DepGraphEdges {
|
||||
nodes: Vec<DepNode>,
|
||||
indices: FxHashMap<DepNode, DepNodeIndex>,
|
||||
edges: FxHashSet<(DepNodeIndex, DepNodeIndex)>,
|
||||
@ -31,8 +31,8 @@ pub struct DepGraphEdges {
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct DepNodeIndex {
|
||||
index: u32
|
||||
pub(super) struct DepNodeIndex {
|
||||
index: u32,
|
||||
}
|
||||
|
||||
impl DepNodeIndex {
|
||||
|
@ -8,11 +8,13 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
|
||||
StableHashingContextProvider};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
||||
use session::config::OutputType;
|
||||
use std::cell::{Ref, RefCell};
|
||||
use std::hash::Hash;
|
||||
use std::rc::Rc;
|
||||
use util::common::{ProfileQueriesMsg, profq_msg};
|
||||
|
||||
@ -22,7 +24,7 @@ use super::dep_node::{DepNode, DepKind, WorkProductId};
|
||||
use super::query::DepGraphQuery;
|
||||
use super::raii;
|
||||
use super::safe::DepGraphSafe;
|
||||
use super::edges::{DepGraphEdges, DepNodeIndex};
|
||||
use super::edges::{self, DepGraphEdges};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DepGraph {
|
||||
@ -38,10 +40,34 @@ pub struct DepGraph {
|
||||
fingerprints: Rc<RefCell<FxHashMap<DepNode, Fingerprint>>>
|
||||
}
|
||||
|
||||
/// As a temporary measure, while transitioning to the new DepGraph
|
||||
/// implementation, we maintain the old and the new dep-graph encoding in
|
||||
/// parallel, so a DepNodeIndex actually contains two indices, one for each
|
||||
/// version.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct DepNodeIndex {
|
||||
legacy: edges::DepNodeIndex,
|
||||
new: DepNodeIndexNew,
|
||||
}
|
||||
|
||||
impl DepNodeIndex {
|
||||
pub const INVALID: DepNodeIndex = DepNodeIndex {
|
||||
legacy: edges::DepNodeIndex::INVALID,
|
||||
new: DepNodeIndexNew::INVALID,
|
||||
};
|
||||
}
|
||||
|
||||
struct DepGraphData {
|
||||
/// The actual graph data.
|
||||
/// The old, initial encoding of the dependency graph. This will soon go
|
||||
/// away.
|
||||
edges: RefCell<DepGraphEdges>,
|
||||
|
||||
/// The new encoding of the dependency graph, optimized for red/green
|
||||
/// tracking. The `current` field is the dependency graph of only the
|
||||
/// current compilation session: We don't merge the previous dep-graph into
|
||||
/// current one anymore.
|
||||
current: RefCell<CurrentDepGraph>,
|
||||
|
||||
/// When we load, there may be `.o` files, cached mir, or other such
|
||||
/// things available to us. If we find that they are not dirty, we
|
||||
/// load the path to the file storing those work-products here into
|
||||
@ -63,6 +89,7 @@ impl DepGraph {
|
||||
work_products: RefCell::new(FxHashMap()),
|
||||
edges: RefCell::new(DepGraphEdges::new()),
|
||||
dep_node_debug: RefCell::new(FxHashMap()),
|
||||
current: RefCell::new(CurrentDepGraph::new()),
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
@ -82,7 +109,8 @@ impl DepGraph {
|
||||
}
|
||||
|
||||
pub fn in_ignore<'graph>(&'graph self) -> Option<raii::IgnoreTask<'graph>> {
|
||||
self.data.as_ref().map(|data| raii::IgnoreTask::new(&data.edges))
|
||||
self.data.as_ref().map(|data| raii::IgnoreTask::new(&data.edges,
|
||||
&data.current))
|
||||
}
|
||||
|
||||
pub fn with_ignore<OP,R>(&self, op: OP) -> R
|
||||
@ -130,6 +158,7 @@ impl DepGraph {
|
||||
{
|
||||
if let Some(ref data) = self.data {
|
||||
data.edges.borrow_mut().push_task(key);
|
||||
data.current.borrow_mut().push_task(key);
|
||||
if cfg!(debug_assertions) {
|
||||
profq_msg(ProfileQueriesMsg::TaskBegin(key.clone()))
|
||||
};
|
||||
@ -145,7 +174,9 @@ impl DepGraph {
|
||||
if cfg!(debug_assertions) {
|
||||
profq_msg(ProfileQueriesMsg::TaskEnd)
|
||||
};
|
||||
let dep_node_index = data.edges.borrow_mut().pop_task(key);
|
||||
|
||||
let dep_node_index_legacy = data.edges.borrow_mut().pop_task(key);
|
||||
let dep_node_index_new = data.current.borrow_mut().pop_task(key);
|
||||
|
||||
let mut stable_hasher = StableHasher::new();
|
||||
result.hash_stable(&mut hcx, &mut stable_hasher);
|
||||
@ -155,7 +186,10 @@ impl DepGraph {
|
||||
.insert(key, stable_hasher.finish())
|
||||
.is_none());
|
||||
|
||||
(result, dep_node_index)
|
||||
(result, DepNodeIndex {
|
||||
legacy: dep_node_index_legacy,
|
||||
new: dep_node_index_new,
|
||||
})
|
||||
} else {
|
||||
if key.kind.fingerprint_needed_for_crate_hash() {
|
||||
let mut hcx = cx.create_stable_hashing_context();
|
||||
@ -180,9 +214,14 @@ impl DepGraph {
|
||||
{
|
||||
if let Some(ref data) = self.data {
|
||||
data.edges.borrow_mut().push_anon_task();
|
||||
data.current.borrow_mut().push_anon_task();
|
||||
let result = op();
|
||||
let dep_node = data.edges.borrow_mut().pop_anon_task(dep_kind);
|
||||
(result, dep_node)
|
||||
let dep_node_index_legacy = data.edges.borrow_mut().pop_anon_task(dep_kind);
|
||||
let dep_node_index_new = data.current.borrow_mut().pop_anon_task(dep_kind);
|
||||
(result, DepNodeIndex {
|
||||
legacy: dep_node_index_legacy,
|
||||
new: dep_node_index_new,
|
||||
})
|
||||
} else {
|
||||
(op(), DepNodeIndex::INVALID)
|
||||
}
|
||||
@ -192,13 +231,15 @@ impl DepGraph {
|
||||
pub fn read(&self, v: DepNode) {
|
||||
if let Some(ref data) = self.data {
|
||||
data.edges.borrow_mut().read(v);
|
||||
data.current.borrow_mut().read(v);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn read_index(&self, v: DepNodeIndex) {
|
||||
if let Some(ref data) = self.data {
|
||||
data.edges.borrow_mut().read_index(v);
|
||||
data.edges.borrow_mut().read_index(v.legacy);
|
||||
data.current.borrow_mut().read_index(v.new);
|
||||
}
|
||||
}
|
||||
|
||||
@ -215,7 +256,13 @@ impl DepGraph {
|
||||
|
||||
pub fn alloc_input_node(&self, node: DepNode) -> DepNodeIndex {
|
||||
if let Some(ref data) = self.data {
|
||||
data.edges.borrow_mut().add_node(node)
|
||||
let dep_node_index_legacy = data.edges.borrow_mut().add_node(node);
|
||||
let dep_node_index_new = data.current.borrow_mut()
|
||||
.alloc_node(node, Vec::new());
|
||||
DepNodeIndex {
|
||||
legacy: dep_node_index_legacy,
|
||||
new: dep_node_index_new,
|
||||
}
|
||||
} else {
|
||||
DepNodeIndex::INVALID
|
||||
}
|
||||
@ -335,3 +382,208 @@ pub struct WorkProduct {
|
||||
/// Saved files associated with this CGU
|
||||
pub saved_files: Vec<(OutputType, String)>,
|
||||
}
|
||||
|
||||
pub(super) struct CurrentDepGraph {
|
||||
nodes: IndexVec<DepNodeIndexNew, DepNode>,
|
||||
edges: IndexVec<DepNodeIndexNew, Vec<DepNodeIndexNew>>,
|
||||
node_to_node_index: FxHashMap<DepNode, DepNodeIndexNew>,
|
||||
|
||||
task_stack: Vec<OpenTask>,
|
||||
}
|
||||
|
||||
impl CurrentDepGraph {
|
||||
fn new() -> CurrentDepGraph {
|
||||
CurrentDepGraph {
|
||||
nodes: IndexVec::new(),
|
||||
edges: IndexVec::new(),
|
||||
node_to_node_index: FxHashMap(),
|
||||
task_stack: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn push_ignore(&mut self) {
|
||||
self.task_stack.push(OpenTask::Ignore);
|
||||
}
|
||||
|
||||
pub(super) fn pop_ignore(&mut self) {
|
||||
let popped_node = self.task_stack.pop().unwrap();
|
||||
debug_assert_eq!(popped_node, OpenTask::Ignore);
|
||||
}
|
||||
|
||||
pub(super) fn push_task(&mut self, key: DepNode) {
|
||||
self.task_stack.push(OpenTask::Regular {
|
||||
node: key,
|
||||
reads: Vec::new(),
|
||||
read_set: FxHashSet(),
|
||||
});
|
||||
}
|
||||
|
||||
pub(super) fn pop_task(&mut self, key: DepNode) -> DepNodeIndexNew {
|
||||
let popped_node = self.task_stack.pop().unwrap();
|
||||
|
||||
if let OpenTask::Regular {
|
||||
node,
|
||||
read_set: _,
|
||||
reads
|
||||
} = popped_node {
|
||||
debug_assert_eq!(node, key);
|
||||
self.alloc_node(node, reads)
|
||||
} else {
|
||||
bug!("pop_task() - Expected regular task to be popped")
|
||||
}
|
||||
}
|
||||
|
||||
fn push_anon_task(&mut self) {
|
||||
self.task_stack.push(OpenTask::Anon {
|
||||
reads: Vec::new(),
|
||||
read_set: FxHashSet(),
|
||||
});
|
||||
}
|
||||
|
||||
fn pop_anon_task(&mut self, kind: DepKind) -> DepNodeIndexNew {
|
||||
let popped_node = self.task_stack.pop().unwrap();
|
||||
|
||||
if let OpenTask::Anon {
|
||||
read_set: _,
|
||||
reads
|
||||
} = popped_node {
|
||||
let mut fingerprint = Fingerprint::zero();
|
||||
let mut hasher = StableHasher::new();
|
||||
|
||||
for &read in reads.iter() {
|
||||
let read_dep_node = self.nodes[read];
|
||||
|
||||
::std::mem::discriminant(&read_dep_node.kind).hash(&mut hasher);
|
||||
|
||||
// Fingerprint::combine() is faster than sending Fingerprint
|
||||
// through the StableHasher (at least as long as StableHasher
|
||||
// is so slow).
|
||||
fingerprint = fingerprint.combine(read_dep_node.hash);
|
||||
}
|
||||
|
||||
fingerprint = fingerprint.combine(hasher.finish());
|
||||
|
||||
let target_dep_node = DepNode {
|
||||
kind,
|
||||
hash: fingerprint,
|
||||
};
|
||||
|
||||
if let Some(&index) = self.node_to_node_index.get(&target_dep_node) {
|
||||
return index;
|
||||
}
|
||||
|
||||
self.alloc_node(target_dep_node, reads)
|
||||
} else {
|
||||
bug!("pop_anon_task() - Expected anonymous task to be popped")
|
||||
}
|
||||
}
|
||||
|
||||
fn read(&mut self, source: DepNode) {
|
||||
let dep_node_index = self.maybe_alloc_node(source);
|
||||
self.read_index(dep_node_index);
|
||||
}
|
||||
|
||||
fn read_index(&mut self, source: DepNodeIndexNew) {
|
||||
match self.task_stack.last_mut() {
|
||||
Some(&mut OpenTask::Regular {
|
||||
ref mut reads,
|
||||
ref mut read_set,
|
||||
node: _,
|
||||
}) => {
|
||||
if read_set.insert(source) {
|
||||
reads.push(source);
|
||||
}
|
||||
}
|
||||
Some(&mut OpenTask::Anon {
|
||||
ref mut reads,
|
||||
ref mut read_set,
|
||||
}) => {
|
||||
if read_set.insert(source) {
|
||||
reads.push(source);
|
||||
}
|
||||
}
|
||||
Some(&mut OpenTask::Ignore) | None => {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn alloc_node(&mut self,
|
||||
dep_node: DepNode,
|
||||
edges: Vec<DepNodeIndexNew>)
|
||||
-> DepNodeIndexNew {
|
||||
debug_assert_eq!(self.edges.len(), self.nodes.len());
|
||||
debug_assert_eq!(self.node_to_node_index.len(), self.nodes.len());
|
||||
debug_assert!(!self.node_to_node_index.contains_key(&dep_node));
|
||||
let dep_node_index = DepNodeIndexNew::new(self.nodes.len());
|
||||
self.nodes.push(dep_node);
|
||||
self.node_to_node_index.insert(dep_node, dep_node_index);
|
||||
self.edges.push(edges);
|
||||
dep_node_index
|
||||
}
|
||||
|
||||
fn maybe_alloc_node(&mut self,
|
||||
dep_node: DepNode)
|
||||
-> DepNodeIndexNew {
|
||||
debug_assert_eq!(self.edges.len(), self.nodes.len());
|
||||
debug_assert_eq!(self.node_to_node_index.len(), self.nodes.len());
|
||||
|
||||
let CurrentDepGraph {
|
||||
ref mut node_to_node_index,
|
||||
ref mut nodes,
|
||||
ref mut edges,
|
||||
..
|
||||
} = *self;
|
||||
|
||||
*node_to_node_index.entry(dep_node).or_insert_with(|| {
|
||||
let next_id = nodes.len();
|
||||
nodes.push(dep_node);
|
||||
edges.push(Vec::new());
|
||||
DepNodeIndexNew::new(next_id)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub(super) struct DepNodeIndexNew {
|
||||
index: u32,
|
||||
}
|
||||
|
||||
impl Idx for DepNodeIndexNew {
|
||||
fn new(idx: usize) -> Self {
|
||||
DepNodeIndexNew::new(idx)
|
||||
}
|
||||
fn index(self) -> usize {
|
||||
self.index()
|
||||
}
|
||||
}
|
||||
|
||||
impl DepNodeIndexNew {
|
||||
|
||||
const INVALID: DepNodeIndexNew = DepNodeIndexNew {
|
||||
index: ::std::u32::MAX,
|
||||
};
|
||||
|
||||
fn new(v: usize) -> DepNodeIndexNew {
|
||||
assert!((v & 0xFFFF_FFFF) == v);
|
||||
DepNodeIndexNew { index: v as u32 }
|
||||
}
|
||||
|
||||
fn index(self) -> usize {
|
||||
self.index as usize
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
enum OpenTask {
|
||||
Regular {
|
||||
node: DepNode,
|
||||
reads: Vec<DepNodeIndexNew>,
|
||||
read_set: FxHashSet<DepNodeIndexNew>,
|
||||
},
|
||||
Anon {
|
||||
reads: Vec<DepNodeIndexNew>,
|
||||
read_set: FxHashSet<DepNodeIndexNew>,
|
||||
},
|
||||
Ignore,
|
||||
}
|
||||
|
@ -22,10 +22,9 @@ pub use self::dep_node::DepNode;
|
||||
pub use self::dep_node::WorkProductId;
|
||||
pub use self::graph::DepGraph;
|
||||
pub use self::graph::WorkProduct;
|
||||
pub use self::edges::DepNodeIndex;
|
||||
pub use self::graph::DepNodeIndex;
|
||||
pub use self::query::DepGraphQuery;
|
||||
pub use self::safe::AssertDepGraphSafe;
|
||||
pub use self::safe::DepGraphSafe;
|
||||
pub use self::raii::DepTask;
|
||||
|
||||
pub use self::dep_node::{DepKind, DepConstructor};
|
||||
|
@ -8,50 +8,33 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use super::DepNode;
|
||||
use super::edges::DepGraphEdges;
|
||||
use super::graph::CurrentDepGraph;
|
||||
|
||||
use std::cell::RefCell;
|
||||
|
||||
pub struct DepTask<'graph> {
|
||||
graph: &'graph RefCell<DepGraphEdges>,
|
||||
key: DepNode,
|
||||
}
|
||||
|
||||
impl<'graph> DepTask<'graph> {
|
||||
pub fn new(graph: &'graph RefCell<DepGraphEdges>,
|
||||
key: DepNode)
|
||||
-> DepTask<'graph> {
|
||||
graph.borrow_mut().push_task(key);
|
||||
DepTask {
|
||||
graph,
|
||||
key,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'graph> Drop for DepTask<'graph> {
|
||||
fn drop(&mut self) {
|
||||
self.graph.borrow_mut().pop_task(self.key);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IgnoreTask<'graph> {
|
||||
graph: &'graph RefCell<DepGraphEdges>,
|
||||
legacy_graph: &'graph RefCell<DepGraphEdges>,
|
||||
new_graph: &'graph RefCell<CurrentDepGraph>,
|
||||
}
|
||||
|
||||
impl<'graph> IgnoreTask<'graph> {
|
||||
pub fn new(graph: &'graph RefCell<DepGraphEdges>) -> IgnoreTask<'graph> {
|
||||
graph.borrow_mut().push_ignore();
|
||||
pub(super) fn new(legacy_graph: &'graph RefCell<DepGraphEdges>,
|
||||
new_graph: &'graph RefCell<CurrentDepGraph>)
|
||||
-> IgnoreTask<'graph> {
|
||||
legacy_graph.borrow_mut().push_ignore();
|
||||
new_graph.borrow_mut().push_ignore();
|
||||
IgnoreTask {
|
||||
graph
|
||||
legacy_graph,
|
||||
new_graph,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'graph> Drop for IgnoreTask<'graph> {
|
||||
fn drop(&mut self) {
|
||||
self.graph.borrow_mut().pop_ignore();
|
||||
self.legacy_graph.borrow_mut().pop_ignore();
|
||||
self.new_graph.borrow_mut().pop_ignore();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,6 +88,15 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
|
||||
).1;
|
||||
}
|
||||
|
||||
{
|
||||
dep_graph.with_task(
|
||||
DepNode::new_no_params(DepKind::AllLocalTraitImpls),
|
||||
&hcx,
|
||||
&krate.trait_impls,
|
||||
identity_fn
|
||||
);
|
||||
}
|
||||
|
||||
let hir_body_nodes = vec![root_mod_def_path_hash];
|
||||
|
||||
let mut collector = NodeCollector {
|
||||
|
Loading…
Reference in New Issue
Block a user