Skip to content

Commit e3e432d

Browse files
committed
Auto merge of #139756 - Zoxc:out-of-order-dep-graph, r=oli-obk
Allow out of order dep graph node encoding This allows out of order dep graph node encoding by also encoding the index instead of using the file node order as the index. `MemEncoder` is also brought back to life and used for encoding. Both of these are done to enable thread-local encoding of dep graph nodes. This is based on #139636.
2 parents 8f43b85 + c8e7c62 commit e3e432d

File tree

3 files changed

+215
-43
lines changed

3 files changed

+215
-43
lines changed

compiler/rustc_query_system/src/dep_graph/serialized.rs

+85-43
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ use rustc_data_structures::profiling::SelfProfilerRef;
4646
use rustc_data_structures::sync::Lock;
4747
use rustc_data_structures::unhash::UnhashMap;
4848
use rustc_index::{Idx, IndexVec};
49+
use rustc_serialize::opaque::mem_encoder::MemEncoder;
4950
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder};
5051
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
5152
use tracing::{debug, instrument};
@@ -105,22 +106,12 @@ impl SerializedDepGraph {
105106
) -> impl Iterator<Item = SerializedDepNodeIndex> + Clone {
106107
let header = self.edge_list_indices[source];
107108
let mut raw = &self.edge_list_data[header.start()..];
108-
// Figure out where the edge list for `source` ends by getting the start index of the next
109-
// edge list, or the end of the array if this is the last edge.
110-
let end = self
111-
.edge_list_indices
112-
.get(source + 1)
113-
.map(|h| h.start())
114-
.unwrap_or_else(|| self.edge_list_data.len() - DEP_NODE_PAD);
115-
116-
// The number of edges for this node is implicitly stored in the combination of the byte
117-
// width and the length.
109+
118110
let bytes_per_index = header.bytes_per_index();
119-
let len = (end - header.start()) / bytes_per_index;
120111

121112
// LLVM doesn't hoist EdgeHeader::mask so we do it ourselves.
122113
let mask = header.mask();
123-
(0..len).map(move |_| {
114+
(0..header.num_edges).map(move |_| {
124115
// Doing this slicing in this order ensures that the first bounds check suffices for
125116
// all the others.
126117
let index = &raw[..DEP_NODE_SIZE];
@@ -163,6 +154,7 @@ impl SerializedDepGraph {
163154
#[derive(Debug, Clone, Copy)]
164155
struct EdgeHeader {
165156
repr: usize,
157+
num_edges: u32,
166158
}
167159

168160
impl EdgeHeader {
@@ -205,9 +197,14 @@ impl SerializedDepGraph {
205197

206198
let graph_bytes = d.len() - (2 * IntEncodedWithFixedSize::ENCODED_SIZE) - d.position();
207199

208-
let mut nodes = IndexVec::with_capacity(node_count);
209-
let mut fingerprints = IndexVec::with_capacity(node_count);
210-
let mut edge_list_indices = IndexVec::with_capacity(node_count);
200+
let mut nodes = IndexVec::from_elem_n(
201+
DepNode { kind: D::DEP_KIND_NULL, hash: PackedFingerprint::from(Fingerprint::ZERO) },
202+
node_count,
203+
);
204+
let mut fingerprints = IndexVec::from_elem_n(Fingerprint::ZERO, node_count);
205+
let mut edge_list_indices =
206+
IndexVec::from_elem_n(EdgeHeader { repr: 0, num_edges: 0 }, node_count);
207+
211208
// This estimation assumes that all of the encoded bytes are for the edge lists or for the
212209
// fixed-size node headers. But that's not necessarily true; if any edge list has a length
213210
// that spills out of the size we can bit-pack into SerializedNodeHeader then some of the
@@ -226,11 +223,14 @@ impl SerializedDepGraph {
226223
let node_header =
227224
SerializedNodeHeader::<D> { bytes: d.read_array(), _marker: PhantomData };
228225

229-
let _i: SerializedDepNodeIndex = nodes.push(node_header.node());
230-
debug_assert_eq!(_i.index(), _index);
226+
let index = node_header.index();
227+
228+
let node = &mut nodes[index];
229+
// Make sure there's no duplicate indices in the dep graph.
230+
assert!(node_header.node().kind != D::DEP_KIND_NULL && node.kind == D::DEP_KIND_NULL);
231+
*node = node_header.node();
231232

232-
let _i: SerializedDepNodeIndex = fingerprints.push(node_header.fingerprint());
233-
debug_assert_eq!(_i.index(), _index);
233+
fingerprints[index] = node_header.fingerprint();
234234

235235
// If the length of this node's edge list is small, the length is stored in the header.
236236
// If it is not, we fall back to another decoder call.
@@ -242,12 +242,11 @@ impl SerializedDepGraph {
242242
let edges_len_bytes = node_header.bytes_per_index() * (num_edges as usize);
243243
// The in-memory structure for the edges list stores the byte width of the edges on
244244
// this node with the offset into the global edge data array.
245-
let edges_header = node_header.edges_header(&edge_list_data);
245+
let edges_header = node_header.edges_header(&edge_list_data, num_edges);
246246

247247
edge_list_data.extend(d.read_raw_bytes(edges_len_bytes));
248248

249-
let _i: SerializedDepNodeIndex = edge_list_indices.push(edges_header);
250-
debug_assert_eq!(_i.index(), _index);
249+
edge_list_indices[index] = edges_header;
251250
}
252251

253252
// When we access the edge list data, we do a fixed-size read from the edge list data then
@@ -298,9 +297,10 @@ impl SerializedDepGraph {
298297
/// * In whatever bits remain, the length of the edge list for this node, if it fits
299298
struct SerializedNodeHeader<D> {
300299
// 2 bytes for the DepNode
300+
// 4 bytes for the index
301301
// 16 for Fingerprint in DepNode
302302
// 16 for Fingerprint in NodeInfo
303-
bytes: [u8; 34],
303+
bytes: [u8; 38],
304304
_marker: PhantomData<D>,
305305
}
306306

@@ -310,6 +310,7 @@ struct Unpacked {
310310
len: Option<u32>,
311311
bytes_per_index: usize,
312312
kind: DepKind,
313+
index: SerializedDepNodeIndex,
313314
hash: PackedFingerprint,
314315
fingerprint: Fingerprint,
315316
}
@@ -331,6 +332,7 @@ impl<D: Deps> SerializedNodeHeader<D> {
331332
#[inline]
332333
fn new(
333334
node: DepNode,
335+
index: DepNodeIndex,
334336
fingerprint: Fingerprint,
335337
edge_max_index: u32,
336338
edge_count: usize,
@@ -352,10 +354,11 @@ impl<D: Deps> SerializedNodeHeader<D> {
352354
let hash: Fingerprint = node.hash.into();
353355

354356
// Using half-open ranges ensures an unconditional panic if we get the magic numbers wrong.
355-
let mut bytes = [0u8; 34];
357+
let mut bytes = [0u8; 38];
356358
bytes[..2].copy_from_slice(&head.to_le_bytes());
357-
bytes[2..18].copy_from_slice(&hash.to_le_bytes());
358-
bytes[18..].copy_from_slice(&fingerprint.to_le_bytes());
359+
bytes[2..6].copy_from_slice(&index.as_u32().to_le_bytes());
360+
bytes[6..22].copy_from_slice(&hash.to_le_bytes());
361+
bytes[22..].copy_from_slice(&fingerprint.to_le_bytes());
359362

360363
#[cfg(debug_assertions)]
361364
{
@@ -372,8 +375,9 @@ impl<D: Deps> SerializedNodeHeader<D> {
372375
#[inline]
373376
fn unpack(&self) -> Unpacked {
374377
let head = u16::from_le_bytes(self.bytes[..2].try_into().unwrap());
375-
let hash = self.bytes[2..18].try_into().unwrap();
376-
let fingerprint = self.bytes[18..].try_into().unwrap();
378+
let index = u32::from_le_bytes(self.bytes[2..6].try_into().unwrap());
379+
let hash = self.bytes[6..22].try_into().unwrap();
380+
let fingerprint = self.bytes[22..].try_into().unwrap();
377381

378382
let kind = head & mask(Self::KIND_BITS) as u16;
379383
let bytes_per_index = (head >> Self::KIND_BITS) & mask(Self::WIDTH_BITS) as u16;
@@ -383,6 +387,7 @@ impl<D: Deps> SerializedNodeHeader<D> {
383387
len: len.checked_sub(1),
384388
bytes_per_index: bytes_per_index as usize + 1,
385389
kind: DepKind::new(kind),
390+
index: SerializedDepNodeIndex::from_u32(index),
386391
hash: Fingerprint::from_le_bytes(hash).into(),
387392
fingerprint: Fingerprint::from_le_bytes(fingerprint),
388393
}
@@ -398,6 +403,11 @@ impl<D: Deps> SerializedNodeHeader<D> {
398403
self.unpack().bytes_per_index
399404
}
400405

406+
#[inline]
407+
fn index(&self) -> SerializedDepNodeIndex {
408+
self.unpack().index
409+
}
410+
401411
#[inline]
402412
fn fingerprint(&self) -> Fingerprint {
403413
self.unpack().fingerprint
@@ -410,9 +420,10 @@ impl<D: Deps> SerializedNodeHeader<D> {
410420
}
411421

412422
#[inline]
413-
fn edges_header(&self, edge_list_data: &[u8]) -> EdgeHeader {
423+
fn edges_header(&self, edge_list_data: &[u8], num_edges: u32) -> EdgeHeader {
414424
EdgeHeader {
415425
repr: (edge_list_data.len() << DEP_NODE_WIDTH_BITS) | (self.bytes_per_index() - 1),
426+
num_edges,
416427
}
417428
}
418429
}
@@ -425,10 +436,15 @@ struct NodeInfo {
425436
}
426437

427438
impl NodeInfo {
428-
fn encode<D: Deps>(&self, e: &mut FileEncoder) {
439+
fn encode<D: Deps>(&self, e: &mut MemEncoder, index: DepNodeIndex) {
429440
let NodeInfo { node, fingerprint, ref edges } = *self;
430-
let header =
431-
SerializedNodeHeader::<D>::new(node, fingerprint, edges.max_index(), edges.len());
441+
let header = SerializedNodeHeader::<D>::new(
442+
node,
443+
index,
444+
fingerprint,
445+
edges.max_index(),
446+
edges.len(),
447+
);
432448
e.write_array(header.bytes);
433449

434450
if header.len().is_none() {
@@ -450,8 +466,9 @@ impl NodeInfo {
450466
/// This avoids the overhead of constructing `EdgesVec`, which would be needed to call `encode`.
451467
#[inline]
452468
fn encode_promoted<D: Deps>(
453-
e: &mut FileEncoder,
469+
e: &mut MemEncoder,
454470
node: DepNode,
471+
index: DepNodeIndex,
455472
fingerprint: Fingerprint,
456473
prev_index: SerializedDepNodeIndex,
457474
colors: &DepNodeColorMap,
@@ -464,7 +481,7 @@ impl NodeInfo {
464481
let edge_max =
465482
edges.clone().map(|i| colors.current(i).unwrap().as_u32()).max().unwrap_or(0);
466483

467-
let header = SerializedNodeHeader::<D>::new(node, fingerprint, edge_max, edge_count);
484+
let header = SerializedNodeHeader::<D>::new(node, index, fingerprint, edge_max, edge_count);
468485
e.write_array(header.bytes);
469486

470487
if header.len().is_none() {
@@ -498,6 +515,8 @@ struct EncoderState<D: Deps> {
498515
total_edge_count: usize,
499516
stats: Option<FxHashMap<DepKind, Stat>>,
500517

518+
mem_encoder: MemEncoder,
519+
501520
/// Stores the number of times we've encoded each dep kind.
502521
kind_stats: Vec<u32>,
503522
marker: PhantomData<D>,
@@ -511,22 +530,28 @@ impl<D: Deps> EncoderState<D> {
511530
total_edge_count: 0,
512531
total_node_count: 0,
513532
stats: record_stats.then(FxHashMap::default),
533+
mem_encoder: MemEncoder::new(),
514534
kind_stats: iter::repeat(0).take(D::DEP_KIND_MAX as usize + 1).collect(),
515535
marker: PhantomData,
516536
}
517537
}
518538

539+
#[inline]
540+
fn alloc_index(&mut self) -> DepNodeIndex {
541+
let index = DepNodeIndex::new(self.total_node_count);
542+
self.total_node_count += 1;
543+
index
544+
}
545+
519546
#[inline]
520547
fn record(
521548
&mut self,
522549
node: DepNode,
550+
index: DepNodeIndex,
523551
edge_count: usize,
524552
edges: impl FnOnce(&mut Self) -> Vec<DepNodeIndex>,
525553
record_graph: &Option<Lock<DepGraphQuery>>,
526554
) -> DepNodeIndex {
527-
let index = DepNodeIndex::new(self.total_node_count);
528-
529-
self.total_node_count += 1;
530555
self.kind_stats[node.kind.as_usize()] += 1;
531556
self.total_edge_count += edge_count;
532557

@@ -558,14 +583,25 @@ impl<D: Deps> EncoderState<D> {
558583
index
559584
}
560585

586+
#[inline]
587+
fn flush_mem_encoder(&mut self) {
588+
let data = &mut self.mem_encoder.data;
589+
if data.len() > 64 * 1024 {
590+
self.encoder.emit_raw_bytes(&data[..]);
591+
data.clear();
592+
}
593+
}
594+
561595
/// Encodes a node to the current graph.
562596
fn encode_node(
563597
&mut self,
564598
node: &NodeInfo,
565599
record_graph: &Option<Lock<DepGraphQuery>>,
566600
) -> DepNodeIndex {
567-
node.encode::<D>(&mut self.encoder);
568-
self.record(node.node, node.edges.len(), |_| node.edges[..].to_vec(), record_graph)
601+
let index = self.alloc_index();
602+
node.encode::<D>(&mut self.mem_encoder, index);
603+
self.flush_mem_encoder();
604+
self.record(node.node, index, node.edges.len(), |_| node.edges[..].to_vec(), record_graph)
569605
}
570606

571607
/// Encodes a node that was promoted from the previous graph. It reads the information directly from
@@ -581,20 +617,22 @@ impl<D: Deps> EncoderState<D> {
581617
record_graph: &Option<Lock<DepGraphQuery>>,
582618
colors: &DepNodeColorMap,
583619
) -> DepNodeIndex {
620+
let index = self.alloc_index();
584621
let node = self.previous.index_to_node(prev_index);
585-
586622
let fingerprint = self.previous.fingerprint_by_index(prev_index);
587623
let edge_count = NodeInfo::encode_promoted::<D>(
588-
&mut self.encoder,
624+
&mut self.mem_encoder,
589625
node,
626+
index,
590627
fingerprint,
591628
prev_index,
592629
colors,
593630
&self.previous,
594631
);
595-
632+
self.flush_mem_encoder();
596633
self.record(
597634
node,
635+
index,
598636
edge_count,
599637
|this| {
600638
this.previous
@@ -603,12 +641,14 @@ impl<D: Deps> EncoderState<D> {
603641
.collect()
604642
},
605643
record_graph,
606-
)
644+
);
645+
index
607646
}
608647

609648
fn finish(self, profiler: &SelfProfilerRef) -> FileEncodeResult {
610649
let Self {
611650
mut encoder,
651+
mem_encoder,
612652
total_node_count,
613653
total_edge_count,
614654
stats: _,
@@ -617,6 +657,8 @@ impl<D: Deps> EncoderState<D> {
617657
previous,
618658
} = self;
619659

660+
encoder.emit_raw_bytes(&mem_encoder.data);
661+
620662
let node_count = total_node_count.try_into().unwrap();
621663
let edge_count = total_edge_count.try_into().unwrap();
622664

compiler/rustc_serialize/src/opaque.rs

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ use crate::int_overflow::DebugStrictAdd;
1010
use crate::leb128;
1111
use crate::serialize::{Decodable, Decoder, Encodable, Encoder};
1212

13+
pub mod mem_encoder;
14+
1315
// -----------------------------------------------------------------------------
1416
// Encoder
1517
// -----------------------------------------------------------------------------

0 commit comments

Comments
 (0)