incr.comp.: Remove legacy dep-graph runtime.

This commit is contained in:
Michael Woerister 2017-09-28 16:19:10 +02:00
parent 171c020857
commit df06a7e532
5 changed files with 87 additions and 386 deletions

View File

@ -1,255 +0,0 @@
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use ich::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stable_hasher::StableHasher;
use std::env;
use std::hash::Hash;
use std::mem;
use super::{DepKind, DepNode};
use super::debug::EdgeFilter;
pub(super) struct DepGraphEdges {
nodes: Vec<DepNode>,
indices: FxHashMap<DepNode, DepNodeIndex>,
edges: FxHashSet<(DepNodeIndex, DepNodeIndex)>,
task_stack: Vec<OpenTask>,
forbidden_edge: Option<EdgeFilter>,
// A set to help assert that no two tasks use the same DepNode. This is a
// temporary measure. Once we load the previous dep-graph as readonly, this
// check will fall out of the graph implementation naturally.
opened_once: FxHashSet<DepNode>,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub(super) struct DepNodeIndex {
index: u32,
}
impl DepNodeIndex {
pub const INVALID: DepNodeIndex = DepNodeIndex { index: ::std::u32::MAX };
fn new(v: usize) -> DepNodeIndex {
assert!((v & 0xFFFF_FFFF) == v);
DepNodeIndex { index: v as u32 }
}
fn index(self) -> usize {
self.index as usize
}
}
#[derive(Clone, Debug, PartialEq)]
enum OpenTask {
Regular {
node: DepNode,
reads: Vec<DepNode>,
read_set: FxHashSet<DepNode>,
},
Anon {
reads: Vec<DepNode>,
read_set: FxHashSet<DepNode>,
},
Ignore,
}
impl DepGraphEdges {
pub fn new() -> DepGraphEdges {
let forbidden_edge = if cfg!(debug_assertions) {
match env::var("RUST_FORBID_DEP_GRAPH_EDGE") {
Ok(s) => {
match EdgeFilter::new(&s) {
Ok(f) => Some(f),
Err(err) => bug!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err),
}
}
Err(_) => None,
}
} else {
None
};
DepGraphEdges {
nodes: vec![],
indices: FxHashMap(),
edges: FxHashSet(),
task_stack: Vec::new(),
forbidden_edge,
opened_once: FxHashSet(),
}
}
pub fn push_ignore(&mut self) {
self.task_stack.push(OpenTask::Ignore);
}
pub fn pop_ignore(&mut self) {
let popped_node = self.task_stack.pop().unwrap();
debug_assert_eq!(popped_node, OpenTask::Ignore);
}
pub fn push_task(&mut self, key: DepNode) {
if !self.opened_once.insert(key) {
bug!("Re-opened node {:?}", key)
}
self.task_stack.push(OpenTask::Regular {
node: key,
reads: Vec::new(),
read_set: FxHashSet(),
});
}
pub fn pop_task(&mut self, key: DepNode) -> DepNodeIndex {
let popped_node = self.task_stack.pop().unwrap();
if let OpenTask::Regular {
node,
read_set: _,
reads
} = popped_node {
debug_assert_eq!(node, key);
debug_assert!(!node.kind.is_input() || reads.is_empty());
let target_id = self.get_or_create_node(node);
for read in reads.into_iter() {
let source_id = self.get_or_create_node(read);
self.edges.insert((source_id, target_id));
}
target_id
} else {
bug!("pop_task() - Expected regular task to be popped")
}
}
pub fn push_anon_task(&mut self) {
self.task_stack.push(OpenTask::Anon {
reads: Vec::new(),
read_set: FxHashSet(),
});
}
pub fn pop_anon_task(&mut self, kind: DepKind) -> DepNodeIndex {
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() {
mem::discriminant(&read.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.hash);
}
fingerprint = fingerprint.combine(hasher.finish());
let target_dep_node = DepNode {
kind,
hash: fingerprint,
};
if let Some(&index) = self.indices.get(&target_dep_node) {
return index;
}
let target_id = self.get_or_create_node(target_dep_node);
for read in reads.into_iter() {
let source_id = self.get_or_create_node(read);
self.edges.insert((source_id, target_id));
}
target_id
} else {
bug!("pop_anon_task() - Expected anonymous task to be popped")
}
}
/// Indicates that the current task `C` reads `v` by adding an
/// edge from `v` to `C`. If there is no current task, has no
/// effect. Note that *reading* from tracked state is harmless if
/// you are not in a task; what is bad is *writing* to tracked
/// state (and leaking data that you read into a tracked task).
pub fn read(&mut self, source: DepNode) {
match self.task_stack.last_mut() {
Some(&mut OpenTask::Regular {
node: target,
ref mut reads,
ref mut read_set,
}) => {
if read_set.insert(source) {
reads.push(source);
if cfg!(debug_assertions) {
if let Some(ref forbidden_edge) = self.forbidden_edge {
if forbidden_edge.test(&source, &target) {
bug!("forbidden edge {:?} -> {:?} created", source, target)
}
}
}
}
}
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
}
}
}
pub fn read_index(&mut self, source: DepNodeIndex) {
let dep_node = self.nodes[source.index()];
self.read(dep_node);
}
#[inline]
pub fn add_edge(&mut self, source: DepNode, target: DepNode) {
let source = self.get_or_create_node(source);
let target = self.get_or_create_node(target);
self.edges.insert((source, target));
}
pub fn add_node(&mut self, node: DepNode) -> DepNodeIndex {
self.get_or_create_node(node)
}
#[inline]
fn get_or_create_node(&mut self, dep_node: DepNode) -> DepNodeIndex {
let DepGraphEdges {
ref mut indices,
ref mut nodes,
..
} = *self;
*indices.entry(dep_node).or_insert_with(|| {
let next_id = nodes.len();
nodes.push(dep_node);
DepNodeIndex::new(next_id)
})
}
}

