Remove prev_index_to_index field from CurrentDepGraph
This commit is contained in:
@@ -66,7 +66,7 @@ pub struct MarkFrame<'a> {
|
|||||||
parent: Option<&'a MarkFrame<'a>>,
|
parent: Option<&'a MarkFrame<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum DepNodeColor {
|
pub(super) enum DepNodeColor {
|
||||||
Red,
|
Red,
|
||||||
Green(DepNodeIndex),
|
Green(DepNodeIndex),
|
||||||
}
|
}
|
||||||
@@ -140,7 +140,7 @@ impl<D: Deps> DepGraph<D> {
|
|||||||
let colors = DepNodeColorMap::new(prev_graph_node_count);
|
let colors = DepNodeColorMap::new(prev_graph_node_count);
|
||||||
|
|
||||||
// Instantiate a dependy-less node only once for anonymous queries.
|
// Instantiate a dependy-less node only once for anonymous queries.
|
||||||
let _green_node_index = current.alloc_new_node(
|
let _green_node_index = current.alloc_node(
|
||||||
DepNode { kind: D::DEP_KIND_NULL, hash: current.anon_id_seed.into() },
|
DepNode { kind: D::DEP_KIND_NULL, hash: current.anon_id_seed.into() },
|
||||||
EdgesVec::new(),
|
EdgesVec::new(),
|
||||||
Fingerprint::ZERO,
|
Fingerprint::ZERO,
|
||||||
@@ -148,26 +148,17 @@ impl<D: Deps> DepGraph<D> {
|
|||||||
assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE);
|
assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE);
|
||||||
|
|
||||||
// Instantiate a dependy-less red node only once for anonymous queries.
|
// Instantiate a dependy-less red node only once for anonymous queries.
|
||||||
let (red_node_index, red_node_prev_index_and_color) = current.intern_node(
|
let red_node_index = current.alloc_node(
|
||||||
&prev_graph,
|
|
||||||
DepNode { kind: D::DEP_KIND_RED, hash: Fingerprint::ZERO.into() },
|
DepNode { kind: D::DEP_KIND_RED, hash: Fingerprint::ZERO.into() },
|
||||||
EdgesVec::new(),
|
EdgesVec::new(),
|
||||||
None,
|
Fingerprint::ZERO,
|
||||||
);
|
);
|
||||||
assert_eq!(red_node_index, DepNodeIndex::FOREVER_RED_NODE);
|
assert_eq!(red_node_index, DepNodeIndex::FOREVER_RED_NODE);
|
||||||
match red_node_prev_index_and_color {
|
if prev_graph_node_count > 0 {
|
||||||
None => {
|
colors.insert(
|
||||||
// This is expected when we have no previous compilation session.
|
SerializedDepNodeIndex::from_u32(DepNodeIndex::FOREVER_RED_NODE.as_u32()),
|
||||||
assert!(prev_graph_node_count == 0);
|
DepNodeColor::Red,
|
||||||
}
|
);
|
||||||
Some((prev_red_node_index, DepNodeColor::Red)) => {
|
|
||||||
assert_eq!(prev_red_node_index.as_usize(), red_node_index.as_usize());
|
|
||||||
colors.insert(prev_red_node_index, DepNodeColor::Red);
|
|
||||||
}
|
|
||||||
Some((_, DepNodeColor::Green(_))) => {
|
|
||||||
// There must be a logic error somewhere if we hit this branch.
|
|
||||||
panic!("DepNodeIndex::FOREVER_RED_NODE evaluated to DepNodeColor::Green")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DepGraph {
|
DepGraph {
|
||||||
@@ -376,8 +367,7 @@ impl<D: Deps> DepGraphData<D> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let dcx = cx.dep_context();
|
let dcx = cx.dep_context();
|
||||||
let dep_node_index =
|
let dep_node_index = self.hash_result_and_alloc_node(dcx, key, edges, &result, hash_result);
|
||||||
self.hash_result_and_intern_node(dcx, key, edges, &result, hash_result);
|
|
||||||
|
|
||||||
(result, dep_node_index)
|
(result, dep_node_index)
|
||||||
}
|
}
|
||||||
@@ -447,7 +437,7 @@ impl<D: Deps> DepGraphData<D> {
|
|||||||
// memory impact of this `anon_node_to_index` map remains tolerable, and helps
|
// memory impact of this `anon_node_to_index` map remains tolerable, and helps
|
||||||
// us avoid useless growth of the graph with almost-equivalent nodes.
|
// us avoid useless growth of the graph with almost-equivalent nodes.
|
||||||
self.current.anon_node_to_index.get_or_insert_with(target_dep_node, || {
|
self.current.anon_node_to_index.get_or_insert_with(target_dep_node, || {
|
||||||
self.current.alloc_new_node(target_dep_node, task_deps, Fingerprint::ZERO)
|
self.current.alloc_node(target_dep_node, task_deps, Fingerprint::ZERO)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -456,7 +446,7 @@ impl<D: Deps> DepGraphData<D> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Intern the new `DepNode` with the dependencies up-to-now.
|
/// Intern the new `DepNode` with the dependencies up-to-now.
|
||||||
fn hash_result_and_intern_node<Ctxt: DepContext<Deps = D>, R>(
|
fn hash_result_and_alloc_node<Ctxt: DepContext<Deps = D>, R>(
|
||||||
&self,
|
&self,
|
||||||
cx: &Ctxt,
|
cx: &Ctxt,
|
||||||
node: DepNode,
|
node: DepNode,
|
||||||
@@ -468,22 +458,8 @@ impl<D: Deps> DepGraphData<D> {
|
|||||||
let current_fingerprint = hash_result.map(|hash_result| {
|
let current_fingerprint = hash_result.map(|hash_result| {
|
||||||
cx.with_stable_hashing_context(|mut hcx| hash_result(&mut hcx, result))
|
cx.with_stable_hashing_context(|mut hcx| hash_result(&mut hcx, result))
|
||||||
});
|
});
|
||||||
|
let dep_node_index = self.alloc_and_color_node(node, edges, current_fingerprint);
|
||||||
// Intern the new `DepNode` with the dependencies up-to-now.
|
|
||||||
let (dep_node_index, prev_and_color) =
|
|
||||||
self.current.intern_node(&self.previous, node, edges, current_fingerprint);
|
|
||||||
|
|
||||||
hashing_timer.finish_with_query_invocation_id(dep_node_index.into());
|
hashing_timer.finish_with_query_invocation_id(dep_node_index.into());
|
||||||
|
|
||||||
if let Some((prev_index, color)) = prev_and_color {
|
|
||||||
debug_assert!(
|
|
||||||
self.colors.get(prev_index).is_none(),
|
|
||||||
"DepGraph::with_task() - Duplicate DepNodeColor insertion for {node:?}",
|
|
||||||
);
|
|
||||||
|
|
||||||
self.colors.insert(prev_index, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
dep_node_index
|
dep_node_index
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -601,7 +577,7 @@ impl<D: Deps> DepGraph<D> {
|
|||||||
//
|
//
|
||||||
// For sanity, we still check that the loaded stable hash and the new one match.
|
// For sanity, we still check that the loaded stable hash and the new one match.
|
||||||
if let Some(prev_index) = data.previous.node_to_index_opt(&node) {
|
if let Some(prev_index) = data.previous.node_to_index_opt(&node) {
|
||||||
let dep_node_index = data.current.prev_index_to_index.lock()[prev_index];
|
let dep_node_index = data.colors.current(prev_index);
|
||||||
if let Some(dep_node_index) = dep_node_index {
|
if let Some(dep_node_index) = dep_node_index {
|
||||||
crate::query::incremental_verify_ich(
|
crate::query::incremental_verify_ich(
|
||||||
cx,
|
cx,
|
||||||
@@ -637,7 +613,7 @@ impl<D: Deps> DepGraph<D> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
data.hash_result_and_intern_node(&cx, node, edges, result, hash_result)
|
data.hash_result_and_alloc_node(&cx, node, edges, result, hash_result)
|
||||||
} else {
|
} else {
|
||||||
// Incremental compilation is turned off. We just execute the task
|
// Incremental compilation is turned off. We just execute the task
|
||||||
// without tracking. We still provide a dep-node index that uniquely
|
// without tracking. We still provide a dep-node index that uniquely
|
||||||
@@ -655,13 +631,11 @@ impl<D: Deps> DepGraphData<D> {
|
|||||||
msg: impl FnOnce() -> S,
|
msg: impl FnOnce() -> S,
|
||||||
) {
|
) {
|
||||||
if let Some(prev_index) = self.previous.node_to_index_opt(dep_node) {
|
if let Some(prev_index) = self.previous.node_to_index_opt(dep_node) {
|
||||||
let current = self.current.prev_index_to_index.lock()[prev_index];
|
let current = self.colors.get(prev_index);
|
||||||
assert!(current.is_none(), "{}", msg())
|
assert!(current.is_none(), "{}", msg())
|
||||||
} else if let Some(nodes_newly_allocated_in_current_session) =
|
} else if let Some(nodes_in_current_session) = &self.current.nodes_in_current_session {
|
||||||
&self.current.nodes_newly_allocated_in_current_session
|
|
||||||
{
|
|
||||||
outline(|| {
|
outline(|| {
|
||||||
let seen = nodes_newly_allocated_in_current_session.lock().contains_key(dep_node);
|
let seen = nodes_in_current_session.lock().contains_key(dep_node);
|
||||||
assert!(!seen, "{}", msg());
|
assert!(!seen, "{}", msg());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -738,15 +712,77 @@ impl<D: Deps> DepGraphData<D> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Promote the previous diagnostics to the current session.
|
// Manually recreate the node as `promote_node_and_deps_to_current` expects all
|
||||||
let index = self.current.promote_node_and_deps_to_current(&self.previous, prev_index);
|
// green dependencies.
|
||||||
// FIXME: Can this race with a parallel compiler?
|
let dep_node_index = self.current.encoder.send(
|
||||||
qcx.store_side_effect(index, side_effect);
|
DepNode {
|
||||||
|
kind: D::DEP_KIND_SIDE_EFFECT,
|
||||||
|
hash: PackedFingerprint::from(Fingerprint::ZERO),
|
||||||
|
},
|
||||||
|
Fingerprint::ZERO,
|
||||||
|
std::iter::once(DepNodeIndex::FOREVER_RED_NODE).collect(),
|
||||||
|
);
|
||||||
|
qcx.store_side_effect(dep_node_index, side_effect);
|
||||||
|
|
||||||
// Mark the node as green.
|
// Mark the node as green.
|
||||||
self.colors.insert(prev_index, DepNodeColor::Green(index));
|
self.colors.insert(prev_index, DepNodeColor::Green(dep_node_index));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn alloc_and_color_node(
|
||||||
|
&self,
|
||||||
|
key: DepNode,
|
||||||
|
edges: EdgesVec,
|
||||||
|
fingerprint: Option<Fingerprint>,
|
||||||
|
) -> DepNodeIndex {
|
||||||
|
let dep_node_index =
|
||||||
|
self.current.alloc_node(key, edges, fingerprint.unwrap_or(Fingerprint::ZERO));
|
||||||
|
|
||||||
|
if let Some(prev_index) = self.previous.node_to_index_opt(&key) {
|
||||||
|
// Determine the color and index of the new `DepNode`.
|
||||||
|
let color = if let Some(fingerprint) = fingerprint {
|
||||||
|
if fingerprint == self.previous.fingerprint_by_index(prev_index) {
|
||||||
|
// This is a green node: it existed in the previous compilation,
|
||||||
|
// its query was re-executed, and it has the same result as before.
|
||||||
|
DepNodeColor::Green(dep_node_index)
|
||||||
|
} else {
|
||||||
|
// This is a red node: it existed in the previous compilation, its query
|
||||||
|
// was re-executed, but it has a different result from before.
|
||||||
|
DepNodeColor::Red
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This is a red node, effectively: it existed in the previous compilation
|
||||||
|
// session, its query was re-executed, but it doesn't compute a result hash
|
||||||
|
// (i.e. it represents a `no_hash` query), so we have no way of determining
|
||||||
|
// whether or not the result was the same as before.
|
||||||
|
DepNodeColor::Red
|
||||||
|
};
|
||||||
|
|
||||||
|
debug_assert!(
|
||||||
|
self.colors.get(prev_index).is_none(),
|
||||||
|
"DepGraph::with_task() - Duplicate DepNodeColor insertion for {key:?}",
|
||||||
|
);
|
||||||
|
|
||||||
|
self.colors.insert(prev_index, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
dep_node_index
|
||||||
|
}
|
||||||
|
|
||||||
|
fn promote_node_and_deps_to_current(&self, prev_index: SerializedDepNodeIndex) -> DepNodeIndex {
|
||||||
|
self.current.debug_assert_not_in_new_nodes(&self.previous, prev_index);
|
||||||
|
|
||||||
|
let dep_node_index = self.current.encoder.send_promoted(prev_index, &self.colors);
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
self.current.record_edge(
|
||||||
|
dep_node_index,
|
||||||
|
self.previous.index_to_node(prev_index),
|
||||||
|
self.previous.fingerprint_by_index(prev_index),
|
||||||
|
);
|
||||||
|
|
||||||
|
dep_node_index
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: Deps> DepGraph<D> {
|
impl<D: Deps> DepGraph<D> {
|
||||||
@@ -948,14 +984,10 @@ impl<D: Deps> DepGraphData<D> {
|
|||||||
|
|
||||||
// We allocating an entry for the node in the current dependency graph and
|
// We allocating an entry for the node in the current dependency graph and
|
||||||
// adding all the appropriate edges imported from the previous graph
|
// adding all the appropriate edges imported from the previous graph
|
||||||
let dep_node_index =
|
let dep_node_index = self.promote_node_and_deps_to_current(prev_dep_node_index);
|
||||||
self.current.promote_node_and_deps_to_current(&self.previous, prev_dep_node_index);
|
|
||||||
|
|
||||||
// ... emitting any stored diagnostic ...
|
|
||||||
|
|
||||||
// ... and finally storing a "Green" entry in the color map.
|
// ... and finally storing a "Green" entry in the color map.
|
||||||
// Multiple threads can all write the same color here
|
// Multiple threads can all write the same color here
|
||||||
self.colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index));
|
|
||||||
|
|
||||||
debug!("successfully marked {dep_node:?} as green");
|
debug!("successfully marked {dep_node:?} as green");
|
||||||
Some(dep_node_index)
|
Some(dep_node_index)
|
||||||
@@ -1106,7 +1138,6 @@ rustc_index::newtype_index! {
|
|||||||
/// first, and `data` second.
|
/// first, and `data` second.
|
||||||
pub(super) struct CurrentDepGraph<D: Deps> {
|
pub(super) struct CurrentDepGraph<D: Deps> {
|
||||||
encoder: GraphEncoder<D>,
|
encoder: GraphEncoder<D>,
|
||||||
prev_index_to_index: Lock<IndexVec<SerializedDepNodeIndex, Option<DepNodeIndex>>>,
|
|
||||||
anon_node_to_index: ShardedHashMap<DepNode, DepNodeIndex>,
|
anon_node_to_index: ShardedHashMap<DepNode, DepNodeIndex>,
|
||||||
|
|
||||||
/// This is used to verify that fingerprints do not change between the creation of a node
|
/// This is used to verify that fingerprints do not change between the creation of a node
|
||||||
@@ -1123,9 +1154,8 @@ pub(super) struct CurrentDepGraph<D: Deps> {
|
|||||||
/// This field is only `Some` if the `-Z incremental_verify_ich` option is present
|
/// This field is only `Some` if the `-Z incremental_verify_ich` option is present
|
||||||
/// or if `debug_assertions` are enabled.
|
/// or if `debug_assertions` are enabled.
|
||||||
///
|
///
|
||||||
/// The map contains all DepNodes that have been allocated in the current session so far and
|
/// The map contains all DepNodes that have been allocated in the current session so far.
|
||||||
/// for which there is no equivalent in the previous session.
|
nodes_in_current_session: Option<Lock<FxHashMap<DepNode, DepNodeIndex>>>,
|
||||||
nodes_newly_allocated_in_current_session: Option<Lock<FxHashMap<DepNode, DepNodeIndex>>>,
|
|
||||||
|
|
||||||
/// Anonymous `DepNode`s are nodes whose IDs we compute from the list of
|
/// Anonymous `DepNode`s are nodes whose IDs we compute from the list of
|
||||||
/// their edges. This has the beneficial side-effect that multiple anonymous
|
/// their edges. This has the beneficial side-effect that multiple anonymous
|
||||||
@@ -1190,13 +1220,12 @@ impl<D: Deps> CurrentDepGraph<D> {
|
|||||||
// FIXME: The count estimate is off as anon nodes are only a portion of the nodes.
|
// FIXME: The count estimate is off as anon nodes are only a portion of the nodes.
|
||||||
new_node_count_estimate / sharded::shards(),
|
new_node_count_estimate / sharded::shards(),
|
||||||
),
|
),
|
||||||
prev_index_to_index: Lock::new(IndexVec::from_elem_n(None, prev_graph_node_count)),
|
|
||||||
anon_id_seed,
|
anon_id_seed,
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
forbidden_edge,
|
forbidden_edge,
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
fingerprints: Lock::new(IndexVec::from_elem_n(None, new_node_count_estimate)),
|
fingerprints: Lock::new(IndexVec::from_elem_n(None, new_node_count_estimate)),
|
||||||
nodes_newly_allocated_in_current_session: new_node_dbg.then(|| {
|
nodes_in_current_session: new_node_dbg.then(|| {
|
||||||
Lock::new(FxHashMap::with_capacity_and_hasher(
|
Lock::new(FxHashMap::with_capacity_and_hasher(
|
||||||
new_node_count_estimate,
|
new_node_count_estimate,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
@@ -1219,7 +1248,7 @@ impl<D: Deps> CurrentDepGraph<D> {
|
|||||||
/// Writes the node to the current dep-graph and allocates a `DepNodeIndex` for it.
|
/// Writes the node to the current dep-graph and allocates a `DepNodeIndex` for it.
|
||||||
/// Assumes that this is a node that has no equivalent in the previous dep-graph.
|
/// Assumes that this is a node that has no equivalent in the previous dep-graph.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn alloc_new_node(
|
fn alloc_node(
|
||||||
&self,
|
&self,
|
||||||
key: DepNode,
|
key: DepNode,
|
||||||
edges: EdgesVec,
|
edges: EdgesVec,
|
||||||
@@ -1230,15 +1259,9 @@ impl<D: Deps> CurrentDepGraph<D> {
|
|||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
self.record_edge(dep_node_index, key, current_fingerprint);
|
self.record_edge(dep_node_index, key, current_fingerprint);
|
||||||
|
|
||||||
if let Some(ref nodes_newly_allocated_in_current_session) =
|
if let Some(ref nodes_in_current_session) = self.nodes_in_current_session {
|
||||||
self.nodes_newly_allocated_in_current_session
|
|
||||||
{
|
|
||||||
outline(|| {
|
outline(|| {
|
||||||
if nodes_newly_allocated_in_current_session
|
if nodes_in_current_session.lock().insert(key, dep_node_index).is_some() {
|
||||||
.lock()
|
|
||||||
.insert(key, dep_node_index)
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
panic!("Found duplicate dep-node {key:?}");
|
panic!("Found duplicate dep-node {key:?}");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1247,102 +1270,20 @@ impl<D: Deps> CurrentDepGraph<D> {
|
|||||||
dep_node_index
|
dep_node_index
|
||||||
}
|
}
|
||||||
|
|
||||||
fn intern_node(
|
|
||||||
&self,
|
|
||||||
prev_graph: &SerializedDepGraph,
|
|
||||||
key: DepNode,
|
|
||||||
edges: EdgesVec,
|
|
||||||
fingerprint: Option<Fingerprint>,
|
|
||||||
) -> (DepNodeIndex, Option<(SerializedDepNodeIndex, DepNodeColor)>) {
|
|
||||||
if let Some(prev_index) = prev_graph.node_to_index_opt(&key) {
|
|
||||||
let get_dep_node_index = |fingerprint| {
|
|
||||||
let mut prev_index_to_index = self.prev_index_to_index.lock();
|
|
||||||
|
|
||||||
let dep_node_index = match prev_index_to_index[prev_index] {
|
|
||||||
Some(dep_node_index) => dep_node_index,
|
|
||||||
None => {
|
|
||||||
let dep_node_index = self.encoder.send(key, fingerprint, edges);
|
|
||||||
prev_index_to_index[prev_index] = Some(dep_node_index);
|
|
||||||
dep_node_index
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
self.record_edge(dep_node_index, key, fingerprint);
|
|
||||||
|
|
||||||
dep_node_index
|
|
||||||
};
|
|
||||||
|
|
||||||
// Determine the color and index of the new `DepNode`.
|
|
||||||
if let Some(fingerprint) = fingerprint {
|
|
||||||
if fingerprint == prev_graph.fingerprint_by_index(prev_index) {
|
|
||||||
// This is a green node: it existed in the previous compilation,
|
|
||||||
// its query was re-executed, and it has the same result as before.
|
|
||||||
let dep_node_index = get_dep_node_index(fingerprint);
|
|
||||||
(dep_node_index, Some((prev_index, DepNodeColor::Green(dep_node_index))))
|
|
||||||
} else {
|
|
||||||
// This is a red node: it existed in the previous compilation, its query
|
|
||||||
// was re-executed, but it has a different result from before.
|
|
||||||
let dep_node_index = get_dep_node_index(fingerprint);
|
|
||||||
(dep_node_index, Some((prev_index, DepNodeColor::Red)))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// This is a red node, effectively: it existed in the previous compilation
|
|
||||||
// session, its query was re-executed, but it doesn't compute a result hash
|
|
||||||
// (i.e. it represents a `no_hash` query), so we have no way of determining
|
|
||||||
// whether or not the result was the same as before.
|
|
||||||
let dep_node_index = get_dep_node_index(Fingerprint::ZERO);
|
|
||||||
(dep_node_index, Some((prev_index, DepNodeColor::Red)))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let fingerprint = fingerprint.unwrap_or(Fingerprint::ZERO);
|
|
||||||
|
|
||||||
// This is a new node: it didn't exist in the previous compilation session.
|
|
||||||
let dep_node_index = self.alloc_new_node(key, edges, fingerprint);
|
|
||||||
|
|
||||||
(dep_node_index, None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn promote_node_and_deps_to_current(
|
|
||||||
&self,
|
|
||||||
prev_graph: &SerializedDepGraph,
|
|
||||||
prev_index: SerializedDepNodeIndex,
|
|
||||||
) -> DepNodeIndex {
|
|
||||||
self.debug_assert_not_in_new_nodes(prev_graph, prev_index);
|
|
||||||
|
|
||||||
let mut prev_index_to_index = self.prev_index_to_index.lock();
|
|
||||||
|
|
||||||
match prev_index_to_index[prev_index] {
|
|
||||||
Some(dep_node_index) => dep_node_index,
|
|
||||||
None => {
|
|
||||||
let dep_node_index = self.encoder.send_promoted(prev_index, &*prev_index_to_index);
|
|
||||||
prev_index_to_index[prev_index] = Some(dep_node_index);
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
self.record_edge(
|
|
||||||
dep_node_index,
|
|
||||||
prev_graph.index_to_node(prev_index),
|
|
||||||
prev_graph.fingerprint_by_index(prev_index),
|
|
||||||
);
|
|
||||||
dep_node_index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn debug_assert_not_in_new_nodes(
|
fn debug_assert_not_in_new_nodes(
|
||||||
&self,
|
&self,
|
||||||
prev_graph: &SerializedDepGraph,
|
prev_graph: &SerializedDepGraph,
|
||||||
prev_index: SerializedDepNodeIndex,
|
prev_index: SerializedDepNodeIndex,
|
||||||
) {
|
) {
|
||||||
let node = &prev_graph.index_to_node(prev_index);
|
if let Some(ref nodes_in_current_session) = self.nodes_in_current_session {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
!self
|
!nodes_in_current_session
|
||||||
.nodes_newly_allocated_in_current_session
|
.lock()
|
||||||
.as_ref()
|
.contains_key(&prev_graph.index_to_node(prev_index)),
|
||||||
.map_or(false, |set| set.lock().contains_key(node)),
|
"node from previous graph present in new node collection"
|
||||||
"node from previous graph present in new node collection"
|
);
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1389,36 +1330,40 @@ impl Default for TaskDeps {
|
|||||||
}
|
}
|
||||||
// A data structure that stores Option<DepNodeColor> values as a contiguous
|
// A data structure that stores Option<DepNodeColor> values as a contiguous
|
||||||
// array, using one u32 per entry.
|
// array, using one u32 per entry.
|
||||||
struct DepNodeColorMap {
|
pub(super) struct DepNodeColorMap {
|
||||||
values: IndexVec<SerializedDepNodeIndex, AtomicU32>,
|
values: IndexVec<SerializedDepNodeIndex, AtomicU32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const COMPRESSED_NONE: u32 = 0;
|
const COMPRESSED_NONE: u32 = u32::MAX;
|
||||||
const COMPRESSED_RED: u32 = 1;
|
const COMPRESSED_RED: u32 = u32::MAX - 1;
|
||||||
const COMPRESSED_FIRST_GREEN: u32 = 2;
|
|
||||||
|
|
||||||
impl DepNodeColorMap {
|
impl DepNodeColorMap {
|
||||||
fn new(size: usize) -> DepNodeColorMap {
|
fn new(size: usize) -> DepNodeColorMap {
|
||||||
|
debug_assert!(COMPRESSED_RED > DepNodeIndex::MAX_AS_U32);
|
||||||
DepNodeColorMap { values: (0..size).map(|_| AtomicU32::new(COMPRESSED_NONE)).collect() }
|
DepNodeColorMap { values: (0..size).map(|_| AtomicU32::new(COMPRESSED_NONE)).collect() }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get(&self, index: SerializedDepNodeIndex) -> Option<DepNodeColor> {
|
pub(super) fn current(&self, index: SerializedDepNodeIndex) -> Option<DepNodeIndex> {
|
||||||
|
let value = self.values[index].load(Ordering::Relaxed);
|
||||||
|
if value <= DepNodeIndex::MAX_AS_U32 { Some(DepNodeIndex::from_u32(value)) } else { None }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn get(&self, index: SerializedDepNodeIndex) -> Option<DepNodeColor> {
|
||||||
match self.values[index].load(Ordering::Acquire) {
|
match self.values[index].load(Ordering::Acquire) {
|
||||||
COMPRESSED_NONE => None,
|
COMPRESSED_NONE => None,
|
||||||
COMPRESSED_RED => Some(DepNodeColor::Red),
|
COMPRESSED_RED => Some(DepNodeColor::Red),
|
||||||
value => {
|
value => Some(DepNodeColor::Green(DepNodeIndex::from_u32(value))),
|
||||||
Some(DepNodeColor::Green(DepNodeIndex::from_u32(value - COMPRESSED_FIRST_GREEN)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn insert(&self, index: SerializedDepNodeIndex, color: DepNodeColor) {
|
pub(super) fn insert(&self, index: SerializedDepNodeIndex, color: DepNodeColor) {
|
||||||
self.values[index].store(
|
self.values[index].store(
|
||||||
match color {
|
match color {
|
||||||
DepNodeColor::Red => COMPRESSED_RED,
|
DepNodeColor::Red => COMPRESSED_RED,
|
||||||
DepNodeColor::Green(index) => index.as_u32() + COMPRESSED_FIRST_GREEN,
|
DepNodeColor::Green(index) => index.as_u32(),
|
||||||
},
|
},
|
||||||
Ordering::Release,
|
Ordering::Release,
|
||||||
)
|
)
|
||||||
@@ -1454,16 +1399,16 @@ fn panic_on_forbidden_read<D: Deps>(data: &DepGraphData<D>, dep_node_index: DepN
|
|||||||
let mut dep_node = None;
|
let mut dep_node = None;
|
||||||
|
|
||||||
// First try to find the dep node among those that already existed in the
|
// First try to find the dep node among those that already existed in the
|
||||||
// previous session
|
// previous session and has been marked green
|
||||||
for (prev_index, index) in data.current.prev_index_to_index.lock().iter_enumerated() {
|
for prev_index in data.colors.values.indices() {
|
||||||
if index == &Some(dep_node_index) {
|
if data.colors.current(prev_index) == Some(dep_node_index) {
|
||||||
dep_node = Some(data.previous.index_to_node(prev_index));
|
dep_node = Some(data.previous.index_to_node(prev_index));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if dep_node.is_none()
|
if dep_node.is_none()
|
||||||
&& let Some(nodes) = &data.current.nodes_newly_allocated_in_current_session
|
&& let Some(nodes) = &data.current.nodes_in_current_session
|
||||||
{
|
{
|
||||||
// Try to find it among the nodes allocated so far in this session
|
// Try to find it among the nodes allocated so far in this session
|
||||||
if let Some((node, _)) = nodes.lock().iter().find(|&(_, index)| *index == dep_node_index) {
|
if let Some((node, _)) = nodes.lock().iter().find(|&(_, index)| *index == dep_node_index) {
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixed
|
|||||||
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||||
use tracing::{debug, instrument};
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
|
use super::graph::{DepNodeColor, DepNodeColorMap};
|
||||||
use super::query::DepGraphQuery;
|
use super::query::DepGraphQuery;
|
||||||
use super::{DepKind, DepNode, DepNodeIndex, Deps};
|
use super::{DepKind, DepNode, DepNodeIndex, Deps};
|
||||||
use crate::dep_graph::edges::EdgesVec;
|
use crate::dep_graph::edges::EdgesVec;
|
||||||
@@ -441,7 +442,7 @@ impl NodeInfo {
|
|||||||
node: DepNode,
|
node: DepNode,
|
||||||
fingerprint: Fingerprint,
|
fingerprint: Fingerprint,
|
||||||
prev_index: SerializedDepNodeIndex,
|
prev_index: SerializedDepNodeIndex,
|
||||||
prev_index_to_index: &IndexVec<SerializedDepNodeIndex, Option<DepNodeIndex>>,
|
colors: &DepNodeColorMap,
|
||||||
previous: &SerializedDepGraph,
|
previous: &SerializedDepGraph,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
let edges = previous.edge_targets_from(prev_index);
|
let edges = previous.edge_targets_from(prev_index);
|
||||||
@@ -449,7 +450,7 @@ impl NodeInfo {
|
|||||||
|
|
||||||
// Find the highest edge in the new dep node indices
|
// Find the highest edge in the new dep node indices
|
||||||
let edge_max =
|
let edge_max =
|
||||||
edges.clone().map(|i| prev_index_to_index[i].unwrap().as_u32()).max().unwrap_or(0);
|
edges.clone().map(|i| colors.current(i).unwrap().as_u32()).max().unwrap_or(0);
|
||||||
|
|
||||||
let header = SerializedNodeHeader::<D>::new(node, fingerprint, edge_max, edge_count);
|
let header = SerializedNodeHeader::<D>::new(node, fingerprint, edge_max, edge_count);
|
||||||
e.write_array(header.bytes);
|
e.write_array(header.bytes);
|
||||||
@@ -460,7 +461,7 @@ impl NodeInfo {
|
|||||||
|
|
||||||
let bytes_per_index = header.bytes_per_index();
|
let bytes_per_index = header.bytes_per_index();
|
||||||
for node_index in edges {
|
for node_index in edges {
|
||||||
let node_index = prev_index_to_index[node_index].unwrap();
|
let node_index = colors.current(node_index).unwrap();
|
||||||
e.write_with(|dest| {
|
e.write_with(|dest| {
|
||||||
*dest = node_index.as_u32().to_le_bytes();
|
*dest = node_index.as_u32().to_le_bytes();
|
||||||
bytes_per_index
|
bytes_per_index
|
||||||
@@ -565,7 +566,7 @@ impl<D: Deps> EncoderState<D> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
prev_index: SerializedDepNodeIndex,
|
prev_index: SerializedDepNodeIndex,
|
||||||
record_graph: &Option<Lock<DepGraphQuery>>,
|
record_graph: &Option<Lock<DepGraphQuery>>,
|
||||||
prev_index_to_index: &IndexVec<SerializedDepNodeIndex, Option<DepNodeIndex>>,
|
colors: &DepNodeColorMap,
|
||||||
) -> DepNodeIndex {
|
) -> DepNodeIndex {
|
||||||
let node = self.previous.index_to_node(prev_index);
|
let node = self.previous.index_to_node(prev_index);
|
||||||
|
|
||||||
@@ -575,7 +576,7 @@ impl<D: Deps> EncoderState<D> {
|
|||||||
node,
|
node,
|
||||||
fingerprint,
|
fingerprint,
|
||||||
prev_index,
|
prev_index,
|
||||||
prev_index_to_index,
|
colors,
|
||||||
&self.previous,
|
&self.previous,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -585,7 +586,7 @@ impl<D: Deps> EncoderState<D> {
|
|||||||
|this| {
|
|this| {
|
||||||
this.previous
|
this.previous
|
||||||
.edge_targets_from(prev_index)
|
.edge_targets_from(prev_index)
|
||||||
.map(|i| prev_index_to_index[i].unwrap())
|
.map(|i| colors.current(i).unwrap())
|
||||||
.collect()
|
.collect()
|
||||||
},
|
},
|
||||||
record_graph,
|
record_graph,
|
||||||
@@ -719,18 +720,31 @@ impl<D: Deps> GraphEncoder<D> {
|
|||||||
|
|
||||||
/// Encodes a node that was promoted from the previous graph. It reads the information directly from
|
/// Encodes a node that was promoted from the previous graph. It reads the information directly from
|
||||||
/// the previous dep graph and expects all edges to already have a new dep node index assigned.
|
/// the previous dep graph and expects all edges to already have a new dep node index assigned.
|
||||||
|
///
|
||||||
|
/// This will also ensure the dep node is marked green.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn send_promoted(
|
pub(crate) fn send_promoted(
|
||||||
&self,
|
&self,
|
||||||
prev_index: SerializedDepNodeIndex,
|
prev_index: SerializedDepNodeIndex,
|
||||||
prev_index_to_index: &IndexVec<SerializedDepNodeIndex, Option<DepNodeIndex>>,
|
colors: &DepNodeColorMap,
|
||||||
) -> DepNodeIndex {
|
) -> DepNodeIndex {
|
||||||
let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph");
|
let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph");
|
||||||
self.status.lock().as_mut().unwrap().encode_promoted_node(
|
|
||||||
prev_index,
|
let mut status = self.status.lock();
|
||||||
&self.record_graph,
|
let status = status.as_mut().unwrap();
|
||||||
prev_index_to_index,
|
|
||||||
)
|
// Check colors inside the lock to avoid racing when `send_promoted` is called concurrently
|
||||||
|
// on the same index.
|
||||||
|
match colors.get(prev_index) {
|
||||||
|
None => {
|
||||||
|
let dep_node_index =
|
||||||
|
status.encode_promoted_node(prev_index, &self.record_graph, colors);
|
||||||
|
colors.insert(prev_index, DepNodeColor::Green(dep_node_index));
|
||||||
|
dep_node_index
|
||||||
|
}
|
||||||
|
Some(DepNodeColor::Green(dep_node_index)) => dep_node_index,
|
||||||
|
Some(DepNodeColor::Red) => panic!(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn finish(&self) -> FileEncodeResult {
|
pub(crate) fn finish(&self) -> FileEncodeResult {
|
||||||
|
|||||||
Reference in New Issue
Block a user