Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 527b8d4

Browse files
committedJan 18, 2019
Auto merge of #57065 - Zoxc:graph-tweaks, r=michaelwoerister
Optimize try_mark_green and eliminate the lock on dep node colors Blocked on #56614 r? @michaelwoerister
2 parents 38650b6 + 1313678 commit 527b8d4

File tree

4 files changed

+117
-113
lines changed

4 files changed

+117
-113
lines changed
 

‎src/librustc/dep_graph/graph.rs

Lines changed: 99 additions & 63 deletions
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,89 @@ 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());
537+
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)?;
535543

536-
let (prev_deps, prev_dep_node_index) = match data.previous.edges_from(dep_node) {
537-
Some(prev) => {
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,
547+
None => {
538548
// This DepNode and the corresponding query invocation existed
539549
// in the previous compilation session too, so we can try to
540550
// mark it as green by recursively marking all of its
541551
// dependencies green.
542-
prev
543-
}
544-
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
552+
self.try_mark_previous_green(
553+
tcx.global_tcx(),
554+
data,
555+
prev_index,
556+
&dep_node
557+
).map(|dep_node_index| {
558+
(prev_index, dep_node_index)
559+
})
550560
}
551-
};
561+
}
562+
}
563+
564+
/// Try to mark a dep-node which existed in the previous compilation session as green
565+
fn try_mark_previous_green<'tcx>(
566+
&self,
567+
tcx: TyCtxt<'_, 'tcx, 'tcx>,
568+
data: &DepGraphData,
569+
prev_dep_node_index: SerializedDepNodeIndex,
570+
dep_node: &DepNode
571+
) -> Option<DepNodeIndex> {
572+
debug!("try_mark_previous_green({:?}) - BEGIN", dep_node);
552573

553-
debug_assert!(data.colors.borrow().get(prev_dep_node_index).is_none());
574+
#[cfg(not(parallel_queries))]
575+
{
576+
debug_assert!(!data.current.borrow().node_to_node_index.contains_key(dep_node));
577+
debug_assert!(data.colors.get(prev_dep_node_index).is_none());
578+
}
579+
580+
// We never try to mark inputs as green
581+
debug_assert!(!dep_node.kind.is_input());
582+
583+
debug_assert_eq!(data.previous.index_to_node(prev_dep_node_index), *dep_node);
584+
585+
let prev_deps = data.previous.edge_targets_from(prev_dep_node_index);
554586

555587
let mut current_deps = SmallVec::new();
556588

557589
for &dep_dep_node_index in prev_deps {
558-
let dep_dep_node_color = data.colors.borrow().get(dep_dep_node_index);
590+
let dep_dep_node_color = data.colors.get(dep_dep_node_index);
559591

560592
match dep_dep_node_color {
561593
Some(DepNodeColor::Green(node_index)) => {
562594
// This dependency has been marked as green before, we are
563595
// still fine and can continue with checking the other
564596
// dependencies.
565-
debug!("try_mark_green({:?}) --- found dependency {:?} to \
597+
debug!("try_mark_previous_green({:?}) --- found dependency {:?} to \
566598
be immediately green",
567599
dep_node,
568600
data.previous.index_to_node(dep_dep_node_index));
@@ -573,7 +605,7 @@ impl DepGraph {
573605
// compared to the previous compilation session. We cannot
574606
// mark the DepNode as green and also don't need to bother
575607
// with checking any of the other dependencies.
576-
debug!("try_mark_green({:?}) - END - dependency {:?} was \
608+
debug!("try_mark_previous_green({:?}) - END - dependency {:?} was \
577609
immediately red",
578610
dep_node,
579611
data.previous.index_to_node(dep_dep_node_index));
@@ -585,12 +617,18 @@ impl DepGraph {
585617
// We don't know the state of this dependency. If it isn't
586618
// an input node, let's try to mark it green recursively.
587619
if !dep_dep_node.kind.is_input() {
588-
debug!("try_mark_green({:?}) --- state of dependency {:?} \
620+
debug!("try_mark_previous_green({:?}) --- state of dependency {:?} \
589621
is unknown, trying to mark it green", dep_node,
590622
dep_dep_node);
591623

592-
if let Some(node_index) = self.try_mark_green(tcx, dep_dep_node) {
593-
debug!("try_mark_green({:?}) --- managed to MARK \
624+
let node_index = self.try_mark_previous_green(
625+
tcx,
626+
data,
627+
dep_dep_node_index,
628+
dep_dep_node
629+
);
630+
if let Some(node_index) = node_index {
631+
debug!("try_mark_previous_green({:?}) --- managed to MARK \
594632
dependency {:?} as green", dep_node, dep_dep_node);
595633
current_deps.push(node_index);
596634
continue;
@@ -620,28 +658,28 @@ impl DepGraph {
620658
}
621659

622660
// We failed to mark it green, so we try to force the query.
623-
debug!("try_mark_green({:?}) --- trying to force \
661+
debug!("try_mark_previous_green({:?}) --- trying to force \
624662
dependency {:?}", dep_node, dep_dep_node);
625663
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);
664+
let dep_dep_node_color = data.colors.get(dep_dep_node_index);
627665

628666
match dep_dep_node_color {
629667
Some(DepNodeColor::Green(node_index)) => {
630-
debug!("try_mark_green({:?}) --- managed to \
668+
debug!("try_mark_previous_green({:?}) --- managed to \
631669
FORCE dependency {:?} to green",
632670
dep_node, dep_dep_node);
633671
current_deps.push(node_index);
634672
}
635673
Some(DepNodeColor::Red) => {
636-
debug!("try_mark_green({:?}) - END - \
674+
debug!("try_mark_previous_green({:?}) - END - \
637675
dependency {:?} was red after forcing",
638676
dep_node,
639677
dep_dep_node);
640678
return None
641679
}
642680
None => {
643681
if !tcx.sess.has_errors() {
644-
bug!("try_mark_green() - Forcing the DepNode \
682+
bug!("try_mark_previous_green() - Forcing the DepNode \
645683
should have set its color")
646684
} else {
647685
// If the query we just forced has resulted
@@ -653,7 +691,7 @@ impl DepGraph {
653691
}
654692
} else {
655693
// The DepNode could not be forced.
656-
debug!("try_mark_green({:?}) - END - dependency {:?} \
694+
debug!("try_mark_previous_green({:?}) - END - dependency {:?} \
657695
could not be forced", dep_node, dep_dep_node);
658696
return None
659697
}
@@ -705,16 +743,15 @@ impl DepGraph {
705743
}
706744

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

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

717-
debug!("try_mark_green({:?}) - END - successfully marked as green", dep_node);
754+
debug!("try_mark_previous_green({:?}) - END - successfully marked as green", dep_node);
718755
Some(dep_node_index)
719756
}
720757

@@ -735,9 +772,8 @@ impl DepGraph {
735772
pub fn exec_cache_promotions<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) {
736773
let green_nodes: Vec<DepNode> = {
737774
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) {
775+
data.colors.values.indices().filter_map(|prev_index| {
776+
match data.colors.get(prev_index) {
741777
Some(DepNodeColor::Green(_)) => {
742778
let dep_node = data.previous.index_to_node(prev_index);
743779
if dep_node.cache_on_disk(tcx) {
@@ -1035,7 +1071,7 @@ pub struct TaskDeps {
10351071
// A data structure that stores Option<DepNodeColor> values as a contiguous
10361072
// array, using one u32 per entry.
10371073
struct DepNodeColorMap {
1038-
values: IndexVec<SerializedDepNodeIndex, u32>,
1074+
values: IndexVec<SerializedDepNodeIndex, AtomicU32>,
10391075
}
10401076

10411077
const COMPRESSED_NONE: u32 = 0;
@@ -1045,12 +1081,12 @@ const COMPRESSED_FIRST_GREEN: u32 = 2;
10451081
impl DepNodeColorMap {
10461082
fn new(size: usize) -> DepNodeColorMap {
10471083
DepNodeColorMap {
1048-
values: IndexVec::from_elem_n(COMPRESSED_NONE, size)
1084+
values: (0..size).map(|_| AtomicU32::new(COMPRESSED_NONE)).collect(),
10491085
}
10501086
}
10511087

10521088
fn get(&self, index: SerializedDepNodeIndex) -> Option<DepNodeColor> {
1053-
match self.values[index] {
1089+
match self.values[index].load(Ordering::Acquire) {
10541090
COMPRESSED_NONE => None,
10551091
COMPRESSED_RED => Some(DepNodeColor::Red),
10561092
value => Some(DepNodeColor::Green(DepNodeIndex::from_u32(
@@ -1059,10 +1095,10 @@ impl DepNodeColorMap {
10591095
}
10601096
}
10611097

1062-
fn insert(&mut self, index: SerializedDepNodeIndex, color: DepNodeColor) {
1063-
self.values[index] = match color {
1098+
fn insert(&self, index: SerializedDepNodeIndex, color: DepNodeColor) {
1099+
self.values[index].store(match color {
10641100
DepNodeColor::Red => COMPRESSED_RED,
10651101
DepNodeColor::Green(index) => index.as_u32() + COMPRESSED_FIRST_GREEN,
1066-
}
1102+
}, Ordering::Release)
10671103
}
10681104
}

‎src/librustc/dep_graph/prev.rs

Lines changed: 5 additions & 8 deletions
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]

‎src/librustc/ty/query/plumbing.rs

Lines changed: 8 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//! that generate the actual methods on tcx which find and execute the
33
//! provider, manage the caches, and so forth.
44
5-
use dep_graph::{DepNodeIndex, DepNode, DepKind, DepNodeColor};
5+
use dep_graph::{DepNodeIndex, DepNode, DepKind, SerializedDepNodeIndex};
66
use errors::DiagnosticBuilder;
77
use errors::Level;
88
use errors::Diagnostic;
@@ -335,40 +335,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
335335
eprintln!("end of query stack");
336336
}
337337

338-
/// Try to read a node index for the node dep_node.
339-
/// A node will have an index, when it's already been marked green, or when we can mark it
340-
/// green. This function will mark the current task as a reader of the specified node, when
341-
/// a node index can be found for that node.
342-
pub(super) fn try_mark_green_and_read(self, dep_node: &DepNode) -> Option<DepNodeIndex> {
343-
match self.dep_graph.node_color(dep_node) {
344-
Some(DepNodeColor::Green(dep_node_index)) => {
345-
self.dep_graph.read_index(dep_node_index);
346-
Some(dep_node_index)
347-
}
348-
Some(DepNodeColor::Red) => {
349-
None
350-
}
351-
None => {
352-
// try_mark_green (called below) will panic when full incremental
353-
// compilation is disabled. If that's the case, we can't try to mark nodes
354-
// as green anyway, so we can safely return None here.
355-
if !self.dep_graph.is_fully_enabled() {
356-
return None;
357-
}
358-
match self.dep_graph.try_mark_green(self.global_tcx(), &dep_node) {
359-
Some(dep_node_index) => {
360-
debug_assert!(self.dep_graph.is_green(&dep_node));
361-
self.dep_graph.read_index(dep_node_index);
362-
Some(dep_node_index)
363-
}
364-
None => {
365-
None
366-
}
367-
}
368-
}
369-
}
370-
}
371-
372338
#[inline(never)]
373339
fn try_get_with<Q: QueryDescription<'gcx>>(
374340
self,
@@ -435,10 +401,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
435401
}
436402

437403
if !dep_node.kind.is_input() {
438-
if let Some(dep_node_index) = self.try_mark_green_and_read(&dep_node) {
404+
if let Some((prev_dep_node_index,
405+
dep_node_index)) = self.dep_graph.try_mark_green_and_read(self,
406+
&dep_node) {
439407
return Ok(self.load_from_disk_and_cache_in_memory::<Q>(
440408
key,
441409
job,
410+
prev_dep_node_index,
442411
dep_node_index,
443412
&dep_node
444413
))
@@ -454,6 +423,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
454423
self,
455424
key: Q::Key,
456425
job: JobOwner<'a, 'gcx, Q>,
426+
prev_dep_node_index: SerializedDepNodeIndex,
457427
dep_node_index: DepNodeIndex,
458428
dep_node: &DepNode
459429
) -> Q::Value
@@ -466,10 +436,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
466436
// First we try to load the result from the on-disk cache
467437
let result = if Q::cache_on_disk(key.clone()) &&
468438
self.sess.opts.debugging_opts.incremental_queries {
469-
let prev_dep_node_index =
470-
self.dep_graph.prev_dep_node_index_of(dep_node);
471-
let result = Q::try_load_from_disk(self.global_tcx(),
472-
prev_dep_node_index);
439+
let result = Q::try_load_from_disk(self.global_tcx(), prev_dep_node_index);
473440

474441
// We always expect to find a cached result for things that
475442
// can be forced from DepNode.
@@ -624,7 +591,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
624591
// Ensuring an "input" or anonymous query makes no sense
625592
assert!(!dep_node.kind.is_anon());
626593
assert!(!dep_node.kind.is_input());
627-
if self.try_mark_green_and_read(&dep_node).is_none() {
594+
if self.dep_graph.try_mark_green_and_read(self, &dep_node).is_none() {
628595
// A None return from `try_mark_green_and_read` means that this is either
629596
// a new dep node or that the dep node has already been marked red.
630597
// Either way, we can't call `dep_graph.read()` as we don't have the

‎src/librustc_data_structures/sync.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ cfg_if! {
7070
pub struct Atomic<T: Copy>(Cell<T>);
7171

7272
impl<T: Copy> Atomic<T> {
73+
#[inline]
7374
pub fn new(v: T) -> Self {
7475
Atomic(Cell::new(v))
7576
}
@@ -80,10 +81,12 @@ cfg_if! {
8081
self.0.into_inner()
8182
}
8283

84+
#[inline]
8385
pub fn load(&self, _: Ordering) -> T {
8486
self.0.get()
8587
}
8688

89+
#[inline]
8790
pub fn store(&self, val: T, _: Ordering) {
8891
self.0.set(val)
8992
}
@@ -118,6 +121,7 @@ cfg_if! {
118121

119122
pub type AtomicUsize = Atomic<usize>;
120123
pub type AtomicBool = Atomic<bool>;
124+
pub type AtomicU32 = Atomic<u32>;
121125
pub type AtomicU64 = Atomic<u64>;
122126

123127
pub use self::serial_join as join;
@@ -223,7 +227,7 @@ cfg_if! {
223227
pub use parking_lot::MutexGuard as LockGuard;
224228
pub use parking_lot::MappedMutexGuard as MappedLockGuard;
225229

226-
pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU64};
230+
pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32, AtomicU64};
227231

228232
pub use std::sync::Arc as Lrc;
229233
pub use std::sync::Weak as Weak;

0 commit comments

Comments
 (0)
Please sign in to comment.