Stream the dep-graph to a file.
This commit is contained in:
parent
16156fb278
commit
6bfaf3a9cb
18 changed files with 710 additions and 918 deletions
|
@ -40,8 +40,9 @@ use rustc_graphviz as dot;
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||
use rustc_middle::dep_graph::debug::{DepNodeFilter, EdgeFilter};
|
||||
use rustc_middle::dep_graph::{DepGraphQuery, DepKind, DepNode, DepNodeExt};
|
||||
use rustc_middle::dep_graph::{
|
||||
DepGraphQuery, DepKind, DepNode, DepNodeExt, DepNodeFilter, EdgeFilter,
|
||||
};
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
|
@ -54,7 +55,7 @@ use std::io::{BufWriter, Write};
|
|||
pub fn assert_dep_graph(tcx: TyCtxt<'_>) {
|
||||
tcx.dep_graph.with_ignore(|| {
|
||||
if tcx.sess.opts.debugging_opts.dump_dep_graph {
|
||||
dump_graph(tcx);
|
||||
tcx.dep_graph.with_query(dump_graph);
|
||||
}
|
||||
|
||||
if !tcx.sess.opts.debugging_opts.query_dep_graph {
|
||||
|
@ -200,29 +201,29 @@ fn check_paths<'tcx>(tcx: TyCtxt<'tcx>, if_this_changed: &Sources, then_this_wou
|
|||
}
|
||||
return;
|
||||
}
|
||||
let query = tcx.dep_graph.query();
|
||||
for &(_, source_def_id, ref source_dep_node) in if_this_changed {
|
||||
let dependents = query.transitive_predecessors(source_dep_node);
|
||||
for &(target_span, ref target_pass, _, ref target_dep_node) in then_this_would_need {
|
||||
if !dependents.contains(&target_dep_node) {
|
||||
tcx.sess.span_err(
|
||||
target_span,
|
||||
&format!(
|
||||
"no path from `{}` to `{}`",
|
||||
tcx.def_path_str(source_def_id),
|
||||
target_pass
|
||||
),
|
||||
);
|
||||
} else {
|
||||
tcx.sess.span_err(target_span, "OK");
|
||||
tcx.dep_graph.with_query(|query| {
|
||||
for &(_, source_def_id, ref source_dep_node) in if_this_changed {
|
||||
let dependents = query.transitive_predecessors(source_dep_node);
|
||||
for &(target_span, ref target_pass, _, ref target_dep_node) in then_this_would_need {
|
||||
if !dependents.contains(&target_dep_node) {
|
||||
tcx.sess.span_err(
|
||||
target_span,
|
||||
&format!(
|
||||
"no path from `{}` to `{}`",
|
||||
tcx.def_path_str(source_def_id),
|
||||
target_pass
|
||||
),
|
||||
);
|
||||
} else {
|
||||
tcx.sess.span_err(target_span, "OK");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn dump_graph(tcx: TyCtxt<'_>) {
|
||||
fn dump_graph(query: &DepGraphQuery) {
|
||||
let path: String = env::var("RUST_DEP_GRAPH").unwrap_or_else(|_| "dep_graph".to_string());
|
||||
let query = tcx.dep_graph.query();
|
||||
|
||||
let nodes = match env::var("RUST_DEP_GRAPH_FILTER") {
|
||||
Ok(string) => {
|
||||
|
|
|
@ -14,7 +14,7 @@ mod assert_dep_graph;
|
|||
pub mod assert_module_sources;
|
||||
mod persist;
|
||||
|
||||
pub use assert_dep_graph::assert_dep_graph;
|
||||
use assert_dep_graph::assert_dep_graph;
|
||||
pub use persist::copy_cgu_workproduct_to_incr_comp_cache_dir;
|
||||
pub use persist::delete_workproduct_files;
|
||||
pub use persist::finalize_session_directory;
|
||||
|
@ -26,4 +26,4 @@ pub use persist::prepare_session_directory;
|
|||
pub use persist::save_dep_graph;
|
||||
pub use persist::save_work_product_index;
|
||||
pub use persist::LoadResult;
|
||||
pub use persist::{load_dep_graph, DepGraphFuture};
|
||||
pub use persist::{build_dep_graph, load_dep_graph, DepGraphFuture};
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
//! the required condition is not met.
|
||||
|
||||
use rustc_ast::{self as ast, Attribute, NestedMetaItem};
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
|
@ -381,10 +380,7 @@ impl DirtyCleanVisitor<'tcx> {
|
|||
fn assert_dirty(&self, item_span: Span, dep_node: DepNode) {
|
||||
debug!("assert_dirty({:?})", dep_node);
|
||||
|
||||
let current_fingerprint = self.get_fingerprint(&dep_node);
|
||||
let prev_fingerprint = self.tcx.dep_graph.prev_fingerprint_of(&dep_node);
|
||||
|
||||
if current_fingerprint == prev_fingerprint {
|
||||
if self.tcx.dep_graph.is_green(&dep_node) {
|
||||
let dep_node_str = self.dep_node_str(&dep_node);
|
||||
self.tcx
|
||||
.sess
|
||||
|
@ -392,28 +388,12 @@ impl DirtyCleanVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_fingerprint(&self, dep_node: &DepNode) -> Option<Fingerprint> {
|
||||
if self.tcx.dep_graph.dep_node_exists(dep_node) {
|
||||
let dep_node_index = self.tcx.dep_graph.dep_node_index_of(dep_node);
|
||||
Some(self.tcx.dep_graph.fingerprint_of(dep_node_index))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_clean(&self, item_span: Span, dep_node: DepNode) {
|
||||
debug!("assert_clean({:?})", dep_node);
|
||||
|
||||
let current_fingerprint = self.get_fingerprint(&dep_node);
|
||||
let prev_fingerprint = self.tcx.dep_graph.prev_fingerprint_of(&dep_node);
|
||||
|
||||
// if the node wasn't previously evaluated and now is (or vice versa),
|
||||
// then the node isn't actually clean or dirty.
|
||||
if (current_fingerprint == None) ^ (prev_fingerprint == None) {
|
||||
return;
|
||||
}
|
||||
|
||||
if current_fingerprint != prev_fingerprint {
|
||||
if self.tcx.dep_graph.is_red(&dep_node) {
|
||||
let dep_node_str = self.dep_node_str(&dep_node);
|
||||
self.tcx
|
||||
.sess
|
||||
|
|
|
@ -122,6 +122,7 @@ mod tests;
|
|||
|
||||
const LOCK_FILE_EXT: &str = ".lock";
|
||||
const DEP_GRAPH_FILENAME: &str = "dep-graph.bin";
|
||||
const STAGING_DEP_GRAPH_FILENAME: &str = "dep-graph.part.bin";
|
||||
const WORK_PRODUCTS_FILENAME: &str = "work-products.bin";
|
||||
const QUERY_CACHE_FILENAME: &str = "query-cache.bin";
|
||||
|
||||
|
@ -134,6 +135,9 @@ const INT_ENCODE_BASE: usize = base_n::CASE_INSENSITIVE;
|
|||
pub fn dep_graph_path(sess: &Session) -> PathBuf {
|
||||
in_incr_comp_dir_sess(sess, DEP_GRAPH_FILENAME)
|
||||
}
|
||||
pub fn staging_dep_graph_path(sess: &Session) -> PathBuf {
|
||||
in_incr_comp_dir_sess(sess, STAGING_DEP_GRAPH_FILENAME)
|
||||
}
|
||||
pub fn dep_graph_path_from(incr_comp_session_dir: &Path) -> PathBuf {
|
||||
in_incr_comp_dir(incr_comp_session_dir, DEP_GRAPH_FILENAME)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use rustc_hir::definitions::Definitions;
|
|||
use rustc_middle::dep_graph::{PreviousDepGraph, SerializedDepGraph, WorkProduct, WorkProductId};
|
||||
use rustc_middle::ty::query::OnDiskCache;
|
||||
use rustc_serialize::opaque::Decoder;
|
||||
use rustc_serialize::Decodable as RustcDecodable;
|
||||
use rustc_serialize::Decodable;
|
||||
use rustc_session::Session;
|
||||
use std::path::Path;
|
||||
|
||||
|
@ -120,7 +120,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
|
|||
// Decode the list of work_products
|
||||
let mut work_product_decoder = Decoder::new(&work_products_data[..], start_pos);
|
||||
let work_products: Vec<SerializedWorkProduct> =
|
||||
RustcDecodable::decode(&mut work_product_decoder).unwrap_or_else(|e| {
|
||||
Decodable::decode(&mut work_product_decoder).unwrap_or_else(|e| {
|
||||
let msg = format!(
|
||||
"Error decoding `work-products` from incremental \
|
||||
compilation session directory: {}",
|
||||
|
|
|
@ -18,6 +18,7 @@ pub use fs::prepare_session_directory;
|
|||
pub use load::load_query_result_cache;
|
||||
pub use load::LoadResult;
|
||||
pub use load::{load_dep_graph, DepGraphFuture};
|
||||
pub use save::build_dep_graph;
|
||||
pub use save::save_dep_graph;
|
||||
pub use save::save_work_product_index;
|
||||
pub use work_product::copy_cgu_workproduct_to_incr_comp_cache_dir;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sync::join;
|
||||
use rustc_middle::dep_graph::{DepGraph, WorkProduct, WorkProductId};
|
||||
use rustc_middle::dep_graph::{DepGraph, PreviousDepGraph, WorkProduct, WorkProductId};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
|
||||
use rustc_serialize::Encodable as RustcEncodable;
|
||||
|
@ -15,6 +15,9 @@ use super::file_format;
|
|||
use super::fs::*;
|
||||
use super::work_product;
|
||||
|
||||
/// Save and dump the DepGraph.
|
||||
///
|
||||
/// No query must be invoked after this function.
|
||||
pub fn save_dep_graph(tcx: TyCtxt<'_>) {
|
||||
debug!("save_dep_graph()");
|
||||
tcx.dep_graph.with_ignore(|| {
|
||||
|
@ -29,6 +32,16 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) {
|
|||
|
||||
let query_cache_path = query_cache_path(sess);
|
||||
let dep_graph_path = dep_graph_path(sess);
|
||||
let staging_dep_graph_path = staging_dep_graph_path(sess);
|
||||
|
||||
join(
|
||||
|| sess.time("assert_dep_graph", || crate::assert_dep_graph(tcx)),
|
||||
|| sess.time("check_dirty_clean", || dirty_clean::check_dirty_clean_annotations(tcx)),
|
||||
);
|
||||
|
||||
if sess.opts.debugging_opts.incremental_info {
|
||||
tcx.dep_graph.print_incremental_info()
|
||||
}
|
||||
|
||||
join(
|
||||
move || {
|
||||
|
@ -36,16 +49,26 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) {
|
|||
save_in(sess, query_cache_path, "query cache", |e| encode_query_cache(tcx, e));
|
||||
});
|
||||
},
|
||||
|| {
|
||||
move || {
|
||||
sess.time("incr_comp_persist_dep_graph", || {
|
||||
save_in(sess, dep_graph_path, "dependency graph", |e| {
|
||||
sess.time("incr_comp_encode_dep_graph", || encode_dep_graph(tcx, e))
|
||||
});
|
||||
if let Err(err) = tcx.dep_graph.encode() {
|
||||
sess.err(&format!(
|
||||
"failed to write dependency graph to `{}`: {}",
|
||||
staging_dep_graph_path.display(),
|
||||
err
|
||||
));
|
||||
}
|
||||
if let Err(err) = fs::rename(&staging_dep_graph_path, &dep_graph_path) {
|
||||
sess.err(&format!(
|
||||
"failed to move dependency graph from `{}` to `{}`: {}",
|
||||
staging_dep_graph_path.display(),
|
||||
dep_graph_path.display(),
|
||||
err
|
||||
));
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
dirty_clean::check_dirty_clean_annotations(tcx);
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -92,7 +115,7 @@ pub fn save_work_product_index(
|
|||
});
|
||||
}
|
||||
|
||||
fn save_in<F>(sess: &Session, path_buf: PathBuf, name: &str, encode: F)
|
||||
pub(crate) fn save_in<F>(sess: &Session, path_buf: PathBuf, name: &str, encode: F)
|
||||
where
|
||||
F: FnOnce(&mut FileEncoder) -> FileEncodeResult,
|
||||
{
|
||||
|
@ -144,21 +167,6 @@ where
|
|||
debug!("save: data written to disk successfully");
|
||||
}
|
||||
|
||||
fn encode_dep_graph(tcx: TyCtxt<'_>, encoder: &mut FileEncoder) -> FileEncodeResult {
|
||||
// First encode the commandline arguments hash
|
||||
tcx.sess.opts.dep_tracking_hash().encode(encoder)?;
|
||||
|
||||
if tcx.sess.opts.debugging_opts.incremental_info {
|
||||
tcx.dep_graph.print_incremental_info();
|
||||
}
|
||||
|
||||
// There is a tiny window between printing the incremental info above and encoding the dep
|
||||
// graph below in which the dep graph could change, thus making the printed incremental info
|
||||
// slightly out of date. If this matters to you, please feel free to submit a patch. :)
|
||||
|
||||
tcx.sess.time("incr_comp_encode_serialized_dep_graph", || tcx.dep_graph.encode(encoder))
|
||||
}
|
||||
|
||||
fn encode_work_product_index(
|
||||
work_products: &FxHashMap<WorkProductId, WorkProduct>,
|
||||
encoder: &mut FileEncoder,
|
||||
|
@ -177,3 +185,56 @@ fn encode_work_product_index(
|
|||
fn encode_query_cache(tcx: TyCtxt<'_>, encoder: &mut FileEncoder) -> FileEncodeResult {
|
||||
tcx.sess.time("incr_comp_serialize_result_cache", || tcx.serialize_query_result_cache(encoder))
|
||||
}
|
||||
|
||||
pub fn build_dep_graph(
|
||||
sess: &Session,
|
||||
prev_graph: PreviousDepGraph,
|
||||
prev_work_products: FxHashMap<WorkProductId, WorkProduct>,
|
||||
) -> Option<DepGraph> {
|
||||
if sess.opts.incremental.is_none() {
|
||||
// No incremental compilation.
|
||||
return None;
|
||||
}
|
||||
|
||||
// Stream the dep-graph to an alternate file, to avoid overwriting anything in case of errors.
|
||||
let path_buf = staging_dep_graph_path(sess);
|
||||
|
||||
let mut encoder = match FileEncoder::new(&path_buf) {
|
||||
Ok(encoder) => encoder,
|
||||
Err(err) => {
|
||||
sess.err(&format!(
|
||||
"failed to create dependency graph at `{}`: {}",
|
||||
path_buf.display(),
|
||||
err
|
||||
));
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(err) = file_format::write_file_header(&mut encoder, sess.is_nightly_build()) {
|
||||
sess.err(&format!(
|
||||
"failed to write dependency graph header to `{}`: {}",
|
||||
path_buf.display(),
|
||||
err
|
||||
));
|
||||
return None;
|
||||
}
|
||||
|
||||
// First encode the commandline arguments hash
|
||||
if let Err(err) = sess.opts.dep_tracking_hash().encode(&mut encoder) {
|
||||
sess.err(&format!(
|
||||
"failed to write dependency graph hash `{}`: {}",
|
||||
path_buf.display(),
|
||||
err
|
||||
));
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(DepGraph::new(
|
||||
prev_graph,
|
||||
prev_work_products,
|
||||
encoder,
|
||||
sess.opts.debugging_opts.query_dep_graph,
|
||||
sess.opts.debugging_opts.incremental_info,
|
||||
))
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue