Skip to content

Commit 3dc1efd

Browse files
committed
Optimize try_mark_green and eliminate the lock on dep node colors
# Conflicts: # src/librustc/dep_graph/graph.rs
1 parent 8f20507 commit 3dc1efd

File tree

4 files changed

+117
-116
lines changed

4 files changed

+117
-116
lines changed

src/librustc/dep_graph/graph.rs

Lines changed: 99 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
1313
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1414
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
1515
use smallvec::SmallVec;
16-
use rustc_data_structures::sync::{Lrc, Lock};
16+
use rustc_data_structures::sync::{Lrc, Lock, AtomicU32, Ordering};
1717
use std::env;
1818
use std::hash::Hash;
1919
use std::collections::hash_map::Entry;
@@ -68,7 +68,7 @@ struct DepGraphData {
6868
/// nodes and edges as well as all fingerprints of nodes that have them.
6969
previous: PreviousDepGraph,
7070

71-
colors: Lock<DepNodeColorMap>,
71+
colors: DepNodeColorMap,
7272

7373
/// When we load, there may be `.o` files, cached mir, or other such
7474
/// things available to us. If we find that they are not dirty, we
@@ -94,7 +94,7 @@ impl DepGraph {
9494
dep_node_debug: Default::default(),
9595
current: Lock::new(CurrentDepGraph::new(prev_graph_node_count)),
9696
previous: prev_graph,
97-
colors: Lock::new(DepNodeColorMap::new(prev_graph_node_count)),
97+
colors: DepNodeColorMap::new(prev_graph_node_count),
9898
loaded_from_cache: Default::default(),
9999
})),
100100
}
@@ -292,12 +292,11 @@ impl DepGraph {
292292
DepNodeColor::Red
293293
};
294294

