Skip to content

Commit 8ef7413

Browse files
committed
Optimize try_mark_green and eliminate the lock on dep node colors
1 parent 33e6df4 commit 8ef7413

File tree

4 files changed

+117
-116
lines changed

4 files changed

+117
-116
lines changed

src/librustc/dep_graph/graph.rs

+99-66
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
33
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
44
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
55
use smallvec::SmallVec;
6-
use rustc_data_structures::sync::{Lrc, Lock};
6+
use rustc_data_structures::sync::{Lrc, Lock, AtomicU32, Ordering};
77
use std::env;
88
use std::hash::Hash;
99
use std::collections::hash_map::Entry;
@@ -58,7 +58,7 @@ struct DepGraphData {
5858
/// nodes and edges as well as all fingerprints of nodes that have them.
5959
previous: PreviousDepGraph,
6060

61-
colors: Lock<DepNodeColorMap>,
61+
colors: DepNodeColorMap,
6262

6363
/// When we load, there may be `.o` files, cached mir, or other such
6464
/// things available to us. If we find that they are not dirty, we
@@ -84,7 +84,7 @@ impl DepGraph {
8484
dep_node_debug: Default::default(),
8585
current: Lock::new(CurrentDepGraph::new(prev_graph_node_count)),
8686
previous: prev_graph,
87-
colors: Lock::new(DepNodeColorMap::new(prev_graph_node_count)),
87+
colors: DepNodeColorMap::new(prev_graph_node_count),
8888
loaded_from_cache: Default::default(),
8989
})),
9090
}
@@ -282,12 +282,11 @@ impl DepGraph {
282282
DepNodeColor::Red
283283
};
284284

285-
let mut colors = data.colors.borrow_mut();
286-
debug_assert!(colors.get(prev_index).is_none(),
285+
debug_assert!(data.colors.get(prev_index).is_none(),
287286
"DepGraph::with_task() - Duplicate DepNodeColor \
288287
insertion for {:?}", key);
289288

290-
colors.insert(prev_index, color);
289+
data.colors.insert(prev_index, color);
291290
}
292291

293292
(result, dep_node_index)
@@ -502,7 +501,7 @@ impl DepGraph {
502501
pub fn node_color(&self, dep_node: &DepNode) -> Option<DepNodeColor> {
503502
if let Some(ref data) = self.data {
504503
if let Some(prev_index) = data.previous.node_to_index_opt(dep_node) {
505-
return data.colors.borrow().get(prev_index)
504+
return data.colors.get(prev_index)
506505
} else {
507506
// This is a node that did not exist in the previous compilation
508507
// session, so we consider it to be red.
@@ -513,56 +512,86 @@ impl DepGraph {
513512
None
514513
}
515514

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

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

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

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

555584
let mut current_deps = SmallVec::new();
556585

557586
for &dep_dep_node_index in prev_deps {
558-
let dep_dep_node_color = data.colors.borrow().get(dep_dep_node_index);
587+
let dep_dep_node_color = data.colors.get(dep_dep_node_index);
559588

560589
match dep_dep_node_color {
561590
Some(DepNodeColor::Green(node_index)) => {
562591
// This dependency has been marked as green before, we are
563592
// still fine and can continue with checking the other
564593
// dependencies.
565-
debug!("try_mark_green({:?}) --- found dependency {:?} to \
594+
debug!("try_mark_previous_green({:?}) --- found dependency {:?} to \
566595
be immediately green",
567596
dep_node,
568597
data.previous.index_to_node(dep_dep_node_index));
@@ -573,7 +602,7 @@ impl DepGraph {
573602
// compared to the previous compilation session. We cannot
574603
// mark the DepNode as green and also don't need to bother
575604
// with checking any of the other dependencies.
576-
debug!("try_mark_green({:?}) - END - dependency {:?} was \
605+
debug!("try_mark_previous_green({:?}) - END - dependency {:?} was \
577606
immediately red",
578607
dep_node,
579608
data.previous.index_to_node(dep_dep_node_index));
@@ -585,12 +614,18 @@ impl DepGraph {
585614
// We don't know the state of this dependency. If it isn't
586615
// an input node, let's try to mark it green recursively.
587616
if !dep_dep_node.kind.is_input() {
588-
debug!("try_mark_green({:?}) --- state of dependency {:?} \
617+
debug!("try_mark_previous_green({:?}) --- state of dependency {:?} \
589618
is unknown, trying to mark it green", dep_node,
590619
dep_dep_node);
591620

592-
if let Some(node_index) = self.try_mark_green(tcx, dep_dep_node) {
593-
debug!("try_mark_green({:?}) --- managed to MARK \
621+
let node_index = self.try_mark_previous_green(
622+
tcx,
623+
data,
624+
dep_dep_node_index,
625+
dep_dep_node
626+
);
627+
if let Some(node_index) = node_index {
628+
debug!("try_mark_previous_green({:?}) --- managed to MARK \
594629
dependency {:?} as green", dep_node, dep_dep_node);
595630
current_deps.push(node_index);
596631
continue;
@@ -620,28 +655,28 @@ impl DepGraph {
620655
}
621656

622657
// We failed to mark it green, so we try to force the query.
623-
debug!("try_mark_green({:?}) --- trying to force \
658+
debug!("try_mark_previous_green({:?}) --- trying to force \
624659
dependency {:?}", dep_node, dep_dep_node);
625660
if ::ty::query::force_from_dep_node(tcx, dep_dep_node) {
626-
let dep_dep_node_color = data.colors.borrow().get(dep_dep_node_index);
661+
let dep_dep_node_color = data.colors.get(dep_dep_node_index);
627662

628663
match dep_dep_node_color {
629664
Some(DepNodeColor::Green(node_index)) => {
630-
debug!("try_mark_green({:?}) --- managed to \
665+
debug!("try_mark_previous_green({:?}) --- managed to \
631666
FORCE dependency {:?} to green",
632667
dep_node, dep_dep_node);
633668
current_deps.push(node_index);
634669
}
635670
Some(DepNodeColor::Red) => {
636-
debug!("try_mark_green({:?}) - END - \
671+
debug!("try_mark_previous_green({:?}) - END - \
637672
dependency {:?} was red after forcing",
638673
dep_node,
639674
dep_dep_node);
640675
return None
641676
}
642677
None => {
643678
if !tcx.sess.has_errors() {
644-
bug!("try_mark_green() - Forcing the DepNode \
679+
bug!("try_mark_previous_green() - Forcing the DepNode \
645680
should have set its color")
646681
} else {
647682
// If the query we just forced has resulted
@@ -653,7 +688,7 @@ impl DepGraph {
653688
}
654689
} else {
655690
// The DepNode could not be forced.
656-
debug!("try_mark_green({:?}) - END - dependency {:?} \
691+
debug!("try_mark_previous_green({:?}) - END - dependency {:?} \
657692
could not be forced", dep_node, dep_dep_node);
658693
return None
659694
}
@@ -705,16 +740,15 @@ impl DepGraph {
705740
}
706741

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

715-
colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index));
749+
data.colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index));
716750

717-
debug!("try_mark_green({:?}) - END - successfully marked as green", dep_node);
751+
debug!("try_mark_previous_green({:?}) - END - successfully marked as green", dep_node);
718752
Some(dep_node_index)
719753
}
720754

@@ -735,9 +769,8 @@ impl DepGraph {
735769
pub fn exec_cache_promotions<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) {
736770
let green_nodes: Vec<DepNode> = {
737771
let data = self.data.as_ref().unwrap();
738-
let colors = data.colors.borrow();
739-
colors.values.indices().filter_map(|prev_index| {
740-
match colors.get(prev_index) {
772+
data.colors.values.indices().filter_map(|prev_index| {
773+
match data.colors.get(prev_index) {
741774
Some(DepNodeColor::Green(_)) => {
742775
let dep_node = data.previous.index_to_node(prev_index);
743776
if dep_node.cache_on_disk(tcx) {
@@ -1035,7 +1068,7 @@ pub struct TaskDeps {
10351068
// A data structure that stores Option<DepNodeColor> values as a contiguous
10361069
// array, using one u32 per entry.
10371070
struct DepNodeColorMap {
1038-
values: IndexVec<SerializedDepNodeIndex, u32>,
1071+
values: IndexVec<SerializedDepNodeIndex, AtomicU32>,
10391072
}
10401073

10411074
const COMPRESSED_NONE: u32 = 0;
@@ -1045,12 +1078,12 @@ const COMPRESSED_FIRST_GREEN: u32 = 2;
10451078
impl DepNodeColorMap {
10461079
fn new(size: usize) -> DepNodeColorMap {
10471080
DepNodeColorMap {
1048-
values: IndexVec::from_elem_n(COMPRESSED_NONE, size)
1081+
values: (0..size).map(|_| AtomicU32::new(COMPRESSED_NONE)).collect(),
10491082
}
10501083
}
10511084

10521085
fn get(&self, index: SerializedDepNodeIndex) -> Option<DepNodeColor> {
1053-
match self.values[index] {
1086+
match self.values[index].load(Ordering::Acquire) {
10541087
COMPRESSED_NONE => None,
10551088
COMPRESSED_RED => Some(DepNodeColor::Red),
10561089
value => Some(DepNodeColor::Green(DepNodeIndex::from_u32(
@@ -1059,10 +1092,10 @@ impl DepNodeColorMap {
10591092
}
10601093
}
10611094

1062-
fn insert(&mut self, index: SerializedDepNodeIndex, color: DepNodeColor) {
1063-
self.values[index] = match color {
1095+
fn insert(&self, index: SerializedDepNodeIndex, color: DepNodeColor) {
1096+
self.values[index].store(match color {
10641097
DepNodeColor::Red => COMPRESSED_RED,
10651098
DepNodeColor::Green(index) => index.as_u32() + COMPRESSED_FIRST_GREEN,
1066-
}
1099+
}, Ordering::Release)
10671100
}
10681101
}

src/librustc/dep_graph/prev.rs

+5-8
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,11 @@ impl PreviousDepGraph {
1919
}
2020

2121
#[inline]
22-
pub fn edges_from(&self,
23-
dep_node: &DepNode)
24-
-> Option<(&[SerializedDepNodeIndex], SerializedDepNodeIndex)> {
25-
self.index
26-
.get(dep_node)
27-
.map(|&node_index| {
28-
(self.data.edge_targets_from(node_index), node_index)
29-
})
22+
pub fn edge_targets_from(
23+
&self,
24+
dep_node_index: SerializedDepNodeIndex
25+
) -> &[SerializedDepNodeIndex] {
26+
self.data.edge_targets_from(dep_node_index)
3027
}
3128

3229
#[inline]

0 commit comments

Comments
 (0)