Skip to content

Commit c801cd6

Browse files
committed
Address review: rename field, lazy-build helper, fold decode loops
Rename the reverse-index field from `index` to `reverse_index`. Move the per-kind fingerprint map build into `LazyKindIndex::fingerprint_map` and have it `debug_assert` each node's kind matches the kind being built, so `node_to_index_opt` is just the lookup. Read the per-kind counts and build their offset ranges in a single decode loop, size `nodes_by_kind` by `node_count`, and document why the placeholder index is never read and why `Null` nodes are skipped.
1 parent 36661b1 commit c801cd6

1 file changed

Lines changed: 65 additions & 41 deletions

File tree

compiler/rustc_middle/src/dep_graph/serialized.rs

Lines changed: 65 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ use rustc_data_structures::outline;
5151
use rustc_data_structures::profiling::SelfProfilerRef;
5252
use rustc_data_structures::sync::{AtomicU64, Lock, WorkerLocal, broadcast};
5353
use rustc_data_structures::unhash::UnhashMap;
54-
use rustc_index::IndexVec;
54+
use rustc_index::{IndexSlice, IndexVec};
5555
use rustc_serialize::opaque::mem_encoder::MemEncoder;
5656
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder};
5757
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
@@ -116,7 +116,7 @@ pub struct SerializedDepGraph {
116116
/// The lazily-built inverse of `nodes`: maps a [`DepNode`] back to its
117117
/// [`SerializedDepNodeIndex`] via the node's key fingerprint. See
118118
/// [`LazyNodeIndex`].
119-
index: LazyNodeIndex,
119+
reverse_index: LazyNodeIndex,
120120
/// The number of previous compilation sessions. This is used to generate
121121
/// unique anon dep nodes per session.
122122
session_count: u64,
@@ -158,6 +158,42 @@ struct LazyKindIndex {
158158
map: OnceLock<UnhashMap<PackedFingerprint, SerializedDepNodeIndex>>,
159159
}
160160

161+
impl LazyKindIndex {
162+
/// Returns this kind's `key_fingerprint -> node index` map, building it from
163+
/// the kind's range of `nodes_by_kind` on the first call. Building does the
164+
/// per-node hash-map inserts that decode used to perform eagerly for every
165+
/// kind; here we only pay it for kinds that are actually looked up.
166+
fn fingerprint_map(
167+
&self,
168+
kind: DepKind,
169+
nodes: &IndexSlice<SerializedDepNodeIndex, DepNode>,
170+
nodes_by_kind: &[SerializedDepNodeIndex],
171+
) -> &UnhashMap<PackedFingerprint, SerializedDepNodeIndex> {
172+
self.map.get_or_init(|| {
173+
let range = (self.start as usize)..(self.start as usize + self.len as usize);
174+
let mut map =
175+
UnhashMap::with_capacity_and_hasher(self.len as usize, Default::default());
176+
for &idx in &nodes_by_kind[range] {
177+
let node = &nodes[idx];
178+
debug_assert_eq!(node.kind, kind);
179+
if map.insert(node.key_fingerprint, idx).is_some()
180+
// Side effect nodes can legitimately share a fingerprint.
181+
&& node.kind != DepKind::SideEffect
182+
{
183+
panic!(
184+
"Error: A dep graph node ({kind:?}) does not have an unique index. \
185+
Running a clean build on a nightly compiler with \
186+
`-Z incremental-verify-ich` can help narrow down the issue for reporting. \
187+
A clean build may also work around the issue.\n
188+
DepNode: {node:?}"
189+
)
190+
}
191+
}
192+
map
193+
})
194+
}
195+
}
196+
161197
impl SerializedDepGraph {
162198
#[inline]
163199
pub fn edge_targets_from(
@@ -188,28 +224,9 @@ impl SerializedDepGraph {
188224

189225
#[inline]
190226
pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option<SerializedDepNodeIndex> {
191-
let kind = self.index.kinds.get(dep_node.kind.as_usize())?;
192-
let map = kind.map.get_or_init(|| {
193-
let range = (kind.start as usize)..(kind.start as usize + kind.len as usize);
194-
let mut map = UnhashMap::with_capacity_and_hasher(kind.len as usize, Default::default());
195-
for &idx in &self.index.nodes_by_kind[range] {
196-
let node = &self.nodes[idx];
197-
if map.insert(node.key_fingerprint, idx).is_some()
198-
// Side effect nodes can legitimately share a fingerprint.
199-
&& node.kind != DepKind::SideEffect
200-
{
201-
panic!(
202-
"Error: A dep graph node ({:?}) does not have an unique index. \
203-
Running a clean build on a nightly compiler with \
204-
`-Z incremental-verify-ich` can help narrow down the issue for reporting. \
205-
A clean build may also work around the issue.\n
206-
DepNode: {node:?}",
207-
node.kind
208-
)
209-
}
210-
}
211-
map
212-
});
227+
let kind = self.reverse_index.kinds.get(dep_node.kind.as_usize())?;
228+
let map =
229+
kind.fingerprint_map(dep_node.kind, &self.nodes, &self.reverse_index.nodes_by_kind);
213230
map.get(&dep_node.key_fingerprint).copied()
214231
}
215232

@@ -345,43 +362,50 @@ impl SerializedDepGraph {
345362
// end of the array. This padding ensure it doesn't.
346363
edge_list_data.extend(&[0u8; DEP_NODE_PAD]);
347364

348-
// Read the number of nodes of each dep kind. These per-kind counts let us
349-
// group node indices by kind below; the fingerprint -> index maps
350-
// themselves are built lazily, per kind, on first lookup (see
351-
// `LazyNodeIndex`).
352-
let kind_counts: Vec<u32> = (0..(DepKind::MAX + 1)).map(|_| d.read_u32()).collect();
353-
354-
let session_count = d.read_u64();
355-
356-
// Counting sort: place every (non-`Null`) node index into a contiguous
357-
// per-kind range of `nodes_by_kind`, using the per-kind counts to compute
358-
// each kind's start offset. Padding gaps (`DepKind::Null`) are never
359-
// looked up by fingerprint, so we skip them.
360-
let mut kinds = Vec::with_capacity(kind_counts.len());
365+
// Read the number of nodes of each dep kind, turning each per-kind count
366+
// into a contiguous, still-empty range of `nodes_by_kind` as we go (a
367+
// prefix sum of the counts gives each kind's start offset). The
368+
// fingerprint -> index map for a kind is built lazily, on the first lookup
369+
// of that kind (see `LazyKindIndex::fingerprint_map`).
370+
let mut kinds = Vec::with_capacity(DepKind::MAX as usize + 1);
361371
let mut offset = 0u32;
362-
for &len in &kind_counts {
372+
for _ in 0..(DepKind::MAX + 1) {
373+
let len = d.read_u32();
363374
kinds.push(LazyKindIndex { start: offset, len, map: OnceLock::new() });
364375
offset += len;
365376
}
377+
// Every encoded node has a (non-`Null`) kind, so the per-kind counts sum to
378+
// `node_count`; `Null` nodes are never encoded, so no range is reserved for
379+
// them.
366380
debug_assert_eq!(offset as usize, node_count);
367-
let mut nodes_by_kind = vec![SerializedDepNodeIndex::from_u32(0); offset as usize];
381+
382+
let session_count = d.read_u64();
383+
384+
// Counting sort: place each node index into its kind's range. `fill[k]`
385+
// points at the next free slot in kind `k`'s range, so a kind's nodes end
386+
// up contiguous. Every slot is written exactly once (the counts sum to the
387+
// number of non-`Null` nodes), so the placeholder index used to size the
388+
// vector is always overwritten before it can be read.
389+
let mut nodes_by_kind = vec![SerializedDepNodeIndex::from_u32(0); node_count];
368390
let mut fill: Vec<u32> = kinds.iter().map(|k| k.start).collect();
369391
for (idx, node) in nodes.iter_enumerated() {
392+
// Unused indices from batch allocation stay `Null`; they carry no
393+
// encoded node and are never looked up by fingerprint, so skip them.
370394
if node.kind == DepKind::Null {
371395
continue;
372396
}
373397
let k = node.kind.as_usize();
374398
nodes_by_kind[fill[k] as usize] = idx;
375399
fill[k] += 1;
376400
}
377-
let index = LazyNodeIndex { nodes_by_kind, kinds };
401+
let reverse_index = LazyNodeIndex { nodes_by_kind, kinds };
378402

379403
Arc::new(SerializedDepGraph {
380404
nodes,
381405
value_fingerprints,
382406
edge_list_indices,
383407
edge_list_data,
384-
index,
408+
reverse_index,
385409
session_count,
386410
})
387411
}

0 commit comments

Comments
 (0)