Skip to content

Commit

Permalink
Create the previous dep graph index on a background thread
Browse files Browse the repository at this point in the history
  • Loading branch information
Zoxc committed Oct 3, 2023
1 parent 4f75af9 commit 2c65d52
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 22 deletions.
5 changes: 3 additions & 2 deletions compiler/rustc_incremental/src/persist/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use rustc_session::config::IncrementalStateAssertion;
use rustc_session::{Session, StableCrateId};
use rustc_span::{ErrorGuaranteed, Symbol};
use std::path::{Path, PathBuf};
use std::sync::Arc;

use super::data::*;
use super::file_format;
Expand Down Expand Up @@ -95,7 +96,7 @@ fn delete_dirty_work_product(sess: &Session, swp: SerializedWorkProduct) {
work_product::delete_workproduct_files(sess, &swp.work_product);
}

fn load_dep_graph(sess: &Session) -> LoadResult<(SerializedDepGraph, WorkProductMap)> {
fn load_dep_graph(sess: &Session) -> LoadResult<(Arc<SerializedDepGraph>, WorkProductMap)> {
let prof = sess.prof.clone();

if sess.opts.incremental.is_none() {
Expand Down Expand Up @@ -169,7 +170,7 @@ fn load_dep_graph(sess: &Session) -> LoadResult<(SerializedDepGraph, WorkProduct
return LoadResult::DataOutOfDate;
}

let dep_graph = SerializedDepGraph::decode::<DepsType>(&mut decoder);
let dep_graph = SerializedDepGraph::decode::<DepsType>(&mut decoder, sess);

LoadResult::Ok { data: (dep_graph, prev_work_products) }
}
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_incremental/src/persist/save.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
use rustc_serialize::Encodable as RustcEncodable;
use rustc_session::Session;
use std::fs;
use std::sync::Arc;

use super::data::*;
use super::dirty_clean;
Expand Down Expand Up @@ -149,7 +150,7 @@ fn encode_query_cache(tcx: TyCtxt<'_>, encoder: FileEncoder) -> FileEncodeResult
/// and moves it to the permanent dep-graph path
pub(crate) fn build_dep_graph(
sess: &Session,
prev_graph: SerializedDepGraph,
prev_graph: Arc<SerializedDepGraph>,
prev_work_products: WorkProductMap,
) -> Option<DepGraph> {
if sess.opts.incremental.is_none() {
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_query_system/src/dep_graph/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use std::fmt::Debug;
use std::hash::Hash;
use std::marker::PhantomData;
use std::sync::atomic::Ordering::Relaxed;
use std::sync::Arc;

use super::query::DepGraphQuery;
use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex};
Expand Down Expand Up @@ -83,7 +84,7 @@ pub struct DepGraphData<D: Deps> {

/// The dep-graph from the previous compilation session. It contains all
/// nodes and edges as well as all fingerprints of nodes that have them.
previous: SerializedDepGraph,
previous: Arc<SerializedDepGraph>,

colors: DepNodeColorMap,

Expand Down Expand Up @@ -115,7 +116,7 @@ where
impl<D: Deps> DepGraph<D> {
pub fn new(
profiler: &SelfProfilerRef,
prev_graph: SerializedDepGraph,
prev_graph: Arc<SerializedDepGraph>,
prev_work_products: WorkProductMap,
encoder: FileEncoder,
record_graph: bool,
Expand Down
105 changes: 88 additions & 17 deletions compiler/rustc_query_system/src/dep_graph/serialized.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,17 @@ use crate::dep_graph::EdgesVec;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fingerprint::PackedFingerprint;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::outline;
use rustc_data_structures::profiling::SelfProfilerRef;
use rustc_data_structures::sync::Lock;
use rustc_data_structures::unhash::UnhashMap;
use rustc_index::{Idx, IndexVec};
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use std::iter;
use rustc_session::Session;
use std::marker::PhantomData;
use std::sync::{Arc, OnceLock};
use std::{iter, thread};

// The maximum value of `SerializedDepNodeIndex` leaves the upper two bits
// unused so that we can store multiple index types in `CompressedHybridIndex`,
Expand All @@ -69,23 +72,33 @@ const DEP_NODE_PAD: usize = DEP_NODE_SIZE - 1;
const DEP_NODE_WIDTH_BITS: usize = DEP_NODE_SIZE / 2;

/// Data for use when recompiling the **current crate**.
#[derive(Debug)]
pub struct SerializedDepGraph {
/// The set of all DepNodes in the graph
nodes: IndexVec<SerializedDepNodeIndex, DepNode>,

/// The set of all Fingerprints in the graph. Each Fingerprint corresponds to
/// the DepNode at the same index in the nodes vector.
fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>,

/// For each DepNode, stores the list of edges originating from that
/// DepNode. Encoded as a [start, end) pair indexing into edge_list_data,
/// which holds the actual DepNodeIndices of the target nodes.
edge_list_indices: IndexVec<SerializedDepNodeIndex, EdgeHeader>,

/// A flattened list of all edge targets in the graph, stored in the same
/// varint encoding that we use on disk. Edge sources are implicit in edge_list_indices.
edge_list_data: Vec<u8>,

/// Stores a map from fingerprints to nodes per dep node kind.
/// This is the reciprocal of `nodes`.
index: Vec<UnhashMap<PackedFingerprint, SerializedDepNodeIndex>>,
/// This is the reciprocal of `nodes`. This is computed on demand for each dep kind.
/// The entire index is also computed in a background thread.
index: Vec<OnceLock<UnhashMap<PackedFingerprint, SerializedDepNodeIndex>>>,

/// Stores the number of node for each dep node kind.
index_sizes: Vec<usize>,

/// A profiler reference for used in the index prefetching thread.
prof: SelfProfilerRef,
}

impl Default for SerializedDepGraph {
Expand All @@ -96,6 +109,8 @@ impl Default for SerializedDepGraph {
edge_list_indices: Default::default(),
edge_list_data: Default::default(),
index: Default::default(),
index_sizes: Default::default(),
prof: SelfProfilerRef::new(None, None),
}
}
}
Expand Down Expand Up @@ -138,9 +153,35 @@ impl SerializedDepGraph {
self.nodes[dep_node_index]
}

/// This computes and sets up the index for just the specified `DepKind`.
fn setup_index(&self, dep_kind: DepKind) {
let _timer = self.prof.generic_activity("incr_comp_dep_graph_setup_index");

let mut index = UnhashMap::with_capacity_and_hasher(
self.index_sizes[dep_kind.as_usize()],
Default::default(),
);

for (idx, node) in self.nodes.iter_enumerated() {
if node.kind == dep_kind {
index.insert(node.hash, idx);
}
}

// This may race with the prefetching thread, but that will set the same value.
self.index[dep_kind.as_usize()].set(index).ok();
}

#[inline]
pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option<SerializedDepNodeIndex> {
self.index.get(dep_node.kind.as_usize())?.get(&dep_node.hash).cloned()
let index = self.index.get(dep_node.kind.as_usize())?;
let index = index.get().unwrap_or_else(|| {
outline(|| {
self.setup_index(dep_node.kind);
self.index[dep_node.kind.as_usize()].get().unwrap()
})
});
index.get(&dep_node.hash).cloned()
}

#[inline]
Expand All @@ -152,6 +193,31 @@ impl SerializedDepGraph {
pub fn node_count(&self) -> usize {
self.nodes.len()
}

/// This spawns a thread that prefetches the index.
fn prefetch(self: &Arc<Self>) {
if !self.index.is_empty() {
let this = self.clone();
thread::spawn(move || {
let _timer = this.prof.generic_activity("incr_comp_prefetch_dep_graph_index");

let mut index: Vec<_> = this
.index_sizes
.iter()
.map(|&n| UnhashMap::with_capacity_and_hasher(n, Default::default()))
.collect();

for (idx, node) in this.nodes.iter_enumerated() {
index[node.kind.as_usize()].insert(node.hash, idx);
}

for (i, index) in index.into_iter().enumerate() {
// This may race with `setup_index`, but that will set the same value.
this.index[i].set(index).ok();
}
});
}
}
}

/// A packed representation of an edge's start index and byte width.
Expand Down Expand Up @@ -185,8 +251,8 @@ fn mask(bits: usize) -> usize {
}

impl SerializedDepGraph {
#[instrument(level = "debug", skip(d))]
pub fn decode<D: Deps>(d: &mut MemDecoder<'_>) -> SerializedDepGraph {
#[instrument(level = "debug", skip(d, sess))]
pub fn decode<D: Deps>(d: &mut MemDecoder<'_>, sess: &Session) -> Arc<SerializedDepGraph> {
// The last 16 bytes are the node count and edge count.
debug!("position: {:?}", d.position());
let (node_count, edge_count) =
Expand Down Expand Up @@ -253,16 +319,21 @@ impl SerializedDepGraph {
// end of the array. This padding ensure it doesn't.
edge_list_data.extend(&[0u8; DEP_NODE_PAD]);

// Read the number of each dep kind and use it to create an hash map with a suitable size.
let mut index: Vec<_> = (0..(D::DEP_KIND_MAX + 1))
.map(|_| UnhashMap::with_capacity_and_hasher(d.read_u32() as usize, Default::default()))
.collect();

for (idx, node) in nodes.iter_enumerated() {
index[node.kind.as_usize()].insert(node.hash, idx);
}

SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data, index }
// Read the number of nodes for each dep kind.
let index_sizes: Vec<_> =
(0..(D::DEP_KIND_MAX + 1)).map(|_| d.read_u32() as usize).collect();

let result = Arc::new(SerializedDepGraph {
nodes,
fingerprints,
edge_list_indices,
edge_list_data,
index: (0..index_sizes.len()).map(|_| OnceLock::new()).collect(),
index_sizes,
prof: sess.prof.clone(),
});
result.prefetch();
result
}
}

Expand Down

0 comments on commit 2c65d52

Please sign in to comment.