Skip to content

Commit c8fa82c

Browse files
committed
Auto merge of #63756 - Zoxc:sharded-dep-graph-1, r=nikomatsakis
Use more fine grained locks for the dep graph Split out from #61845. r? @michaelwoerister cc @aturon
2 parents 0e8a4b4 + b6a5740 commit c8fa82c

File tree

1 file changed

+72
-60
lines changed

1 file changed

+72
-60
lines changed

src/librustc/dep_graph/graph.rs

+72-60
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
33
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
44
use rustc_index::vec::{Idx, IndexVec};
55
use smallvec::SmallVec;
6-
use rustc_data_structures::sync::{Lrc, Lock, AtomicU32, Ordering};
6+
use rustc_data_structures::sync::{Lrc, Lock, AtomicU32, AtomicU64, Ordering};
7+
use std::sync::atomic::Ordering::SeqCst;
78
use std::env;
89
use std::hash::Hash;
910
use std::collections::hash_map::Entry;
@@ -53,7 +54,7 @@ struct DepGraphData {
5354
/// tracking. The `current` field is the dependency graph of only the
5455
/// current compilation session: We don't merge the previous dep-graph into
5556
/// current one anymore.
56-
current: Lock<CurrentDepGraph>,
57+
current: CurrentDepGraph,
5758

5859
/// The dep-graph from the previous compilation session. It contains all
5960
/// nodes and edges as well as all fingerprints of nodes that have them.
@@ -95,7 +96,7 @@ impl DepGraph {
9596
data: Some(Lrc::new(DepGraphData {
9697
previous_work_products: prev_work_products,
9798
dep_node_debug: Default::default(),
98-
current: Lock::new(CurrentDepGraph::new(prev_graph_node_count)),
99+
current: CurrentDepGraph::new(prev_graph_node_count),
99100
emitting_diagnostics: Default::default(),
100101
emitting_diagnostics_cond_var: Condvar::new(),
101102
previous: prev_graph,
@@ -117,13 +118,12 @@ impl DepGraph {
117118
}
118119

119120
pub fn query(&self) -> DepGraphQuery {
120-
let current_dep_graph = self.data.as_ref().unwrap().current.borrow();
121-
let nodes: Vec<_> = current_dep_graph.data.iter().map(|n| n.node).collect();
121+
let data = self.data.as_ref().unwrap().current.data.lock();
122+
let nodes: Vec<_> = data.iter().map(|n| n.node).collect();
122123
let mut edges = Vec::new();
123-
for (from, edge_targets) in current_dep_graph.data.iter()
124-
.map(|d| (d.node, &d.edges)) {
124+
for (from, edge_targets) in data.iter().map(|d| (d.node, &d.edges)) {
125125
for &edge_target in edge_targets.iter() {
126-
let to = current_dep_graph.data[edge_target].node;
126+
let to = data[edge_target].node;
127127
edges.push((from, to));
128128
}
129129
}
@@ -202,7 +202,7 @@ impl DepGraph {
202202
read_set: Default::default(),
203203
}),
204204
|data, key, fingerprint, task| {
205-
data.borrow_mut().complete_task(key, task.unwrap(), fingerprint)
205+
data.complete_task(key, task.unwrap(), fingerprint)
206206
},
207207
hash_result)
208208
}
@@ -223,7 +223,7 @@ impl DepGraph {
223223
self.with_task_impl(key, cx, input, true, identity_fn,
224224
|_| None,
225225
|data, key, fingerprint, _| {
226-
data.borrow_mut().alloc_node(key, SmallVec::new(), fingerprint)
226+
data.alloc_node(key, SmallVec::new(), fingerprint)
227227
},
228228
hash_result::<R>)
229229
}
@@ -236,7 +236,7 @@ impl DepGraph {
236236
no_tcx: bool,
237237
task: fn(C, A) -> R,
238238
create_task: fn(DepNode) -> Option<TaskDeps>,
239-
finish_task_and_alloc_depnode: fn(&Lock<CurrentDepGraph>,
239+
finish_task_and_alloc_depnode: fn(&CurrentDepGraph,
240240
DepNode,
241241
Fingerprint,
242242
Option<TaskDeps>) -> DepNodeIndex,
@@ -350,7 +350,6 @@ impl DepGraph {
350350
(r, task_deps.into_inner())
351351
});
352352
let dep_node_index = data.current
353-
.borrow_mut()
354353
.complete_anon_task(dep_kind, task_deps);
355354
(result, dep_node_index)
356355
} else {
@@ -374,18 +373,17 @@ impl DepGraph {
374373
self.with_task_impl(key, cx, arg, false, task,
375374
|_| None,
376375
|data, key, fingerprint, _| {
377-
let mut current = data.borrow_mut();
378-
current.alloc_node(key, smallvec![], fingerprint)
376+
data.alloc_node(key, smallvec![], fingerprint)
379377
},
380378
hash_result)
381379
}
382380

383381
#[inline]
384382
pub fn read(&self, v: DepNode) {
385383
if let Some(ref data) = self.data {
386-
let current = data.current.borrow_mut();
387-
if let Some(&dep_node_index) = current.node_to_node_index.get(&v) {
388-
std::mem::drop(current);
384+
let map = data.current.node_to_node_index.lock();
385+
if let Some(dep_node_index) = map.get(&v).copied() {
386+
std::mem::drop(map);
389387
data.read_index(dep_node_index);
390388
} else {
391389
bug!("DepKind {:?} should be pre-allocated but isn't.", v.kind)
@@ -406,8 +404,8 @@ impl DepGraph {
406404
.as_ref()
407405
.unwrap()
408406
.current
409-
.borrow_mut()
410407
.node_to_node_index
408+
.lock()
411409
.get(dep_node)
412410
.cloned()
413411
.unwrap()
@@ -416,16 +414,16 @@ impl DepGraph {
416414
#[inline]
417415
pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool {
418416
if let Some(ref data) = self.data {
419-
data.current.borrow_mut().node_to_node_index.contains_key(dep_node)
417+
data.current.node_to_node_index.lock().contains_key(dep_node)
420418
} else {
421419
false
422420
}
423421
}
424422

425423
#[inline]
426424
pub fn fingerprint_of(&self, dep_node_index: DepNodeIndex) -> Fingerprint {
427-
let current = self.data.as_ref().expect("dep graph enabled").current.borrow_mut();
428-
current.data[dep_node_index].fingerprint
425+
let data = self.data.as_ref().expect("dep graph enabled").current.data.lock();
426+
data[dep_node_index].fingerprint
429427
}
430428

431429
pub fn prev_fingerprint_of(&self, dep_node: &DepNode) -> Option<Fingerprint> {
@@ -479,32 +477,29 @@ impl DepGraph {
479477

480478
pub fn edge_deduplication_data(&self) -> Option<(u64, u64)> {
481479
if cfg!(debug_assertions) {
482-
let current_dep_graph = self.data.as_ref().unwrap().current.borrow();
480+
let current_dep_graph = &self.data.as_ref().unwrap().current;
483481

484-
Some((current_dep_graph.total_read_count,
485-
current_dep_graph.total_duplicate_read_count))
482+
Some((current_dep_graph.total_read_count.load(SeqCst),
483+
current_dep_graph.total_duplicate_read_count.load(SeqCst)))
486484
} else {
487485
None
488486
}
489487
}
490488

491489
pub fn serialize(&self) -> SerializedDepGraph {
492-
let current_dep_graph = self.data.as_ref().unwrap().current.borrow();
490+
let data = self.data.as_ref().unwrap().current.data.lock();
493491

494492
let fingerprints: IndexVec<SerializedDepNodeIndex, _> =
495-
current_dep_graph.data.iter().map(|d| d.fingerprint).collect();
493+
data.iter().map(|d| d.fingerprint).collect();
496494
let nodes: IndexVec<SerializedDepNodeIndex, _> =
497-
current_dep_graph.data.iter().map(|d| d.node).collect();
495+
data.iter().map(|d| d.node).collect();
498496

499-
let total_edge_count: usize = current_dep_graph.data.iter()
500-
.map(|d| d.edges.len())
501-
.sum();
497+
let total_edge_count: usize = data.iter().map(|d| d.edges.len()).sum();
502498

503499
let mut edge_list_indices = IndexVec::with_capacity(nodes.len());
504500
let mut edge_list_data = Vec::with_capacity(total_edge_count);
505501

506-
for (current_dep_node_index, edges) in current_dep_graph.data.iter_enumerated()
507-
.map(|(i, d)| (i, &d.edges)) {
502+
for (current_dep_node_index, edges) in data.iter_enumerated().map(|(i, d)| (i, &d.edges)) {
508503
let start = edge_list_data.len() as u32;
509504
// This should really just be a memcpy :/
510505
edge_list_data.extend(edges.iter().map(|i| SerializedDepNodeIndex::new(i.index())));
@@ -600,7 +595,7 @@ impl DepGraph {
600595

601596
#[cfg(not(parallel_compiler))]
602597
{
603-
debug_assert!(!data.current.borrow().node_to_node_index.contains_key(dep_node));
598+
debug_assert!(!data.current.node_to_node_index.lock().contains_key(dep_node));
604599
debug_assert!(data.colors.get(prev_dep_node_index).is_none());
605600
}
606601

@@ -733,15 +728,13 @@ impl DepGraph {
733728
// There may be multiple threads trying to mark the same dep node green concurrently
734729

735730
let dep_node_index = {
736-
let mut current = data.current.borrow_mut();
737-
738731
// Copy the fingerprint from the previous graph,
739732
// so we don't have to recompute it
740733
let fingerprint = data.previous.fingerprint_by_index(prev_dep_node_index);
741734

742735
// We allocating an entry for the node in the current dependency graph and
743736
// adding all the appropriate edges imported from the previous graph
744-
current.intern_node(*dep_node, current_deps, fingerprint)
737+
data.current.intern_node(*dep_node, current_deps, fingerprint)
745738
};
746739

747740
// ... emitting any stored diagnostic ...
@@ -917,9 +910,27 @@ struct DepNodeData {
917910
fingerprint: Fingerprint,
918911
}
919912

913+
/// `CurrentDepGraph` stores the dependency graph for the current session.
914+
/// It will be populated as we run queries or tasks.
915+
///
916+
/// The nodes in it are identified by an index (`DepNodeIndex`).
917+
/// The data for each node is stored in its `DepNodeData`, found in the `data` field.
918+
///
919+
/// We never remove nodes from the graph: they are only added.
920+
///
921+
/// This struct uses two locks internally. The `data` and `node_to_node_index` fields are
922+
/// locked separately. Operations that take a `DepNodeIndex` typically just access
923+
/// the data field.
924+
///
925+
/// The only operation that must manipulate both locks is adding new nodes, in which case
926+
/// we first acquire the `node_to_node_index` lock and then, once a new node is to be inserted,
927+
/// acquire the lock on `data.`
920928
pub(super) struct CurrentDepGraph {
921-
data: IndexVec<DepNodeIndex, DepNodeData>,
922-
node_to_node_index: FxHashMap<DepNode, DepNodeIndex>,
929+
data: Lock<IndexVec<DepNodeIndex, DepNodeData>>,
930+
node_to_node_index: Lock<FxHashMap<DepNode, DepNodeIndex>>,
931+
932+
/// Used to trap when a specific edge is added to the graph.
933+
/// This is used for debug purposes and is only active with `debug_assertions`.
923934
#[allow(dead_code)]
924935
forbidden_edge: Option<EdgeFilter>,
925936

@@ -936,8 +947,10 @@ pub(super) struct CurrentDepGraph {
936947
/// the `DepGraph` is created.
937948
anon_id_seed: Fingerprint,
938949

939-
total_read_count: u64,
940-
total_duplicate_read_count: u64,
950+
/// These are simple counters that are for profiling and
951+
/// debugging and only active with `debug_assertions`.
952+
total_read_count: AtomicU64,
953+
total_duplicate_read_count: AtomicU64,
941954
}
942955

943956
impl CurrentDepGraph {
@@ -971,28 +984,28 @@ impl CurrentDepGraph {
971984
let new_node_count_estimate = (prev_graph_node_count * 102) / 100 + 200;
972985

973986
CurrentDepGraph {
974-
data: IndexVec::with_capacity(new_node_count_estimate),
975-
node_to_node_index: FxHashMap::with_capacity_and_hasher(
987+
data: Lock::new(IndexVec::with_capacity(new_node_count_estimate)),
988+
node_to_node_index: Lock::new(FxHashMap::with_capacity_and_hasher(
976989
new_node_count_estimate,
977990
Default::default(),
978-
),
991+
)),
979992
anon_id_seed: stable_hasher.finish(),
980993
forbidden_edge,
981-
total_read_count: 0,
982-
total_duplicate_read_count: 0,
994+
total_read_count: AtomicU64::new(0),
995+
total_duplicate_read_count: AtomicU64::new(0),
983996
}
984997
}
985998

986999
fn complete_task(
987-
&mut self,
1000+
&self,
9881001
node: DepNode,
9891002
task_deps: TaskDeps,
9901003
fingerprint: Fingerprint
9911004
) -> DepNodeIndex {
9921005
self.alloc_node(node, task_deps.reads, fingerprint)
9931006
}
9941007

995-
fn complete_anon_task(&mut self, kind: DepKind, task_deps: TaskDeps) -> DepNodeIndex {
1008+
fn complete_anon_task(&self, kind: DepKind, task_deps: TaskDeps) -> DepNodeIndex {
9961009
debug_assert!(!kind.is_eval_always());
9971010

9981011
let mut hasher = StableHasher::new();
@@ -1017,28 +1030,27 @@ impl CurrentDepGraph {
10171030
}
10181031

10191032
fn alloc_node(
1020-
&mut self,
1033+
&self,
10211034
dep_node: DepNode,
10221035
edges: SmallVec<[DepNodeIndex; 8]>,
10231036
fingerprint: Fingerprint
10241037
) -> DepNodeIndex {
1025-
debug_assert!(!self.node_to_node_index.contains_key(&dep_node));
1038+
debug_assert!(!self.node_to_node_index.lock().contains_key(&dep_node));
10261039
self.intern_node(dep_node, edges, fingerprint)
10271040
}
10281041

10291042
fn intern_node(
1030-
&mut self,
1043+
&self,
10311044
dep_node: DepNode,
10321045
edges: SmallVec<[DepNodeIndex; 8]>,
10331046
fingerprint: Fingerprint
10341047
) -> DepNodeIndex {
1035-
debug_assert_eq!(self.node_to_node_index.len(), self.data.len());
1036-
1037-
match self.node_to_node_index.entry(dep_node) {
1048+
match self.node_to_node_index.lock().entry(dep_node) {
10381049
Entry::Occupied(entry) => *entry.get(),
10391050
Entry::Vacant(entry) => {
1040-
let dep_node_index = DepNodeIndex::new(self.data.len());
1041-
self.data.push(DepNodeData {
1051+
let mut data = self.data.lock();
1052+
let dep_node_index = DepNodeIndex::new(data.len());
1053+
data.push(DepNodeData {
10421054
node: dep_node,
10431055
edges,
10441056
fingerprint
@@ -1057,17 +1069,17 @@ impl DepGraphData {
10571069
if let Some(task_deps) = icx.task_deps {
10581070
let mut task_deps = task_deps.lock();
10591071
if cfg!(debug_assertions) {
1060-
self.current.lock().total_read_count += 1;
1072+
self.current.total_read_count.fetch_add(1, SeqCst);
10611073
}
10621074
if task_deps.read_set.insert(source) {
10631075
task_deps.reads.push(source);
10641076

10651077
#[cfg(debug_assertions)]
10661078
{
10671079
if let Some(target) = task_deps.node {
1068-
let graph = self.current.lock();
1069-
if let Some(ref forbidden_edge) = graph.forbidden_edge {
1070-
let source = graph.data[source].node;
1080+
let data = self.current.data.lock();
1081+
if let Some(ref forbidden_edge) = self.current.forbidden_edge {
1082+
let source = data[source].node;
10711083
if forbidden_edge.test(&source, &target) {
10721084
bug!("forbidden edge {:?} -> {:?} created",
10731085
source,
@@ -1077,7 +1089,7 @@ impl DepGraphData {
10771089
}
10781090
}
10791091
} else if cfg!(debug_assertions) {
1080-
self.current.lock().total_duplicate_read_count += 1;
1092+
self.current.total_duplicate_read_count.fetch_add(1, SeqCst);
10811093
}
10821094
}
10831095
})

0 commit comments

Comments
 (0)