@@ -43,16 +43,33 @@ impl std::convert::From<DepNodeIndex> for QueryInvocationId {
43
43
}
44
44
45
45
struct DepGraphData < K : DepKind > {
46
- /// The new encoding of the dependency graph, optimized for red/green
47
- /// tracking. The `current` field is the dependency graph of only the
48
- /// current compilation session: We don't merge the previous dep-graph into
49
- /// current one anymore, but we do reference shared data to save space.
50
- current : CurrentDepGraph ,
51
-
52
46
/// The dep-graph from the previous compilation session. It contains all
53
47
/// nodes and edges as well as all fingerprints of nodes that have them.
54
48
previous : RwLock < SerializedDepGraph < K > > ,
55
49
50
+ /// Used to trap when a specific edge is added to the graph.
51
+ /// This is used for debug purposes and is only active with `debug_assertions`.
52
+ #[ allow( dead_code) ]
53
+ forbidden_edge : Option < EdgeFilter > ,
54
+
55
+ /// Anonymous `DepNode`s are nodes whose IDs we compute from the list of
56
+ /// their edges. This has the beneficial side-effect that multiple anonymous
57
+ /// nodes can be coalesced into one without changing the semantics of the
58
+ /// dependency graph. However, the merging of nodes can lead to a subtle
59
+ /// problem during red-green marking: The color of an anonymous node from
60
+ /// the current session might "shadow" the color of the node with the same
61
+ /// ID from the previous session. In order to side-step this problem, we make
62
+ /// sure that anonymous `NodeId`s allocated in different sessions don't overlap.
63
+ /// This is implemented by mixing a session-key into the ID fingerprint of
64
+ /// each anon node. The session-key is just a random number generated when
65
+ /// the `DepGraph` is created.
66
+ anon_id_seed : Fingerprint ,
67
+
68
+ /// These are simple counters that are for profiling and
69
+ /// debugging and only active with `debug_assertions`.
70
+ total_read_count : AtomicU64 ,
71
+ total_duplicate_read_count : AtomicU64 ,
72
+
56
73
/// A set of loaded diagnostics that is in the progress of being emitted.
57
74
emitting_diagnostics : Lock < FxHashSet < DepNodeIndex > > ,
58
75
@@ -80,13 +97,70 @@ impl<K: DepKind> DepGraph<K> {
80
97
prev_graph : SerializedDepGraph < K > ,
81
98
prev_work_products : FxHashMap < WorkProductId , WorkProduct > ,
82
99
) -> DepGraph < K > {
83
- let prev_graph_node_count = prev_graph. serialized_node_count ( ) ;
100
+ let _prev_graph_node_count = prev_graph. serialized_node_count ( ) ;
101
+
102
+ use std:: time:: { SystemTime , UNIX_EPOCH } ;
103
+
104
+ let duration = SystemTime :: now ( ) . duration_since ( UNIX_EPOCH ) . unwrap ( ) ;
105
+ let nanos = duration. as_secs ( ) * 1_000_000_000 + duration. subsec_nanos ( ) as u64 ;
106
+ let mut stable_hasher = StableHasher :: new ( ) ;
107
+ nanos. hash ( & mut stable_hasher) ;
108
+
109
+ let forbidden_edge = if cfg ! ( debug_assertions) {
110
+ match env:: var ( "RUST_FORBID_DEP_GRAPH_EDGE" ) {
111
+ Ok ( s) => match EdgeFilter :: new ( & s) {
112
+ Ok ( f) => Some ( f) ,
113
+ Err ( err) => panic ! ( "RUST_FORBID_DEP_GRAPH_EDGE invalid: {}" , err) ,
114
+ } ,
115
+ Err ( _) => None ,
116
+ }
117
+ } else {
118
+ None
119
+ } ;
120
+
121
+ /*
122
+ // Pre-allocate the dep node structures. We over-allocate a little so
123
+ // that we hopefully don't have to re-allocate during this compilation
124
+ // session. The over-allocation for new nodes is 2% plus a small
125
+ // constant to account for the fact that in very small crates 2% might
126
+ // not be enough. The allocation for red and green node data doesn't
127
+ // include a constant, as we don't want to allocate anything for these
128
+ // structures during full incremental builds, where they aren't used.
129
+ //
130
+ // These estimates are based on the distribution of node and edge counts
131
+ // seen in rustc-perf benchmarks, adjusted somewhat to account for the
132
+ // fact that these benchmarks aren't perfectly representative.
133
+ //
134
+ // FIXME Use a collection type that doesn't copy node and edge data and
135
+ // grow multiplicatively on reallocation. Without such a collection or
136
+ // solution having the same effect, there is a performance hazard here
137
+ // in both time and space, as growing these collections means copying a
138
+ // large amount of data and doubling already large buffer capacities. A
139
+ // solution for this will also mean that it's less important to get
140
+ // these estimates right.
141
+ let new_node_count_estimate = (prev_graph_node_count * 2) / 100 + 200;
142
+ let red_node_count_estimate = (prev_graph_node_count * 3) / 100;
143
+ let light_green_node_count_estimate = (prev_graph_node_count * 25) / 100;
144
+ let total_node_count_estimate = prev_graph_node_count + new_node_count_estimate;
145
+
146
+ let average_edges_per_node_estimate = 6;
147
+ let unshared_edge_count_estimate = average_edges_per_node_estimate
148
+ * (new_node_count_estimate + red_node_count_estimate + light_green_node_count_estimate);
149
+ */
150
+
151
+ // We store a large collection of these in `prev_index_to_index` during
152
+ // non-full incremental builds, and want to ensure that the element size
153
+ // doesn't inadvertently increase.
154
+ static_assert_size ! ( Option <DepNodeIndex >, 4 ) ;
84
155
85
156
DepGraph {
86
157
data : Some ( Lrc :: new ( DepGraphData {
87
158
previous_work_products : prev_work_products,
88
159
dep_node_debug : Default :: default ( ) ,
89
- current : CurrentDepGraph :: new ( prev_graph_node_count) ,
160
+ anon_id_seed : stable_hasher. finish ( ) ,
161
+ forbidden_edge,
162
+ total_read_count : AtomicU64 :: new ( 0 ) ,
163
+ total_duplicate_read_count : AtomicU64 :: new ( 0 ) ,
90
164
emitting_diagnostics : Default :: default ( ) ,
91
165
previous : RwLock :: new ( prev_graph) ,
92
166
} ) ) ,
@@ -239,7 +313,7 @@ impl<K: DepKind> DepGraph<K> {
239
313
// Fingerprint::combine() is faster than sending Fingerprint
240
314
// through the StableHasher (at least as long as StableHasher
241
315
// is so slow).
242
- hash : data. current . anon_id_seed . combine ( hasher. finish ( ) ) . into ( ) ,
316
+ hash : data. anon_id_seed . combine ( hasher. finish ( ) ) . into ( ) ,
243
317
} ;
244
318
245
319
let mut previous = data. previous . write ( ) ;
@@ -272,7 +346,7 @@ impl<K: DepKind> DepGraph<K> {
272
346
let mut task_deps = task_deps. lock ( ) ;
273
347
let task_deps = & mut * task_deps;
274
348
if cfg ! ( debug_assertions) {
275
- data. current . total_read_count . fetch_add ( 1 , Relaxed ) ;
349
+ data. total_read_count . fetch_add ( 1 , Relaxed ) ;
276
350
}
277
351
278
352
// As long as we only have a low number of reads we can avoid doing a hash
@@ -293,7 +367,7 @@ impl<K: DepKind> DepGraph<K> {
293
367
#[ cfg( debug_assertions) ]
294
368
{
295
369
if let Some ( target) = task_deps. node {
296
- if let Some ( ref forbidden_edge) = data. current . forbidden_edge {
370
+ if let Some ( ref forbidden_edge) = data. forbidden_edge {
297
371
let src = self . dep_node_of ( dep_node_index) ;
298
372
if forbidden_edge. test ( & src, & target) {
299
373
panic ! ( "forbidden edge {:?} -> {:?} created" , src, target)
@@ -302,7 +376,7 @@ impl<K: DepKind> DepGraph<K> {
302
376
}
303
377
}
304
378
} else if cfg ! ( debug_assertions) {
305
- data. current . total_duplicate_read_count . fetch_add ( 1 , Relaxed ) ;
379
+ data. total_duplicate_read_count . fetch_add ( 1 , Relaxed ) ;
306
380
}
307
381
}
308
382
} )
@@ -687,7 +761,6 @@ impl<K: DepKind> DepGraph<K> {
687
761
688
762
let data = self . data . as_ref ( ) . unwrap ( ) ;
689
763
let prev = & data. previous . read ( ) ;
690
- let current = & data. current ;
691
764
692
765
let mut stats: FxHashMap < _ , Stat < K > > = FxHashMap :: with_hasher ( Default :: default ( ) ) ;
693
766
@@ -721,8 +794,8 @@ impl<K: DepKind> DepGraph<K> {
721
794
eprintln ! ( "[incremental] Total Edge Count: {}" , total_edge_count) ;
722
795
723
796
if cfg ! ( debug_assertions) {
724
- let total_edge_reads = current . total_read_count . load ( Relaxed ) ;
725
- let total_duplicate_edge_reads = current . total_duplicate_read_count . load ( Relaxed ) ;
797
+ let total_edge_reads = data . total_read_count . load ( Relaxed ) ;
798
+ let total_duplicate_edge_reads = data . total_duplicate_read_count . load ( Relaxed ) ;
726
799
727
800
eprintln ! ( "[incremental] Total Edge Reads: {}" , total_edge_reads) ;
728
801
eprintln ! ( "[incremental] Total Duplicate Edge Reads: {}" , total_duplicate_edge_reads) ;
@@ -819,125 +892,6 @@ rustc_index::newtype_index! {
819
892
struct EdgeIndex { .. }
820
893
}
821
894
822
- /// `CurrentDepGraph` stores the dependency graph for the current session. It
823
- /// will be populated as we run queries or tasks. We never remove nodes from the
824
- /// graph: they are only added.
825
- ///
826
- /// The nodes in it are identified by a `DepNodeIndex`. Internally, this maps to
827
- /// a `HybridIndex`, which identifies which collection in the `data` field
828
- /// contains a node's data. Which collection is used for a node depends on
829
- /// whether the node was present in the `SerializedDepGraph`, and if so, the color
830
- /// of the node. Each type of node can share more or less data with the previous
831
- /// graph. When possible, we can store just the index of the node in the
832
- /// previous graph, rather than duplicating its data in our own collections.
833
- /// This is important, because these graph structures are some of the largest in
834
- /// the compiler.
835
- ///
836
- /// For the same reason, we also avoid storing `DepNode`s more than once as map
837
- /// keys. The `new_node_to_index` map only contains nodes not in the previous
838
- /// graph, and we map nodes in the previous graph to indices via a two-step
839
- /// mapping. `SerializedDepGraph` maps from `DepNode` to `SerializedDepNodeIndex`,
840
- /// and the `prev_index_to_index` vector (which is more compact and faster than
841
- /// using a map) maps from `SerializedDepNodeIndex` to `DepNodeIndex`.
842
- ///
843
- /// This struct uses three locks internally. The `data`, `new_node_to_index`,
844
- /// and `prev_index_to_index` fields are locked separately. Operations that take
845
- /// a `DepNodeIndex` typically just access the `data` field.
846
- ///
847
- /// We only need to manipulate at most two locks simultaneously:
848
- /// `new_node_to_index` and `data`, or `prev_index_to_index` and `data`. When
849
- /// manipulating both, we acquire `new_node_to_index` or `prev_index_to_index`
850
- /// first, and `data` second.
851
- pub ( super ) struct CurrentDepGraph {
852
- /// Used to trap when a specific edge is added to the graph.
853
- /// This is used for debug purposes and is only active with `debug_assertions`.
854
- #[ allow( dead_code) ]
855
- forbidden_edge : Option < EdgeFilter > ,
856
-
857
- /// Anonymous `DepNode`s are nodes whose IDs we compute from the list of
858
- /// their edges. This has the beneficial side-effect that multiple anonymous
859
- /// nodes can be coalesced into one without changing the semantics of the
860
- /// dependency graph. However, the merging of nodes can lead to a subtle
861
- /// problem during red-green marking: The color of an anonymous node from
862
- /// the current session might "shadow" the color of the node with the same
863
- /// ID from the previous session. In order to side-step this problem, we make
864
- /// sure that anonymous `NodeId`s allocated in different sessions don't overlap.
865
- /// This is implemented by mixing a session-key into the ID fingerprint of
866
- /// each anon node. The session-key is just a random number generated when
867
- /// the `DepGraph` is created.
868
- anon_id_seed : Fingerprint ,
869
-
870
- /// These are simple counters that are for profiling and
871
- /// debugging and only active with `debug_assertions`.
872
- total_read_count : AtomicU64 ,
873
- total_duplicate_read_count : AtomicU64 ,
874
- }
875
-
876
- impl CurrentDepGraph {
877
- fn new ( _prev_graph_node_count : usize ) -> CurrentDepGraph {
878
- use std:: time:: { SystemTime , UNIX_EPOCH } ;
879
-
880
- let duration = SystemTime :: now ( ) . duration_since ( UNIX_EPOCH ) . unwrap ( ) ;
881
- let nanos = duration. as_secs ( ) * 1_000_000_000 + duration. subsec_nanos ( ) as u64 ;
882
- let mut stable_hasher = StableHasher :: new ( ) ;
883
- nanos. hash ( & mut stable_hasher) ;
884
-
885
- let forbidden_edge = if cfg ! ( debug_assertions) {
886
- match env:: var ( "RUST_FORBID_DEP_GRAPH_EDGE" ) {
887
- Ok ( s) => match EdgeFilter :: new ( & s) {
888
- Ok ( f) => Some ( f) ,
889
- Err ( err) => panic ! ( "RUST_FORBID_DEP_GRAPH_EDGE invalid: {}" , err) ,
890
- } ,
891
- Err ( _) => None ,
892
- }
893
- } else {
894
- None
895
- } ;
896
-
897
- /*
898
- // Pre-allocate the dep node structures. We over-allocate a little so
899
- // that we hopefully don't have to re-allocate during this compilation
900
- // session. The over-allocation for new nodes is 2% plus a small
901
- // constant to account for the fact that in very small crates 2% might
902
- // not be enough. The allocation for red and green node data doesn't
903
- // include a constant, as we don't want to allocate anything for these
904
- // structures during full incremental builds, where they aren't used.
905
- //
906
- // These estimates are based on the distribution of node and edge counts
907
- // seen in rustc-perf benchmarks, adjusted somewhat to account for the
908
- // fact that these benchmarks aren't perfectly representative.
909
- //
910
- // FIXME Use a collection type that doesn't copy node and edge data and
911
- // grow multiplicatively on reallocation. Without such a collection or
912
- // solution having the same effect, there is a performance hazard here
913
- // in both time and space, as growing these collections means copying a
914
- // large amount of data and doubling already large buffer capacities. A
915
- // solution for this will also mean that it's less important to get
916
- // these estimates right.
917
- let new_node_count_estimate = (prev_graph_node_count * 2) / 100 + 200;
918
- let red_node_count_estimate = (prev_graph_node_count * 3) / 100;
919
- let light_green_node_count_estimate = (prev_graph_node_count * 25) / 100;
920
- let total_node_count_estimate = prev_graph_node_count + new_node_count_estimate;
921
-
922
- let average_edges_per_node_estimate = 6;
923
- let unshared_edge_count_estimate = average_edges_per_node_estimate
924
- * (new_node_count_estimate + red_node_count_estimate + light_green_node_count_estimate);
925
- */
926
-
927
- // We store a large collection of these in `prev_index_to_index` during
928
- // non-full incremental builds, and want to ensure that the element size
929
- // doesn't inadvertently increase.
930
- static_assert_size ! ( Option <DepNodeIndex >, 4 ) ;
931
-
932
- CurrentDepGraph {
933
- anon_id_seed : stable_hasher. finish ( ) ,
934
- forbidden_edge,
935
- total_read_count : AtomicU64 :: new ( 0 ) ,
936
- total_duplicate_read_count : AtomicU64 :: new ( 0 ) ,
937
- }
938
- }
939
- }
940
-
941
895
/// The capacity of the `reads` field `SmallVec`
942
896
const TASK_DEPS_READS_CAP : usize = 8 ;
943
897
type EdgesVec = SmallVec < [ DepNodeIndex ; TASK_DEPS_READS_CAP ] > ;
0 commit comments