Skip to content

Commit e62d47d

Browse files
committed
Auto merge of #139410 - Zoxc:fix-dep-graph-no-prev-map, r=oli-obk
Reuse the index from promoted nodes when coloring executed tasks #138824 did not correctly handle the case where a dep node was promoted green, but later or concurrently executed. It resulted in multiple dep nodes being allocated to it. This fixes that by checking that the node was not previously green in the encoder lock. This also fixes a race when forcing diagnostic nodes introduced in #138824. #138824 should get reverted on beta. This should fix #139110. r? `@oli-obk`
2 parents 0fe8f34 + 1c568bb commit e62d47d

File tree

2 files changed

+88
-36
lines changed

2 files changed

+88
-36
lines changed

Diff for: compiler/rustc_query_system/src/dep_graph/graph.rs

+50-33
Original file line numberDiff line numberDiff line change
@@ -141,15 +141,15 @@ impl<D: Deps> DepGraph<D> {
141141
let colors = DepNodeColorMap::new(prev_graph_node_count);
142142

143143
// Instantiate a node with zero dependencies only once for anonymous queries.
144-
let _green_node_index = current.alloc_node(
144+
let _green_node_index = current.alloc_new_node(
145145
DepNode { kind: D::DEP_KIND_ANON_ZERO_DEPS, hash: current.anon_id_seed.into() },
146146
EdgesVec::new(),
147147
Fingerprint::ZERO,
148148
);
149149
assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_ZERO_DEPS_ANON_NODE);
150150

151151
// Instantiate a dependy-less red node only once for anonymous queries.
152-
let red_node_index = current.alloc_node(
152+
let red_node_index = current.alloc_new_node(
153153
DepNode { kind: D::DEP_KIND_RED, hash: Fingerprint::ZERO.into() },
154154
EdgesVec::new(),
155155
Fingerprint::ZERO,
@@ -438,7 +438,7 @@ impl<D: Deps> DepGraphData<D> {
438438
// memory impact of this `anon_node_to_index` map remains tolerable, and helps
439439
// us avoid useless growth of the graph with almost-equivalent nodes.
440440
self.current.anon_node_to_index.get_or_insert_with(target_dep_node, || {
441-
self.current.alloc_node(target_dep_node, task_deps, Fingerprint::ZERO)
441+
self.current.alloc_new_node(target_dep_node, task_deps, Fingerprint::ZERO)
442442
})
443443
}
444444
};
@@ -680,8 +680,8 @@ impl<D: Deps> DepGraphData<D> {
680680
qcx: Qcx,
681681
diagnostic: &DiagInner,
682682
) -> DepNodeIndex {
683-
// Use `send` so we get an unique index, even though the dep node is not.
684-
let dep_node_index = self.current.encoder.send(
683+
// Use `send_new` so we get an unique index, even though the dep node is not.
684+
let dep_node_index = self.current.encoder.send_new(
685685
DepNode {
686686
kind: D::DEP_KIND_SIDE_EFFECT,
687687
hash: PackedFingerprint::from(Fingerprint::ZERO),
@@ -713,20 +713,22 @@ impl<D: Deps> DepGraphData<D> {
713713
}
714714
}
715715

716-
// Manually recreate the node as `promote_node_and_deps_to_current` expects all
717-
// green dependencies.
718-
let dep_node_index = self.current.encoder.send(
716+
// Use `send_and_color` as `promote_node_and_deps_to_current` expects all
717+
// green dependencies. `send_and_color` will also prevent multiple nodes
718+
// being encoded for concurrent calls.
719+
let dep_node_index = self.current.encoder.send_and_color(
720+
prev_index,
721+
&self.colors,
719722
DepNode {
720723
kind: D::DEP_KIND_SIDE_EFFECT,
721724
hash: PackedFingerprint::from(Fingerprint::ZERO),
722725
},
723726
Fingerprint::ZERO,
724727
std::iter::once(DepNodeIndex::FOREVER_RED_NODE).collect(),
728+
true,
725729
);
730+
// This will just overwrite the same value for concurrent calls.
726731
qcx.store_side_effect(dep_node_index, side_effect);
727-
728-
// Mark the node as green.
729-
self.colors.insert(prev_index, DepNodeColor::Green(dep_node_index));
730732
})
731733
}
732734

@@ -736,38 +738,43 @@ impl<D: Deps> DepGraphData<D> {
736738
edges: EdgesVec,
737739
fingerprint: Option<Fingerprint>,
738740
) -> DepNodeIndex {
739-
let dep_node_index =
740-
self.current.alloc_node(key, edges, fingerprint.unwrap_or(Fingerprint::ZERO));
741-
742741
if let Some(prev_index) = self.previous.node_to_index_opt(&key) {
743742
// Determine the color and index of the new `DepNode`.
744-
let color = if let Some(fingerprint) = fingerprint {
743+
let is_green = if let Some(fingerprint) = fingerprint {
745744
if fingerprint == self.previous.fingerprint_by_index(prev_index) {
746745
// This is a green node: it existed in the previous compilation,
747746
// its query was re-executed, and it has the same result as before.
748-
DepNodeColor::Green(dep_node_index)
747+
true
749748
} else {
750749
// This is a red node: it existed in the previous compilation, its query
751750
// was re-executed, but it has a different result from before.
752-
DepNodeColor::Red
751+
false
753752
}
754753
} else {
755754
// This is a red node, effectively: it existed in the previous compilation
756755
// session, its query was re-executed, but it doesn't compute a result hash
757756
// (i.e. it represents a `no_hash` query), so we have no way of determining
758757
// whether or not the result was the same as before.
759-
DepNodeColor::Red
758+
false
760759
};
761760

762-
debug_assert!(
763-
self.colors.get(prev_index).is_none(),
764-
"DepGraph::with_task() - Duplicate DepNodeColor insertion for {key:?}",
761+
let fingerprint = fingerprint.unwrap_or(Fingerprint::ZERO);
762+
763+
let dep_node_index = self.current.encoder.send_and_color(
764+
prev_index,
765+
&self.colors,
766+
key,
767+
fingerprint,
768+
edges,
769+
is_green,
765770
);
766771

767-
self.colors.insert(prev_index, color);
768-
}
772+
self.current.record_node(dep_node_index, key, fingerprint);
769773

770-
dep_node_index
774+
dep_node_index
775+
} else {
776+
self.current.alloc_new_node(key, edges, fingerprint.unwrap_or(Fingerprint::ZERO))
777+
}
771778
}
772779

773780
fn promote_node_and_deps_to_current(&self, prev_index: SerializedDepNodeIndex) -> DepNodeIndex {
@@ -1246,19 +1253,15 @@ impl<D: Deps> CurrentDepGraph<D> {
12461253
assert_eq!(previous, fingerprint, "Unstable fingerprints for {:?}", key);
12471254
}
12481255

1249-
/// Writes the node to the current dep-graph and allocates a `DepNodeIndex` for it.
1250-
/// Assumes that this is a node that has no equivalent in the previous dep-graph.
12511256
#[inline(always)]
1252-
fn alloc_node(
1257+
fn record_node(
12531258
&self,
1259+
dep_node_index: DepNodeIndex,
12541260
key: DepNode,
1255-
edges: EdgesVec,
1256-
current_fingerprint: Fingerprint,
1257-
) -> DepNodeIndex {
1258-
let dep_node_index = self.encoder.send(key, current_fingerprint, edges);
1259-
1261+
_current_fingerprint: Fingerprint,
1262+
) {
12601263
#[cfg(debug_assertions)]
1261-
self.record_edge(dep_node_index, key, current_fingerprint);
1264+
self.record_edge(dep_node_index, key, _current_fingerprint);
12621265

12631266
if let Some(ref nodes_in_current_session) = self.nodes_in_current_session {
12641267
outline(|| {
@@ -1267,6 +1270,20 @@ impl<D: Deps> CurrentDepGraph<D> {
12671270
}
12681271
});
12691272
}
1273+
}
1274+
1275+
/// Writes the node to the current dep-graph and allocates a `DepNodeIndex` for it.
1276+
/// Assumes that this is a node that has no equivalent in the previous dep-graph.
1277+
#[inline(always)]
1278+
fn alloc_new_node(
1279+
&self,
1280+
key: DepNode,
1281+
edges: EdgesVec,
1282+
current_fingerprint: Fingerprint,
1283+
) -> DepNodeIndex {
1284+
let dep_node_index = self.encoder.send_new(key, current_fingerprint, edges);
1285+
1286+
self.record_node(dep_node_index, key, current_fingerprint);
12701287

12711288
dep_node_index
12721289
}

Diff for: compiler/rustc_query_system/src/dep_graph/serialized.rs

+38-3
Original file line numberDiff line numberDiff line change
@@ -707,7 +707,8 @@ impl<D: Deps> GraphEncoder<D> {
707707
}
708708
}
709709

710-
pub(crate) fn send(
710+
/// Encodes a node that does not exists in the previous graph.
711+
pub(crate) fn send_new(
711712
&self,
712713
node: DepNode,
713714
fingerprint: Fingerprint,
@@ -718,6 +719,40 @@ impl<D: Deps> GraphEncoder<D> {
718719
self.status.lock().as_mut().unwrap().encode_node(&node, &self.record_graph)
719720
}
720721

722+
/// Encodes a node that exists in the previous graph, but was re-executed.
723+
///
724+
/// This will also ensure the dep node is colored either red or green.
725+
pub(crate) fn send_and_color(
726+
&self,
727+
prev_index: SerializedDepNodeIndex,
728+
colors: &DepNodeColorMap,
729+
node: DepNode,
730+
fingerprint: Fingerprint,
731+
edges: EdgesVec,
732+
is_green: bool,
733+
) -> DepNodeIndex {
734+
let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph");
735+
let node = NodeInfo { node, fingerprint, edges };
736+
737+
let mut status = self.status.lock();
738+
let status = status.as_mut().unwrap();
739+
740+
// Check colors inside the lock to avoid racing when `send_promoted` is called concurrently
741+
// on the same index.
742+
match colors.get(prev_index) {
743+
None => {
744+
let dep_node_index = status.encode_node(&node, &self.record_graph);
745+
colors.insert(
746+
prev_index,
747+
if is_green { DepNodeColor::Green(dep_node_index) } else { DepNodeColor::Red },
748+
);
749+
dep_node_index
750+
}
751+
Some(DepNodeColor::Green(dep_node_index)) => dep_node_index,
752+
Some(DepNodeColor::Red) => panic!(),
753+
}
754+
}
755+
721756
/// Encodes a node that was promoted from the previous graph. It reads the information directly from
722757
/// the previous dep graph and expects all edges to already have a new dep node index assigned.
723758
///
@@ -733,8 +768,8 @@ impl<D: Deps> GraphEncoder<D> {
733768
let mut status = self.status.lock();
734769
let status = status.as_mut().unwrap();
735770

736-
// Check colors inside the lock to avoid racing when `send_promoted` is called concurrently
737-
// on the same index.
771+
// Check colors inside the lock to avoid racing when `send_promoted` or `send_and_color`
772+
// is called concurrently on the same index.
738773
match colors.get(prev_index) {
739774
None => {
740775
let dep_node_index =

0 commit comments

Comments
 (0)