View File

@ -14,6 +14,7 @@ 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::env;
use std::hash::Hash;
use std::rc::Rc;
use ty::TyCtxt;
@ -21,15 +22,14 @@ use util::common::{ProfileQueriesMsg, profq_msg};
use ich::Fingerprint;
use super::debug::EdgeFilter;
use super::dep_node::{DepNode, DepKind, WorkProductId};
use super::query::DepGraphQuery;
use super::raii;
use super::safe::DepGraphSafe;
use super::edges::{self, DepGraphEdges};
use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex};
use super::prev::PreviousDepGraph;
#[derive(Clone)]
pub struct DepGraph {
data: Option<Rc<DepGraphData>>,
@ -44,20 +44,25 @@ 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,
index: u32,
}
impl Idx for DepNodeIndex {
fn new(idx: usize) -> Self {
assert!((idx & 0xFFFF_FFFF) == idx);
DepNodeIndex { index: idx as u32 }
}
fn index(self) -> usize {
self.index as usize
}
}
impl DepNodeIndex {
pub const INVALID: DepNodeIndex = DepNodeIndex {
legacy: edges::DepNodeIndex::INVALID,
new: DepNodeIndexNew::INVALID,
const INVALID: DepNodeIndex = DepNodeIndex {
index: ::std::u32::MAX,
};
}
@ -77,10 +82,6 @@ impl DepNodeColor {
}
struct DepGraphData {
/// 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
@ -105,7 +106,7 @@ struct DepGraphData {
dep_node_debug: RefCell<FxHashMap<DepNode, String>>,
// Used for testing, only populated when -Zquery-dep-graph is specified.
loaded_from_cache: RefCell<FxHashMap<DepNodeIndexNew, bool>>,
loaded_from_cache: RefCell<FxHashMap<DepNodeIndex, bool>>,
}
impl DepGraph {
@ -115,7 +116,6 @@ impl DepGraph {
data: Some(Rc::new(DepGraphData {
previous_work_products: RefCell::new(FxHashMap()),
work_products: RefCell::new(FxHashMap()),
edges: RefCell::new(DepGraphEdges::new()),
dep_node_debug: RefCell::new(FxHashMap()),
current: RefCell::new(CurrentDepGraph::new()),
previous: prev_graph,
@ -155,8 +155,7 @@ impl DepGraph {
}
pub fn in_ignore<'graph>(&'graph self) -> Option<raii::IgnoreTask<'graph>> {
self.data.as_ref().map(|data| raii::IgnoreTask::new(&data.edges,
&data.current))
self.data.as_ref().map(|data| raii::IgnoreTask::new(&data.current))
}
pub fn with_ignore<OP,R>(&self, op: OP) -> R
@ -205,7 +204,6 @@ impl DepGraph {
if let Some(ref data) = self.data {
debug_assert!(!data.colors.borrow().contains_key(&key));
data.edges.borrow_mut().push_task(key);
data.current.borrow_mut().push_task(key);
if cfg!(debug_assertions) {
profq_msg(ProfileQueriesMsg::TaskBegin(key.clone()))
@ -223,8 +221,7 @@ impl DepGraph {
profq_msg(ProfileQueriesMsg::TaskEnd)
};
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 dep_node_index = data.current.borrow_mut().pop_task(key);
let mut stable_hasher = StableHasher::new();
result.hash_stable(&mut hcx, &mut stable_hasher);
@ -239,20 +236,14 @@ impl DepGraph {
let prev_fingerprint = data.previous.fingerprint_of(&key);
let color = if Some(current_fingerprint) == prev_fingerprint {
DepNodeColor::Green(DepNodeIndex {
legacy: dep_node_index_legacy,
new: dep_node_index_new,
})
DepNodeColor::Green(dep_node_index)
} else {
DepNodeColor::Red
};
assert!(data.colors.borrow_mut().insert(key, color).is_none());
(result, DepNodeIndex {
legacy: dep_node_index_legacy,
new: dep_node_index_new,
})
(result, dep_node_index)
} else {
if key.kind.fingerprint_needed_for_crate_hash() {
let mut hcx = cx.create_stable_hashing_context();
@ -276,17 +267,12 @@ impl DepGraph {
where OP: FnOnce() -> R
{
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_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,
})
let dep_node_index = data.current
.borrow_mut()
.pop_anon_task(dep_kind);
(result, dep_node_index)
} else {
(op(), DepNodeIndex::INVALID)
}
@ -295,11 +281,9 @@ impl DepGraph {
#[inline]
pub fn read(&self, v: DepNode) {
if let Some(ref data) = self.data {
data.edges.borrow_mut().read(v);
let mut current = data.current.borrow_mut();
if let Some(&dep_node_index_new) = current.node_to_node_index.get(&v) {
current.read_index(dep_node_index_new);
if let Some(&dep_node_index) = current.node_to_node_index.get(&v) {
current.read_index(dep_node_index);
} else {
bug!("DepKind {:?} should be pre-allocated but isn't.", v.kind)
}
@ -307,24 +291,12 @@ impl DepGraph {
}
#[inline]
pub fn read_index(&self, v: DepNodeIndex) {
pub fn read_index(&self, dep_node_index: DepNodeIndex) {
if let Some(ref data) = self.data {
data.edges.borrow_mut().read_index(v.legacy);
data.current.borrow_mut().read_index(v.new);
data.current.borrow_mut().read_index(dep_node_index);
}
}
/// Only to be used during graph loading
#[inline]
pub fn add_edge_directly(&self, source: DepNode, target: DepNode) {
self.data.as_ref().unwrap().edges.borrow_mut().add_edge(source, target);
}
/// Only to be used during graph loading
pub fn add_node_directly(&self, node: DepNode) {
self.data.as_ref().unwrap().edges.borrow_mut().add_node(node);
}
pub fn fingerprint_of(&self, dep_node: &DepNode) -> Fingerprint {
self.fingerprints.borrow()[dep_node]
}
@ -567,18 +539,9 @@ impl DepGraph {
// ... allocating an entry for it in the current dependency graph and
// adding all the appropriate edges imported from the previous graph ...
let node_index_new = data.current
let dep_node_index = data.current
.borrow_mut()
.alloc_node(*dep_node,
current_deps.iter().map(|n| n.new).collect());
let dep_node_index_legacy = {
let mut legacy_graph = data.edges.borrow_mut();
legacy_graph.push_task(*dep_node);
for node_index in current_deps.into_iter().map(|n| n.legacy) {
legacy_graph.read_index(node_index);
}
legacy_graph.pop_task(*dep_node)
};
.alloc_node(*dep_node, current_deps);
// ... copying the fingerprint from the previous graph too, so we don't
// have to recompute it ...
@ -588,24 +551,19 @@ impl DepGraph {
.insert(*dep_node, fingerprint)
.is_none());
let node_index = DepNodeIndex {
legacy: dep_node_index_legacy,
new: node_index_new,
};
// ... and finally storing a "Green" entry in the color map.
assert!(data.colors
.borrow_mut()
.insert(*dep_node, DepNodeColor::Green(node_index))
.insert(*dep_node, DepNodeColor::Green(dep_node_index))
.is_none());
debug!("try_mark_green({:?}) - END - successfully marked as green", dep_node.kind);
Some(node_index)
Some(dep_node_index)
}
// Used in various assertions
pub fn is_green(&self, dep_node_index: DepNodeIndex) -> bool {
let dep_node = self.data.as_ref().unwrap().current.borrow().nodes[dep_node_index.new];
let dep_node = self.data.as_ref().unwrap().current.borrow().nodes[dep_node_index];
self.data.as_ref().unwrap().colors.borrow().get(&dep_node).map(|&color| {
match color {
DepNodeColor::Red => false,
@ -614,9 +572,9 @@ impl DepGraph {
}).unwrap_or(false)
}
pub fn mark_loaded_from_cache(&self, dep_node: DepNodeIndex, state: bool) {
pub fn mark_loaded_from_cache(&self, dep_node_index: DepNodeIndex, state: bool) {
debug!("mark_loaded_from_cache({:?}, {})",
self.data.as_ref().unwrap().current.borrow().nodes[dep_node.new],
self.data.as_ref().unwrap().current.borrow().nodes[dep_node_index],
state);
self.data
@ -624,7 +582,7 @@ impl DepGraph {
.unwrap()
.loaded_from_cache
.borrow_mut()
.insert(dep_node.new, state);
.insert(dep_node_index, state);
}
pub fn was_loaded_from_cache(&self, dep_node: &DepNode) -> Option<bool> {
@ -673,13 +631,12 @@ pub struct WorkProduct {
}
pub(super) struct CurrentDepGraph {
nodes: IndexVec<DepNodeIndexNew, DepNode>,
edges: IndexVec<DepNodeIndexNew, Vec<DepNodeIndexNew>>,
node_to_node_index: FxHashMap<DepNode, DepNodeIndexNew>,
nodes: IndexVec<DepNodeIndex, DepNode>,
edges: IndexVec<DepNodeIndex, Vec<DepNodeIndex>>,
node_to_node_index: FxHashMap<DepNode, DepNodeIndex>,
anon_id_seed: Fingerprint,
task_stack: Vec<OpenTask>,
forbidden_edge: Option<EdgeFilter>,
}
impl CurrentDepGraph {
@ -692,12 +649,27 @@ impl CurrentDepGraph {
let mut stable_hasher = StableHasher::new();
nanos.hash(&mut stable_hasher);
let forbidden_edge = if cfg!(debug_assertions) {
match env::var("RUST_FORBID_DEP_GRAPH_EDGE") {
Ok(s) => {
match EdgeFilter::new(&s) {
Ok(f) => Some(f),
Err(err) => bug!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err),
}
}
Err(_) => None,
}
} else {
None
};
CurrentDepGraph {
nodes: IndexVec::new(),
edges: IndexVec::new(),
node_to_node_index: FxHashMap(),
anon_id_seed: stable_hasher.finish(),
task_stack: Vec::new(),
forbidden_edge,
}
}
@ -718,7 +690,7 @@ impl CurrentDepGraph {
});
}
pub(super) fn pop_task(&mut self, key: DepNode) -> DepNodeIndexNew {
pub(super) fn pop_task(&mut self, key: DepNode) -> DepNodeIndex {
let popped_node = self.task_stack.pop().unwrap();
if let OpenTask::Regular {
@ -740,7 +712,7 @@ impl CurrentDepGraph {
});
}
fn pop_anon_task(&mut self, kind: DepKind) -> DepNodeIndexNew {
fn pop_anon_task(&mut self, kind: DepKind) -> DepNodeIndex {
let popped_node = self.task_stack.pop().unwrap();
if let OpenTask::Anon {
@ -778,15 +750,26 @@ impl CurrentDepGraph {
}
}
fn read_index(&mut self, source: DepNodeIndexNew) {
fn read_index(&mut self, source: DepNodeIndex) {
match self.task_stack.last_mut() {
Some(&mut OpenTask::Regular {
ref mut reads,
ref mut read_set,
node: _,
node: ref target,
}) => {
if read_set.insert(source) {
reads.push(source);
if cfg!(debug_assertions) {
if let Some(ref forbidden_edge) = self.forbidden_edge {
let source = self.nodes[source];
if forbidden_edge.test(&source, &target) {
bug!("forbidden edge {:?} -> {:?} created",
source,
target)
}
}
}
}
}
Some(&mut OpenTask::Anon {
@ -805,12 +788,12 @@ impl CurrentDepGraph {
fn alloc_node(&mut self,
dep_node: DepNode,
edges: Vec<DepNodeIndexNew>)
-> DepNodeIndexNew {
edges: Vec<DepNodeIndex>)
-> DepNodeIndex {
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());
let dep_node_index = DepNodeIndex::new(self.nodes.len());
self.nodes.push(dep_node);
self.node_to_node_index.insert(dep_node, dep_node_index);
self.edges.push(edges);
@ -818,38 +801,16 @@ impl CurrentDepGraph {
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub(super) struct DepNodeIndexNew {
index: u32,
}
impl Idx for DepNodeIndexNew {
fn new(v: usize) -> DepNodeIndexNew {
assert!((v & 0xFFFF_FFFF) == v);
DepNodeIndexNew { index: v as u32 }
}
fn index(self) -> usize {
self.index as usize
}
}
impl DepNodeIndexNew {
const INVALID: DepNodeIndexNew = DepNodeIndexNew {
index: ::std::u32::MAX,
};
}
#[derive(Clone, Debug, PartialEq)]
enum OpenTask {
Regular {
node: DepNode,
reads: Vec<DepNodeIndexNew>,
read_set: FxHashSet<DepNodeIndexNew>,
reads: Vec<DepNodeIndex>,
read_set: FxHashSet<DepNodeIndex>,
},
Anon {
reads: Vec<DepNodeIndexNew>,
read_set: FxHashSet<DepNodeIndexNew>,
reads: Vec<DepNodeIndex>,
read_set: FxHashSet<DepNodeIndex>,
},
Ignore,
}

View File

@ -11,7 +11,6 @@
pub mod debug;
mod dep_node;
mod dep_tracking_map;
mod edges;
mod graph;
mod prev;
mod query;

View File

@ -8,33 +8,26 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::edges::DepGraphEdges;
use super::graph::CurrentDepGraph;
use std::cell::RefCell;
pub struct IgnoreTask<'graph> {
legacy_graph: &'graph RefCell<DepGraphEdges>,
new_graph: &'graph RefCell<CurrentDepGraph>,
graph: &'graph RefCell<CurrentDepGraph>,
}
impl<'graph> IgnoreTask<'graph> {
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();
pub(super) fn new(graph: &'graph RefCell<CurrentDepGraph>) -> IgnoreTask<'graph> {
graph.borrow_mut().push_ignore();
IgnoreTask {
legacy_graph,
new_graph,
graph,
}
}
}
impl<'graph> Drop for IgnoreTask<'graph> {
fn drop(&mut self) {
self.legacy_graph.borrow_mut().pop_ignore();
self.new_graph.borrow_mut().pop_ignore();
self.graph.borrow_mut().pop_ignore();
}
}

View File

@ -56,7 +56,10 @@ impl SerializedDepGraph {
}
}
pub fn edge_targets_from(&self, source: SerializedDepNodeIndex) -> &[SerializedDepNodeIndex] {
#[inline]
pub fn edge_targets_from(&self,
source: SerializedDepNodeIndex)
-> &[SerializedDepNodeIndex] {
let targets = self.edge_list_indices[source];
&self.edge_list_data[targets.0 as usize..targets.1 as usize]
}