35
35
//! If the number of edges in this node does not fit in the bits available in the header, we
36
36
//! store it directly after the header with leb128.
37
37
38
- use std:: iter;
39
38
use std:: marker:: PhantomData ;
40
- use std:: sync:: Arc ;
39
+ use std:: sync:: { Arc , OnceLock } ;
40
+ use std:: { iter, thread} ;
41
41
42
42
use rustc_data_structures:: fingerprint:: { Fingerprint , PackedFingerprint } ;
43
43
use rustc_data_structures:: fx:: FxHashMap ;
44
- use rustc_data_structures:: outline;
45
44
use rustc_data_structures:: profiling:: SelfProfilerRef ;
46
45
use rustc_data_structures:: sync:: Lock ;
47
46
use rustc_data_structures:: unhash:: UnhashMap ;
47
+ use rustc_data_structures:: { jobserver, outline} ;
48
48
use rustc_index:: { Idx , IndexVec } ;
49
49
use rustc_serialize:: opaque:: { FileEncodeResult , FileEncoder , IntEncodedWithFixedSize , MemDecoder } ;
50
50
use rustc_serialize:: { Decodable , Decoder , Encodable , Encoder } ;
51
+ use rustc_session:: Session ;
51
52
use tracing:: { debug, instrument} ;
52
53
53
54
use super :: query:: DepGraphQuery ;
@@ -74,23 +75,47 @@ const DEP_NODE_PAD: usize = DEP_NODE_SIZE - 1;
74
75
const DEP_NODE_WIDTH_BITS : usize = DEP_NODE_SIZE / 2 ;
75
76
76
77
/// Data for use when recompiling the **current crate**.
77
- #[ derive( Debug , Default ) ]
78
78
pub struct SerializedDepGraph {
79
79
/// The set of all DepNodes in the graph
80
80
nodes : IndexVec < SerializedDepNodeIndex , DepNode > ,
81
+
81
82
/// The set of all Fingerprints in the graph. Each Fingerprint corresponds to
82
83
/// the DepNode at the same index in the nodes vector.
83
84
fingerprints : IndexVec < SerializedDepNodeIndex , Fingerprint > ,
85
+
84
86
/// For each DepNode, stores the list of edges originating from that
85
87
/// DepNode. Encoded as a [start, end) pair indexing into edge_list_data,
86
88
/// which holds the actual DepNodeIndices of the target nodes.
87
89
edge_list_indices : IndexVec < SerializedDepNodeIndex , EdgeHeader > ,
90
+
88
91
/// A flattened list of all edge targets in the graph, stored in the same
89
92
/// varint encoding that we use on disk. Edge sources are implicit in edge_list_indices.
90
93
edge_list_data : Vec < u8 > ,
94
+
91
95
/// Stores a map from fingerprints to nodes per dep node kind.
92
- /// This is the reciprocal of `nodes`.
93
- index : Vec < UnhashMap < PackedFingerprint , SerializedDepNodeIndex > > ,
96
+ /// This is the reciprocal of `nodes`. This is computed on demand for each dep kind.
97
+ /// The entire index is also computed in a background thread.
98
+ index : Vec < OnceLock < UnhashMap < PackedFingerprint , SerializedDepNodeIndex > > > ,
99
+
100
+ /// Stores the number of node for each dep node kind.
101
+ index_sizes : Vec < usize > ,
102
+
103
+ /// A profiler reference for used in the index prefetching thread.
104
+ prof : SelfProfilerRef ,
105
+ }
106
+
107
+ impl Default for SerializedDepGraph {
108
+ fn default ( ) -> Self {
109
+ SerializedDepGraph {
110
+ nodes : Default :: default ( ) ,
111
+ fingerprints : Default :: default ( ) ,
112
+ edge_list_indices : Default :: default ( ) ,
113
+ edge_list_data : Default :: default ( ) ,
114
+ index : Default :: default ( ) ,
115
+ index_sizes : Default :: default ( ) ,
116
+ prof : SelfProfilerRef :: new ( None , None ) ,
117
+ }
118
+ }
94
119
}
95
120
96
121
impl SerializedDepGraph {
@@ -131,9 +156,35 @@ impl SerializedDepGraph {
131
156
self . nodes [ dep_node_index]
132
157
}
133
158
159
+ /// This computes and sets up the index for just the specified `DepKind`.
160
+ fn setup_index ( & self , dep_kind : DepKind ) {
161
+ let _timer = self . prof . generic_activity ( "incr_comp_dep_graph_setup_index" ) ;
162
+
163
+ let mut index = UnhashMap :: with_capacity_and_hasher (
164
+ self . index_sizes [ dep_kind. as_usize ( ) ] ,
165
+ Default :: default ( ) ,
166
+ ) ;
167
+
168
+ for ( idx, node) in self . nodes . iter_enumerated ( ) {
169
+ if node. kind == dep_kind {
170
+ index. insert ( node. hash , idx) ;
171
+ }
172
+ }
173
+
174
+ // This may race with the prefetching thread, but that will set the same value.
175
+ self . index [ dep_kind. as_usize ( ) ] . set ( index) . ok ( ) ;
176
+ }
177
+
134
178
#[ inline]
135
179
pub fn node_to_index_opt ( & self , dep_node : & DepNode ) -> Option < SerializedDepNodeIndex > {
136
- self . index . get ( dep_node. kind . as_usize ( ) ) ?. get ( & dep_node. hash ) . cloned ( )
180
+ let index = self . index . get ( dep_node. kind . as_usize ( ) ) ?;
181
+ let index = index. get ( ) . unwrap_or_else ( || {
182
+ outline ( || {
183
+ self . setup_index ( dep_node. kind ) ;
184
+ self . index [ dep_node. kind . as_usize ( ) ] . get ( ) . unwrap ( )
185
+ } )
186
+ } ) ;
187
+ index. get ( & dep_node. hash ) . cloned ( )
137
188
}
138
189
139
190
#[ inline]
@@ -145,6 +196,48 @@ impl SerializedDepGraph {
145
196
pub fn node_count ( & self ) -> usize {
146
197
self . nodes . len ( )
147
198
}
199
+
200
+ fn prefetch ( & self ) {
201
+ let _timer = self . prof . generic_activity ( "incr_comp_prefetch_dep_graph_index" ) ;
202
+
203
+ let mut index: Vec < _ > = self
204
+ . index_sizes
205
+ . iter ( )
206
+ . map ( |& n| UnhashMap :: with_capacity_and_hasher ( n, Default :: default ( ) ) )
207
+ . collect ( ) ;
208
+
209
+ // Use a single loop to build indices for all kinds, unlike `setup_index` which builds
210
+ // a single index for each loop over the nodes.
211
+ for ( idx, node) in self . nodes . iter_enumerated ( ) {
212
+ index[ node. kind . as_usize ( ) ] . insert ( node. hash , idx) ;
213
+ }
214
+
215
+ for ( i, index) in index. into_iter ( ) . enumerate ( ) {
216
+ // This may race with `setup_index`, but that will set the same value.
217
+ self . index [ i] . set ( index) . ok ( ) ;
218
+ }
219
+ }
220
+
221
+ /// This spawns a thread that prefetches the index.
222
+ fn spawn_prefetch_thread ( self : & Arc < Self > ) {
223
+ if !self . index . is_empty ( ) {
224
+ let client = jobserver:: client ( ) ;
225
+ // This should ideally use `try_acquire` to avoid races on the tokens,
226
+ // but the jobserver crate doesn't support that operation.
227
+ if let Ok ( tokens) = client. available ( )
228
+ && tokens > 0
229
+ {
230
+ let this = self . clone ( ) ;
231
+ thread:: spawn ( move || {
232
+ let _token = client. acquire ( ) ;
233
+ this. prefetch ( ) ;
234
+ } ) ;
235
+ } else {
236
+ // Prefetch the index on the current thread if we don't have a token available.
237
+ self . prefetch ( ) ;
238
+ }
239
+ }
240
+ }
148
241
}
149
242
150
243
/// A packed representation of an edge's start index and byte width.
@@ -179,8 +272,8 @@ fn mask(bits: usize) -> usize {
179
272
}
180
273
181
274
impl SerializedDepGraph {
182
- #[ instrument( level = "debug" , skip( d) ) ]
183
- pub fn decode < D : Deps > ( d : & mut MemDecoder < ' _ > ) -> Arc < SerializedDepGraph > {
275
+ #[ instrument( level = "debug" , skip( d, sess ) ) ]
276
+ pub fn decode < D : Deps > ( d : & mut MemDecoder < ' _ > , sess : & Session ) -> Arc < SerializedDepGraph > {
184
277
// The last 16 bytes are the node count and edge count.
185
278
debug ! ( "position: {:?}" , d. position( ) ) ;
186
279
let ( node_count, edge_count) =
@@ -246,22 +339,21 @@ impl SerializedDepGraph {
246
339
// end of the array. This padding ensure it doesn't.
247
340
edge_list_data. extend ( & [ 0u8 ; DEP_NODE_PAD ] ) ;
248
341
249
- // Read the number of each dep kind and use it to create an hash map with a suitable size.
250
- let mut index: Vec < _ > = ( 0 ..( D :: DEP_KIND_MAX + 1 ) )
251
- . map ( |_| UnhashMap :: with_capacity_and_hasher ( d. read_u32 ( ) as usize , Default :: default ( ) ) )
252
- . collect ( ) ;
342
+ // Read the number of nodes for each dep kind.
343
+ let index_sizes: Vec < _ > =
344
+ ( 0 ..( D :: DEP_KIND_MAX + 1 ) ) . map ( |_| d. read_u32 ( ) as usize ) . collect ( ) ;
253
345
254
- for ( idx, node) in nodes. iter_enumerated ( ) {
255
- index[ node. kind . as_usize ( ) ] . insert ( node. hash , idx) ;
256
- }
257
-
258
- Arc :: new ( SerializedDepGraph {
346
+ let result = Arc :: new ( SerializedDepGraph {
259
347
nodes,
260
348
fingerprints,
261
349
edge_list_indices,
262
350
edge_list_data,
263
- index,
264
- } )
351
+ index : ( 0 ..index_sizes. len ( ) ) . map ( |_| OnceLock :: new ( ) ) . collect ( ) ,
352
+ index_sizes,
353
+ prof : sess. prof . clone ( ) ,
354
+ } ) ;
355
+ result. spawn_prefetch_thread ( ) ;
356
+ result
265
357
}
266
358
}
267
359
0 commit comments