@@ -15,6 +15,7 @@ use std::env;
15
15
use std:: hash:: Hash ;
16
16
use std:: marker:: PhantomData ;
17
17
use std:: mem;
18
+ use std:: ops:: Range ;
18
19
use std:: sync:: atomic:: Ordering :: Relaxed ;
19
20
20
21
use super :: debug:: EdgeFilter ;
@@ -143,42 +144,48 @@ impl<K: DepKind> DepGraph<K> {
143
144
let node_count = data. hybrid_indices . len ( ) ;
144
145
145
146
let mut nodes = Vec :: with_capacity ( node_count) ;
146
- let mut edges = Vec :: with_capacity ( edge_count) ;
147
-
148
- for ( index, & hybrid_index) in data. hybrid_indices . iter_enumerated ( ) {
149
- let src = index. index ( ) ;
147
+ let mut edge_list_indices = Vec :: with_capacity ( node_count) ;
148
+ let mut edge_list_data = Vec :: with_capacity ( edge_count) ;
149
+ edge_list_data. extend ( data. unshared_edges . iter ( ) . map ( |i| i. index ( ) ) ) ;
150
150
151
+ for & hybrid_index in data. hybrid_indices . iter ( ) {
151
152
match hybrid_index. into ( ) {
152
153
HybridIndex :: New ( new_index) => {
153
- let new = & data. new ;
154
- nodes . push ( new. nodes [ new_index] ) ;
155
- edges . extend ( new . edges [ new_index ] . iter ( ) . map ( |dst| ( src , dst . index ( ) ) ) ) ;
154
+ nodes . push ( data. new . nodes [ new_index ] ) ;
155
+ let edges = & data . new . edges [ new_index] ;
156
+ edge_list_indices . push ( ( edges. start . index ( ) , edges . end . index ( ) ) ) ;
156
157
}
157
158
HybridIndex :: Red ( red_index) => {
158
- let red = & data. red ;
159
- nodes . push ( previous . index_to_node ( red. node_indices [ red_index] ) ) ;
160
- edges . extend ( red . edges [ red_index ] . iter ( ) . map ( |dst| ( src , dst . index ( ) ) ) ) ;
159
+ nodes . push ( previous . index_to_node ( data. red . node_indices [ red_index ] ) ) ;
160
+ let edges = & data . red . edges [ red_index] ;
161
+ edge_list_indices . push ( ( edges. start . index ( ) , edges . end . index ( ) ) ) ;
161
162
}
162
163
HybridIndex :: LightGreen ( lg_index) => {
163
- let lg = & data. light_green ;
164
- nodes . push ( previous . index_to_node ( lg . node_indices [ lg_index] ) ) ;
165
- edges . extend ( lg . edges [ lg_index ] . iter ( ) . map ( |dst| ( src , dst . index ( ) ) ) ) ;
164
+ nodes . push ( previous . index_to_node ( data. light_green . node_indices [ lg_index ] ) ) ;
165
+ let edges = & data . light_green . edges [ lg_index] ;
166
+ edge_list_indices . push ( ( edges. start . index ( ) , edges . end . index ( ) ) ) ;
166
167
}
167
168
HybridIndex :: DarkGreen ( prev_index) => {
168
169
nodes. push ( previous. index_to_node ( prev_index) ) ;
170
+
169
171
let edges_iter = previous
170
172
. edge_targets_from ( prev_index)
171
173
. iter ( )
172
- . map ( |& dst| ( src, prev_index_to_index[ dst] . unwrap ( ) . index ( ) ) ) ;
173
- edges. extend ( edges_iter) ;
174
+ . map ( |& dst| prev_index_to_index[ dst] . unwrap ( ) . index ( ) ) ;
175
+
176
+ let start = edge_list_data. len ( ) ;
177
+ edge_list_data. extend ( edges_iter) ;
178
+ let end = edge_list_data. len ( ) ;
179
+ edge_list_indices. push ( ( start, end) ) ;
174
180
}
175
181
}
176
182
}
177
183
178
184
debug_assert_eq ! ( nodes. len( ) , node_count) ;
179
- debug_assert_eq ! ( edges. len( ) , edge_count) ;
185
+ debug_assert_eq ! ( edge_list_indices. len( ) , node_count) ;
186
+ debug_assert_eq ! ( edge_list_data. len( ) , edge_count) ;
180
187
181
- DepGraphQuery :: new ( & nodes[ ..] , & edges [ ..] )
188
+ DepGraphQuery :: new ( & nodes[ ..] , & edge_list_indices [ .. ] , & edge_list_data [ ..] )
182
189
}
183
190
184
191
pub fn assert_ignored ( & self ) {
@@ -561,11 +568,7 @@ impl<K: DepKind> DepGraph<K> {
561
568
let previous = & data. previous ;
562
569
let data = data. current . data . lock ( ) ;
563
570
564
- // Linearly scanning each collection is a bit faster than scanning
565
- // `hybrid_indices` and bouncing around the different collections.
566
- let mut edge_count = data. new . edges . iter ( ) . map ( |e| e. len ( ) ) . sum :: < usize > ( )
567
- + data. red . edges . iter ( ) . map ( |e| e. len ( ) ) . sum :: < usize > ( )
568
- + data. light_green . edges . iter ( ) . map ( |e| e. len ( ) ) . sum :: < usize > ( ) ;
571
+ let mut edge_count = data. unshared_edges . len ( ) ;
569
572
570
573
for & hybrid_index in data. hybrid_indices . iter ( ) {
571
574
if let HybridIndex :: DarkGreen ( prev_index) = hybrid_index. into ( ) {
@@ -591,46 +594,44 @@ impl<K: DepKind> DepGraph<K> {
591
594
let mut fingerprints = IndexVec :: with_capacity ( node_count) ;
592
595
let mut edge_list_indices = IndexVec :: with_capacity ( node_count) ;
593
596
let mut edge_list_data = Vec :: with_capacity ( edge_count) ;
594
-
595
- fn add_edges < ' a , I : Iterator < Item = & ' a DepNodeIndex > > (
596
- edge_list_indices : & mut IndexVec < SerializedDepNodeIndex , ( u32 , u32 ) > ,
597
- edge_list_data : & mut Vec < SerializedDepNodeIndex > ,
598
- iter : I ,
599
- ) {
600
- let start = edge_list_data. len ( ) as u32 ;
601
- edge_list_data. extend ( iter. map ( |i| SDNI :: new ( i. index ( ) ) ) ) ;
602
- let end = edge_list_data. len ( ) as u32 ;
603
- edge_list_indices. push ( ( start, end) ) ;
604
- } ;
597
+ edge_list_data. extend ( data. unshared_edges . iter ( ) . map ( |i| SDNI :: new ( i. index ( ) ) ) ) ;
605
598
606
599
for & hybrid_index in data. hybrid_indices . iter ( ) {
607
600
match hybrid_index. into ( ) {
608
601
HybridIndex :: New ( i) => {
609
602
let new = & data. new ;
610
603
nodes. push ( new. nodes [ i] ) ;
611
604
fingerprints. push ( new. fingerprints [ i] ) ;
612
- add_edges ( & mut edge_list_indices, & mut edge_list_data, new. edges [ i] . iter ( ) ) ;
605
+ let edges = & new. edges [ i] ;
606
+ edge_list_indices. push ( ( edges. start . as_u32 ( ) , edges. end . as_u32 ( ) ) ) ;
613
607
}
614
608
HybridIndex :: Red ( i) => {
615
609
let red = & data. red ;
616
610
nodes. push ( previous. index_to_node ( red. node_indices [ i] ) ) ;
617
611
fingerprints. push ( red. fingerprints [ i] ) ;
618
- add_edges ( & mut edge_list_indices, & mut edge_list_data, red. edges [ i] . iter ( ) ) ;
612
+ let edges = & red. edges [ i] ;
613
+ edge_list_indices. push ( ( edges. start . as_u32 ( ) , edges. end . as_u32 ( ) ) ) ;
619
614
}
620
615
HybridIndex :: LightGreen ( i) => {
621
616
let lg = & data. light_green ;
622
617
nodes. push ( previous. index_to_node ( lg. node_indices [ i] ) ) ;
623
618
fingerprints. push ( previous. fingerprint_by_index ( lg. node_indices [ i] ) ) ;
624
- add_edges ( & mut edge_list_indices, & mut edge_list_data, lg. edges [ i] . iter ( ) ) ;
619
+ let edges = & lg. edges [ i] ;
620
+ edge_list_indices. push ( ( edges. start . as_u32 ( ) , edges. end . as_u32 ( ) ) ) ;
625
621
}
626
622
HybridIndex :: DarkGreen ( prev_index) => {
627
623
nodes. push ( previous. index_to_node ( prev_index) ) ;
628
624
fingerprints. push ( previous. fingerprint_by_index ( prev_index) ) ;
625
+
629
626
let edges_iter = previous
630
627
. edge_targets_from ( prev_index)
631
628
. iter ( )
632
629
. map ( |& dst| prev_index_to_index[ dst] . as_ref ( ) . unwrap ( ) ) ;
633
- add_edges ( & mut edge_list_indices, & mut edge_list_data, edges_iter) ;
630
+
631
+ let start = edge_list_data. len ( ) as u32 ;
632
+ edge_list_data. extend ( edges_iter. map ( |i| SDNI :: new ( i. index ( ) ) ) ) ;
633
+ let end = edge_list_data. len ( ) as u32 ;
634
+ edge_list_indices. push ( ( start, end) ) ;
634
635
}
635
636
}
636
637
}
@@ -1125,6 +1126,11 @@ impl From<CompressedHybridIndex> for HybridIndex {
1125
1126
}
1126
1127
}
1127
1128
1129
+ // Index type for `DepNodeData`'s edges.
1130
+ rustc_index:: newtype_index! {
1131
+ struct EdgeIndex { .. }
1132
+ }
1133
+
1128
1134
/// Data for nodes in the current graph, divided into different collections
1129
1135
/// based on their presence in the previous graph, and if present, their color.
1130
1136
/// We divide nodes this way because different types of nodes are able to share
@@ -1171,6 +1177,16 @@ struct DepNodeData<K> {
1171
1177
/// Data for nodes in previous graph that have been marked light green.
1172
1178
light_green : LightGreenDepNodeData ,
1173
1179
1180
+ // Edges for all nodes other than dark-green ones. Edges for each node
1181
+ // occupy a contiguous region of this collection, which a node can reference
1182
+ // using two indices. Storing edges this way rather than using an `EdgesVec`
1183
+ // for each node reduces memory consumption by a not insignificant amount
1184
+ // when compiling large crates. The downside is that we have to copy into
1185
+ // this collection the edges from the `EdgesVec`s that are built up during
1186
+ // query execution. But this is mostly balanced out by the more efficient
1187
+ // implementation of `DepGraph::serialize` enabled by this representation.
1188
+ unshared_edges : IndexVec < EdgeIndex , DepNodeIndex > ,
1189
+
1174
1190
/// Mapping from `DepNodeIndex` to an index into a collection above.
1175
1191
/// Indicates which of the above collections contains a node's data.
1176
1192
///
@@ -1186,7 +1202,7 @@ struct DepNodeData<K> {
1186
1202
/// the previous graph, so we must store all of such a node's data here.
1187
1203
struct NewDepNodeData < K > {
1188
1204
nodes : IndexVec < NewDepNodeIndex , DepNode < K > > ,
1189
- edges : IndexVec < NewDepNodeIndex , EdgesVec > ,
1205
+ edges : IndexVec < NewDepNodeIndex , Range < EdgeIndex > > ,
1190
1206
fingerprints : IndexVec < NewDepNodeIndex , Fingerprint > ,
1191
1207
}
1192
1208
@@ -1195,7 +1211,7 @@ struct NewDepNodeData<K> {
1195
1211
/// fingerprint is known to be different, so we store the latter two directly.
1196
1212
struct RedDepNodeData {
1197
1213
node_indices : IndexVec < RedDepNodeIndex , SerializedDepNodeIndex > ,
1198
- edges : IndexVec < RedDepNodeIndex , EdgesVec > ,
1214
+ edges : IndexVec < RedDepNodeIndex , Range < EdgeIndex > > ,
1199
1215
fingerprints : IndexVec < RedDepNodeIndex , Fingerprint > ,
1200
1216
}
1201
1217
@@ -1205,7 +1221,7 @@ struct RedDepNodeData {
1205
1221
/// graph, but the edges may be different, so we store them directly.
1206
1222
struct LightGreenDepNodeData {
1207
1223
node_indices : IndexVec < LightGreenDepNodeIndex , SerializedDepNodeIndex > ,
1208
- edges : IndexVec < LightGreenDepNodeIndex , EdgesVec > ,
1224
+ edges : IndexVec < LightGreenDepNodeIndex , Range < EdgeIndex > > ,
1209
1225
}
1210
1226
1211
1227
/// `CurrentDepGraph` stores the dependency graph for the current session. It
@@ -1294,11 +1310,27 @@ impl<K: DepKind> CurrentDepGraph<K> {
1294
1310
// not be enough. The allocation for red and green node data doesn't
1295
1311
// include a constant, as we don't want to allocate anything for these
1296
1312
// structures during full incremental builds, where they aren't used.
1313
+ //
1314
+ // These estimates are based on the distribution of node and edge counts
1315
+ // seen in rustc-perf benchmarks, adjusted somewhat to account for the
1316
+ // fact that these benchmarks aren't perfectly representative.
1317
+ //
1318
+ // FIXME Use a collection type that doesn't copy node and edge data and
1319
+ // grow multiplicatively on reallocation. Without such a collection or
1320
+ // solution having the same effect, there is a performance hazard here
1321
+ // in both time and space, as growing these collections means copying a
1322
+ // large amount of data and doubling already large buffer capacities. A
1323
+ // solution for this will also mean that it's less important to get
1324
+ // these estimates right.
1297
1325
let new_node_count_estimate = ( prev_graph_node_count * 2 ) / 100 + 200 ;
1298
1326
let red_node_count_estimate = ( prev_graph_node_count * 3 ) / 100 ;
1299
1327
let light_green_node_count_estimate = ( prev_graph_node_count * 25 ) / 100 ;
1300
1328
let total_node_count_estimate = prev_graph_node_count + new_node_count_estimate;
1301
1329
1330
+ let average_edges_per_node_estimate = 6 ;
1331
+ let unshared_edge_count_estimate = average_edges_per_node_estimate
1332
+ * ( new_node_count_estimate + red_node_count_estimate + light_green_node_count_estimate) ;
1333
+
1302
1334
// We store a large collection of these in `prev_index_to_index` during
1303
1335
// non-full incremental builds, and want to ensure that the element size
1304
1336
// doesn't inadvertently increase.
@@ -1320,6 +1352,7 @@ impl<K: DepKind> CurrentDepGraph<K> {
1320
1352
node_indices : IndexVec :: with_capacity ( light_green_node_count_estimate) ,
1321
1353
edges : IndexVec :: with_capacity ( light_green_node_count_estimate) ,
1322
1354
} ,
1355
+ unshared_edges : IndexVec :: with_capacity ( unshared_edge_count_estimate) ,
1323
1356
hybrid_indices : IndexVec :: with_capacity ( total_node_count_estimate) ,
1324
1357
} ) ,
1325
1358
new_node_to_index : Sharded :: new ( || {
@@ -1352,9 +1385,9 @@ impl<K: DepKind> CurrentDepGraph<K> {
1352
1385
match self . new_node_to_index . get_shard_by_value ( & dep_node) . lock ( ) . entry ( dep_node) {
1353
1386
Entry :: Occupied ( entry) => * entry. get ( ) ,
1354
1387
Entry :: Vacant ( entry) => {
1355
- let mut data = self . data . lock ( ) ;
1388
+ let data = & mut * self . data . lock ( ) ;
1356
1389
let new_index = data. new . nodes . push ( dep_node) ;
1357
- data. new . edges . push ( edges) ;
1390
+ add_edges ( & mut data. unshared_edges , & mut data . new . edges , edges) ;
1358
1391
data. new . fingerprints . push ( fingerprint) ;
1359
1392
let dep_node_index = data. hybrid_indices . push ( new_index. into ( ) ) ;
1360
1393
entry. insert ( dep_node_index) ;
@@ -1377,9 +1410,9 @@ impl<K: DepKind> CurrentDepGraph<K> {
1377
1410
match prev_index_to_index[ prev_index] {
1378
1411
Some ( dep_node_index) => dep_node_index,
1379
1412
None => {
1380
- let mut data = self . data . lock ( ) ;
1413
+ let data = & mut * self . data . lock ( ) ;
1381
1414
let red_index = data. red . node_indices . push ( prev_index) ;
1382
- data. red . edges . push ( edges) ;
1415
+ add_edges ( & mut data. unshared_edges , & mut data . red . edges , edges) ;
1383
1416
data. red . fingerprints . push ( fingerprint) ;
1384
1417
let dep_node_index = data. hybrid_indices . push ( red_index. into ( ) ) ;
1385
1418
prev_index_to_index[ prev_index] = Some ( dep_node_index) ;
@@ -1401,9 +1434,9 @@ impl<K: DepKind> CurrentDepGraph<K> {
1401
1434
match prev_index_to_index[ prev_index] {
1402
1435
Some ( dep_node_index) => dep_node_index,
1403
1436
None => {
1404
- let mut data = self . data . lock ( ) ;
1437
+ let data = & mut * self . data . lock ( ) ;
1405
1438
let light_green_index = data. light_green . node_indices . push ( prev_index) ;
1406
- data. light_green . edges . push ( edges) ;
1439
+ add_edges ( & mut data. unshared_edges , & mut data . light_green . edges , edges) ;
1407
1440
let dep_node_index = data. hybrid_indices . push ( light_green_index. into ( ) ) ;
1408
1441
prev_index_to_index[ prev_index] = Some ( dep_node_index) ;
1409
1442
dep_node_index
@@ -1445,6 +1478,18 @@ impl<K: DepKind> CurrentDepGraph<K> {
1445
1478
}
1446
1479
}
1447
1480
1481
+ #[ inline]
1482
+ fn add_edges < I : Idx > (
1483
+ edges : & mut IndexVec < EdgeIndex , DepNodeIndex > ,
1484
+ edge_indices : & mut IndexVec < I , Range < EdgeIndex > > ,
1485
+ new_edges : EdgesVec ,
1486
+ ) {
1487
+ let start = edges. next_index ( ) ;
1488
+ edges. extend ( new_edges) ;
1489
+ let end = edges. next_index ( ) ;
1490
+ edge_indices. push ( start..end) ;
1491
+ }
1492
+
1448
1493
/// The capacity of the `reads` field `SmallVec`
1449
1494
const TASK_DEPS_READS_CAP : usize = 8 ;
1450
1495
type EdgesVec = SmallVec < [ DepNodeIndex ; TASK_DEPS_READS_CAP ] > ;
0 commit comments