295-
let mut colors = data.colors.borrow_mut();
296-
debug_assert!(colors.get(prev_index).is_none(),
295+
debug_assert!(data.colors.get(prev_index).is_none(),
297296
"DepGraph::with_task() - Duplicate DepNodeColor \
298297
insertion for {:?}", key);
299298

300-
colors.insert(prev_index, color);
299+
data.colors.insert(prev_index, color);
301300
}
302301

303302
(result, dep_node_index)
@@ -498,7 +497,7 @@ impl DepGraph {
498497
pub fn node_color(&self, dep_node: &DepNode) -> Option<DepNodeColor> {
499498
if let Some(ref data) = self.data {
500499
if let Some(prev_index) = data.previous.node_to_index_opt(dep_node) {
501-
return data.colors.borrow().get(prev_index)
500+
return data.colors.get(prev_index)
502501
} else {
503502
// This is a node that did not exist in the previous compilation
504503
// session, so we consider it to be red.
@@ -509,56 +508,86 @@ impl DepGraph {
509508
None
510509
}
511510

512-
pub fn try_mark_green<'tcx>(&self,
513-
tcx: TyCtxt<'_, 'tcx, 'tcx>,
514-
dep_node: &DepNode)
515-
-> Option<DepNodeIndex> {
516-
debug!("try_mark_green({:?}) - BEGIN", dep_node);
517-
let data = self.data.as_ref().unwrap();
511+
/// Try to read a node index for the node dep_node.
512+
/// A node will have an index, when it's already been marked green, or when we can mark it
513+
/// green. This function will mark the current task as a reader of the specified node, when
514+
/// a node index can be found for that node.
515+
pub fn try_mark_green_and_read(
516+
&self,
517+
tcx: TyCtxt<'_, '_, '_>,
518+
dep_node: &DepNode
519+
) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> {
520+
self.try_mark_green(tcx, dep_node).map(|(prev_index, dep_node_index)| {
521+
debug_assert!(self.is_green(&dep_node));
522+
self.read_index(dep_node_index);
523+
(prev_index, dep_node_index)
524+
})
525+
}
518526

519-
#[cfg(not(parallel_queries))]
520-
debug_assert!(!data.current.borrow().node_to_node_index.contains_key(dep_node));
521-
522-
if dep_node.kind.is_input() {
523-
// We should only hit try_mark_green() for inputs that do not exist
524-
// anymore in the current compilation session. Existing inputs are
525-
// eagerly marked as either red/green before any queries are
526-
// executed.
527-
debug_assert!(dep_node.extract_def_id(tcx).is_none());
528-
debug!("try_mark_green({:?}) - END - DepNode is deleted input", dep_node);
529-
return None;
530-
}
527+
pub fn try_mark_green(
528+
&self,
529+
tcx: TyCtxt<'_, '_, '_>,
530+
dep_node: &DepNode
531+
) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> {
532+
debug_assert!(!dep_node.kind.is_input());
531533

532-
let (prev_deps, prev_dep_node_index) = match data.previous.edges_from(dep_node) {
533-
Some(prev) => {
534-
// This DepNode and the corresponding query invocation existed
535-
// in the previous compilation session too, so we can try to
536-
// mark it as green by recursively marking all of its
537-
// dependencies green.
538-
prev
539-
}
534+
// Return None if the dep graph is disabled
535+
let data = self.data.as_ref()?;
536+
537+
// Return None if the dep node didn't exist in the previous session
538+
let prev_index = data.previous.node_to_index_opt(dep_node)?;
539+
540+
match data.colors.get(prev_index) {
541+
Some(DepNodeColor::Green(dep_node_index)) => Some((prev_index, dep_node_index)),
542+
Some(DepNodeColor::Red) => None,
540543
None => {
541-
// This DepNode did not exist in the previous compilation session,
542-
// so we cannot mark it as green.
543-
debug!("try_mark_green({:?}) - END - DepNode does not exist in \
544-
current compilation session anymore", dep_node);
545-
return None
544+
self.try_mark_previous_green(
545+
tcx.global_tcx(),
546+
data,
547+
prev_index,
548+
&dep_node
549+
).map(|dep_node_index| {
550+
(prev_index, dep_node_index)
551+
})
546552
}
547-
};
553+
}
554+
}
548555

549-
debug_assert!(data.colors.borrow().get(prev_dep_node_index).is_none());
556+
fn try_mark_previous_green<'tcx>(
557+
&self,
558+
tcx: TyCtxt<'_, 'tcx, 'tcx>,
559+
data: &DepGraphData,
560+
prev_dep_node_index: SerializedDepNodeIndex,
561+
dep_node: &DepNode
562+
) -> Option<DepNodeIndex> {
563+
debug!("try_mark_previous_green({:?}) - BEGIN", dep_node);
564+
565+
#[cfg(not(parallel_queries))]
566+
{
567+
debug_assert!(!data.current.borrow().node_to_node_index.contains_key(dep_node));
568+
debug_assert!(data.colors.get(prev_dep_node_index).is_none());
569+
}
570+
571+
debug_assert!(!dep_node.kind.is_input());
572+
debug_assert_eq!(data.previous.index_to_node(prev_dep_node_index), *dep_node);
573+
574+
// We never try to mark inputs as green
575+
// FIXME: Make an debug_assert!
576+
assert!(!dep_node.kind.is_input());
577+
578+
let prev_deps = data.previous.edge_targets_from(prev_dep_node_index);
550579

551580
let mut current_deps = SmallVec::new();
552581

553582
for &dep_dep_node_index in prev_deps {
554-
let dep_dep_node_color = data.colors.borrow().get(dep_dep_node_index);
583+
let dep_dep_node_color = data.colors.get(dep_dep_node_index);
555584

556585
match dep_dep_node_color {
557586
Some(DepNodeColor::Green(node_index)) => {
558587
// This dependency has been marked as green before, we are
559588
// still fine and can continue with checking the other
560589
// dependencies.
561-
debug!("try_mark_green({:?}) --- found dependency {:?} to \
590+
debug!("try_mark_previous_green({:?}) --- found dependency {:?} to \
562591
be immediately green",
563592
dep_node,
564593
data.previous.index_to_node(dep_dep_node_index));
@@ -569,7 +598,7 @@ impl DepGraph {
569598
// compared to the previous compilation session. We cannot
570599
// mark the DepNode as green and also don't need to bother
571600
// with checking any of the other dependencies.
572-
debug!("try_mark_green({:?}) - END - dependency {:?} was \
601+
debug!("try_mark_previous_green({:?}) - END - dependency {:?} was \
573602
immediately red",
574603
dep_node,
575604
data.previous.index_to_node(dep_dep_node_index));
@@ -581,12 +610,18 @@ impl DepGraph {
581610
// We don't know the state of this dependency. If it isn't
582611
// an input node, let's try to mark it green recursively.
583612
if !dep_dep_node.kind.is_input() {
584-
debug!("try_mark_green({:?}) --- state of dependency {:?} \
613+
debug!("try_mark_previous_green({:?}) --- state of dependency {:?} \
585614
is unknown, trying to mark it green", dep_node,
586615
dep_dep_node);
587616

588-
if let Some(node_index) = self.try_mark_green(tcx, dep_dep_node) {
589-
debug!("try_mark_green({:?}) --- managed to MARK \
617+
let node_index = self.try_mark_previous_green(
618+
tcx,
619+
data,
620+
dep_dep_node_index,
621+
dep_dep_node
622+
);
623+
if let Some(node_index) = node_index {
624+
debug!("try_mark_previous_green({:?}) --- managed to MARK \
590625
dependency {:?} as green", dep_node, dep_dep_node);
591626
current_deps.push(node_index);
592627
continue;
@@ -616,28 +651,28 @@ impl DepGraph {
616651
}
617652

618653
// We failed to mark it green, so we try to force the query.
619-
debug!("try_mark_green({:?}) --- trying to force \
654+
debug!("try_mark_previous_green({:?}) --- trying to force \
620655
dependency {:?}", dep_node, dep_dep_node);
621656
if ::ty::query::force_from_dep_node(tcx, dep_dep_node) {
622-
let dep_dep_node_color = data.colors.borrow().get(dep_dep_node_index);
657+
let dep_dep_node_color = data.colors.get(dep_dep_node_index);
623658

624659
match dep_dep_node_color {
625660
Some(DepNodeColor::Green(node_index)) => {
626-
debug!("try_mark_green({:?}) --- managed to \
661+
debug!("try_mark_previous_green({:?}) --- managed to \
627662
FORCE dependency {:?} to green",
628663
dep_node, dep_dep_node);
629664
current_deps.push(node_index);
630665
}
631666
Some(DepNodeColor::Red) => {
632-
debug!("try_mark_green({:?}) - END - \
667+
debug!("try_mark_previous_green({:?}) - END - \
633668
dependency {:?} was red after forcing",
634669
dep_node,
635670
dep_dep_node);
636671
return None
637672
}
638673
None => {
639674
if !tcx.sess.has_errors() {
640-
bug!("try_mark_green() - Forcing the DepNode \
675+
bug!("try_mark_previous_green() - Forcing the DepNode \
641676
should have set its color")
642677
} else {
643678
// If the query we just forced has resulted
@@ -649,7 +684,7 @@ impl DepGraph {
649684
}
650685
} else {
651686
// The DepNode could not be forced.
652-
debug!("try_mark_green({:?}) - END - dependency {:?} \
687+
debug!("try_mark_previous_green({:?}) - END - dependency {:?} \
653688
could not be forced", dep_node, dep_dep_node);
654689
return None
655690
}
@@ -701,16 +736,15 @@ impl DepGraph {
701736
}
702737

703738
// ... and finally storing a "Green" entry in the color map.
704-
let mut colors = data.colors.borrow_mut();
705739
// Multiple threads can all write the same color here
706740
#[cfg(not(parallel_queries))]
707-
debug_assert!(colors.get(prev_dep_node_index).is_none(),
708-
"DepGraph::try_mark_green() - Duplicate DepNodeColor \
741+
debug_assert!(data.colors.get(prev_dep_node_index).is_none(),
742+
"DepGraph::try_mark_previous_green() - Duplicate DepNodeColor \
709743
insertion for {:?}", dep_node);
710744

711-
colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index));
745+
data.colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index));
712746

713-
debug!("try_mark_green({:?}) - END - successfully marked as green", dep_node);
747+
debug!("try_mark_previous_green({:?}) - END - successfully marked as green", dep_node);
714748
Some(dep_node_index)
715749
}
716750

@@ -731,9 +765,8 @@ impl DepGraph {
731765
pub fn exec_cache_promotions<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) {
732766
let green_nodes: Vec<DepNode> = {
733767
let data = self.data.as_ref().unwrap();
734-
let colors = data.colors.borrow();
735-
colors.values.indices().filter_map(|prev_index| {
736-
match colors.get(prev_index) {
768+
data.colors.values.indices().filter_map(|prev_index| {
769+
match data.colors.get(prev_index) {
737770
Some(DepNodeColor::Green(_)) => {
738771
let dep_node = data.previous.index_to_node(prev_index);
739772
if dep_node.cache_on_disk(tcx) {
@@ -1083,7 +1116,7 @@ pub enum OpenTask {
10831116
// A data structure that stores Option<DepNodeColor> values as a contiguous
10841117
// array, using one u32 per entry.
10851118
struct DepNodeColorMap {
1086-
values: IndexVec<SerializedDepNodeIndex, u32>,
1119+
values: IndexVec<SerializedDepNodeIndex, AtomicU32>,
10871120
}
10881121

10891122
const COMPRESSED_NONE: u32 = 0;
@@ -1093,12 +1126,12 @@ const COMPRESSED_FIRST_GREEN: u32 = 2;
10931126
impl DepNodeColorMap {
10941127
fn new(size: usize) -> DepNodeColorMap {
10951128
DepNodeColorMap {
1096-
values: IndexVec::from_elem_n(COMPRESSED_NONE, size)
1129+
values: (0..size).map(|_| AtomicU32::new(COMPRESSED_NONE)).collect(),
10971130
}
10981131
}
10991132

11001133
fn get(&self, index: SerializedDepNodeIndex) -> Option<DepNodeColor> {
1101-
match self.values[index] {
1134+
match self.values[index].load(Ordering::Acquire) {
11021135
COMPRESSED_NONE => None,
11031136
COMPRESSED_RED => Some(DepNodeColor::Red),
11041137
value => Some(DepNodeColor::Green(DepNodeIndex::from_u32(
@@ -1107,10 +1140,10 @@ impl DepNodeColorMap {
11071140
}
11081141
}
11091142

1110-
fn insert(&mut self, index: SerializedDepNodeIndex, color: DepNodeColor) {
1111-
self.values[index] = match color {
1143+
fn insert(&self, index: SerializedDepNodeIndex, color: DepNodeColor) {
1144+
self.values[index].store(match color {
11121145
DepNodeColor::Red => COMPRESSED_RED,
11131146
DepNodeColor::Green(index) => index.as_u32() + COMPRESSED_FIRST_GREEN,
1114-
}
1147+
}, Ordering::Release)
11151148
}
11161149
}

src/librustc/dep_graph/prev.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,11 @@ impl PreviousDepGraph {
2929
}
3030

3131
#[inline]
32-
pub fn edges_from(&self,
33-
dep_node: &DepNode)
34-
-> Option<(&[SerializedDepNodeIndex], SerializedDepNodeIndex)> {
35-
self.index
36-
.get(dep_node)
37-
.map(|&node_index| {
38-
(self.data.edge_targets_from(node_index), node_index)
39-
})
32+
pub fn edge_targets_from(
33+
&self,
34+
dep_node_index: SerializedDepNodeIndex
35+
) -> &[SerializedDepNodeIndex] {
36+
self.data.edge_targets_from(dep_node_index)
4037
}
4138

4239
#[inline]

0 commit comments

Comments
 (0)