Skip to content

Commit cca4804

Browse files
committed
Code to save/load the work-products map from disk
Work products are deleted if any of their inputs are dirty.
1 parent ffc13b2 commit cca4804

File tree

7 files changed

+191
-53
lines changed

7 files changed

+191
-53
lines changed

src/librustc_driver/driver.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ pub fn compile_input(sess: &Session,
8888
// We need nested scopes here, because the intermediate results can keep
8989
// large chunks of memory alive and we want to free them as soon as
9090
// possible to keep the peak memory usage low
91-
let (outputs, trans) = {
91+
let (outputs, trans, id) = {
9292
let krate = match phase_1_parse_input(sess, cfg, input) {
9393
Ok(krate) => krate,
9494
Err(mut parse_error) => {
@@ -212,11 +212,11 @@ pub fn compile_input(sess: &Session,
212212
// Discard interned strings as they are no longer required.
213213
token::clear_ident_interner();
214214

215-
Ok((outputs, trans))
215+
Ok((outputs, trans, id.clone()))
216216
})??
217217
};
218218

219-
let phase5_result = phase_5_run_llvm_passes(sess, &trans, &outputs);
219+
let phase5_result = phase_5_run_llvm_passes(sess, &id, &trans, &outputs);
220220

221221
controller_entry_point!(after_llvm,
222222
sess,
@@ -1020,6 +1020,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
10201020
/// Run LLVM itself, producing a bitcode file, assembly file or object file
10211021
/// as a side effect.
10221022
pub fn phase_5_run_llvm_passes(sess: &Session,
1023+
crate_name: &str,
10231024
trans: &trans::CrateTranslation,
10241025
outputs: &OutputFilenames) -> CompileResult {
10251026
if sess.opts.cg.no_integrated_as {
@@ -1041,6 +1042,10 @@ pub fn phase_5_run_llvm_passes(sess: &Session,
10411042
|| write::run_passes(sess, trans, &sess.opts.output_types, outputs));
10421043
}
10431044

1045+
time(sess.time_passes(),
1046+
"serialize work products",
1047+
move || rustc_incremental::save_work_products(sess, crate_name));
1048+
10441049
if sess.err_count() > 0 {
10451050
Err(sess.err_count())
10461051
} else {

src/librustc_incremental/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
html_root_url = "https://doc.rust-lang.org/nightly/")]
2020
#![cfg_attr(not(stage0), deny(warnings))]
2121

22+
#![feature(question_mark)]
2223
#![feature(rustc_private)]
2324
#![feature(staged_api)]
2425

@@ -40,3 +41,4 @@ pub use assert_dep_graph::assert_dep_graph;
4041
pub use calculate_svh::SvhCalculate;
4142
pub use persist::load_dep_graph;
4243
pub use persist::save_dep_graph;
44+
pub use persist::save_work_products;

src/librustc_incremental/persist/data.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010

1111
//! The data that we will serialize and deserialize.
1212
13-
use rustc::dep_graph::DepNode;
13+
use rustc::dep_graph::{DepNode, WorkProduct, WorkProductId};
1414
use rustc::hir::def_id::DefIndex;
15+
use std::sync::Arc;
1516

1617
use super::directory::DefPathIndex;
1718

@@ -55,6 +56,15 @@ pub struct SerializedHash {
5556
pub hash: u64,
5657
}
5758

59+
#[derive(Debug, RustcEncodable, RustcDecodable)]
60+
pub struct SerializedWorkProduct {
61+
/// node that produced the work-product
62+
pub id: Arc<WorkProductId>,
63+
64+
/// work-product data itself
65+
pub work_product: WorkProduct,
66+
}
67+
5868
/// Data for use when downstream crates get recompiled.
5969
#[derive(Debug, RustcEncodable, RustcDecodable)]
6070
pub struct SerializedMetadataHashes {

src/librustc_incremental/persist/load.rs

Lines changed: 95 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@ use rbml::Error;
1414
use rbml::opaque::Decoder;
1515
use rustc::dep_graph::DepNode;
1616
use rustc::hir::def_id::DefId;
17+
use rustc::session::Session;
1718
use rustc::ty::TyCtxt;
1819
use rustc_data_structures::fnv::FnvHashSet;
1920
use rustc_serialize::Decodable as RustcDecodable;
2021
use std::io::Read;
21-
use std::fs::File;
22-
use std::path::Path;
22+
use std::fs::{self, File};
23+
use std::path::{Path};
2324

2425
use super::data::*;
2526
use super::directory::*;
@@ -38,50 +39,73 @@ type CleanEdges = Vec<(DepNode<DefId>, DepNode<DefId>)>;
3839
/// actually it doesn't matter all that much.) See `README.md` for
3940
/// more general overview.
4041
pub fn load_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
42+
if tcx.sess.opts.incremental.is_none() {
43+
return;
44+
}
45+
4146
let _ignore = tcx.dep_graph.in_ignore();
47+
load_dep_graph_if_exists(tcx);
48+
dirty_clean::check_dirty_clean_annotations(tcx);
49+
}
4250

43-
if let Some(dep_graph) = dep_graph_path(tcx) {
44-
// FIXME(#32754) lock file?
45-
load_dep_graph_if_exists(tcx, &dep_graph);
46-
dirty_clean::check_dirty_clean_annotations(tcx);
51+
fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
52+
let dep_graph_path = dep_graph_path(tcx).unwrap();
53+
let dep_graph_data = match load_data(tcx.sess, &dep_graph_path) {
54+
Some(p) => p,
55+
None => return // no file
56+
};
57+
58+
let work_products_path = tcx_work_products_path(tcx).unwrap();
59+
let work_products_data = match load_data(tcx.sess, &work_products_path) {
60+
Some(p) => p,
61+
None => return // no file
62+
};
63+
64+
match decode_dep_graph(tcx, &dep_graph_data, &work_products_data) {
65+
Ok(()) => return,
66+
Err(err) => bug!("decoding error in dep-graph from `{}` and `{}`: {}",
67+
dep_graph_path.display(),
68+
work_products_path.display(),
69+
err),
4770
}
4871
}
4972

50-
pub fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, path: &Path) {
73+
fn load_data(sess: &Session, path: &Path) -> Option<Vec<u8>> {
5174
if !path.exists() {
52-
return;
75+
return None;
5376
}
5477

5578
let mut data = vec![];
5679
match
5780
File::open(path)
5881
.and_then(|mut file| file.read_to_end(&mut data))
5982
{
60-
Ok(_) => { }
83+
Ok(_) => {
84+
Some(data)
85+
}
6186
Err(err) => {
62-
tcx.sess.err(
87+
sess.err(
6388
&format!("could not load dep-graph from `{}`: {}",
6489
path.display(), err));
65-
return;
90+
None
6691
}
6792
}
6893

69-
match decode_dep_graph(tcx, &data) {
70-
Ok(dirty) => dirty,
71-
Err(err) => {
72-
bug!("decoding error in dep-graph from `{}`: {}", path.display(), err);
73-
}
74-
}
7594
}
7695

96+
/// Decode the dep graph and load the edges/nodes that are still clean
97+
/// into `tcx.dep_graph`. On success, returns a hashset containing all
98+
/// the paths of work-products from clean nodes (any work-products not
99+
/// in this set can be deleted).
77100
pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
78-
data: &[u8])
101+
dep_graph_data: &[u8],
102+
work_products_data: &[u8])
79103
-> Result<(), Error>
80104
{
81105
// Deserialize the directory and dep-graph.
82-
let mut decoder = Decoder::new(data, 0);
83-
let directory = try!(DefIdDirectory::decode(&mut decoder));
84-
let serialized_dep_graph = try!(SerializedDepGraph::decode(&mut decoder));
106+
let mut dep_graph_decoder = Decoder::new(dep_graph_data, 0);
107+
let directory = try!(DefIdDirectory::decode(&mut dep_graph_decoder));
108+
let serialized_dep_graph = try!(SerializedDepGraph::decode(&mut dep_graph_decoder));
85109

86110
debug!("decode_dep_graph: directory = {:#?}", directory);
87111
debug!("decode_dep_graph: serialized_dep_graph = {:#?}", serialized_dep_graph);
@@ -121,12 +145,18 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
121145
// Add nodes and edges that are not dirty into our main graph.
122146
let dep_graph = tcx.dep_graph.clone();
123147
for (source, target) in clean_edges.into_iter().chain(clean_nodes) {
124-
let _task = dep_graph.in_task(target.clone());
125-
dep_graph.read(source.clone());
126-
127148
debug!("decode_dep_graph: clean edge: {:?} -> {:?}", source, target);
149+
150+
let _task = dep_graph.in_task(target);
151+
dep_graph.read(source);
128152
}
129153

154+
// Add in work-products that are still clean, and delete those that are
155+
// dirty.
156+
let mut work_product_decoder = Decoder::new(work_products_data, 0);
157+
let work_products = try!(<Vec<SerializedWorkProduct>>::decode(&mut work_product_decoder));
158+
reconcile_work_products(tcx, work_products, &dirty_nodes);
159+
130160
Ok(())
131161
}
132162

@@ -141,9 +171,9 @@ fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
141171
match hash.node.map_def(|&i| retraced.def_id(i)) {
142172
Some(dep_node) => {
143173
let current_hash = hcx.hash(&dep_node).unwrap();
144-
debug!("initial_dirty_nodes: hash of {:?} is {:?}, was {:?}",
145-
dep_node, current_hash, hash.hash);
146174
if current_hash != hash.hash {
175+
debug!("initial_dirty_nodes: {:?} is dirty as hash is {:?}, was {:?}",
176+
dep_node, current_hash, hash.hash);
147177
dirty_nodes.insert(dep_node);
148178
}
149179
}
@@ -177,6 +207,8 @@ fn compute_clean_edges(serialized_edges: &[(SerializedEdge)],
177207
clean_edges.push((source, target))
178208
} else {
179209
// source removed, target must be dirty
210+
debug!("compute_clean_edges: {:?} dirty because {:?} no longer exists",
211+
target, serialized_source);
180212
dirty_nodes.insert(target);
181213
}
182214
} else {
@@ -213,3 +245,40 @@ fn compute_clean_edges(serialized_edges: &[(SerializedEdge)],
213245

214246
clean_edges
215247
}
248+
249+
/// Go through the list of work-products produced in the previous run.
250+
/// Delete any whose nodes have been found to be dirty or which are
251+
/// otherwise no longer applicable.
252+
fn reconcile_work_products<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
253+
work_products: Vec<SerializedWorkProduct>,
254+
dirty_nodes: &DirtyNodes) {
255+
debug!("reconcile_work_products({:?})", work_products);
256+
for swp in work_products {
257+
let dep_node = DepNode::WorkProduct(swp.id.clone());
258+
if dirty_nodes.contains(&dep_node) {
259+
debug!("reconcile_work_products: dep-node for {:?} is dirty", swp);
260+
delete_dirty_work_product(tcx, swp);
261+
} else {
262+
let path = in_incr_comp_dir(tcx.sess, &swp.work_product.file_name).unwrap();
263+
if path.exists() {
264+
tcx.dep_graph.insert_previous_work_product(&swp.id, swp.work_product);
265+
} else {
266+
debug!("reconcile_work_products: file for {:?} does not exist", swp);
267+
}
268+
}
269+
}
270+
}
271+
272+
fn delete_dirty_work_product(tcx: TyCtxt,
273+
swp: SerializedWorkProduct) {
274+
debug!("delete_dirty_work_product({:?})", swp);
275+
let path = in_incr_comp_dir(tcx.sess, &swp.work_product.file_name).unwrap();
276+
match fs::remove_file(&path) {
277+
Ok(()) => { }
278+
Err(err) => {
279+
tcx.sess.warn(
280+
&format!("file-system error deleting outdated file `{}`: {}",
281+
path.display(), err));
282+
}
283+
}
284+
}

src/librustc_incremental/persist/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ mod util;
2222

2323
pub use self::load::load_dep_graph;
2424
pub use self::save::save_dep_graph;
25+
pub use self::save::save_work_products;

src/librustc_incremental/persist/save.rs

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use rbml::opaque::Encoder;
1212
use rustc::dep_graph::DepNode;
1313
use rustc::middle::cstore::LOCAL_CRATE;
14+
use rustc::session::Session;
1415
use rustc::ty::TyCtxt;
1516
use rustc_serialize::{Encodable as RustcEncodable};
1617
use std::hash::{Hasher, SipHasher};
@@ -24,19 +25,26 @@ use super::hash::*;
2425
use super::util::*;
2526

2627
pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
28+
debug!("save_dep_graph()");
2729
let _ignore = tcx.dep_graph.in_ignore();
30+
let sess = tcx.sess;
2831
let mut hcx = HashContext::new(tcx);
29-
save_in(&mut hcx, dep_graph_path(tcx), encode_dep_graph);
30-
save_in(&mut hcx, metadata_hash_path(tcx, LOCAL_CRATE), encode_metadata_hashes);
32+
save_in(sess, dep_graph_path(tcx), |e| encode_dep_graph(&mut hcx, e));
33+
save_in(sess, metadata_hash_path(tcx, LOCAL_CRATE), |e| encode_metadata_hashes(&mut hcx, e));
3134
}
3235

33-
fn save_in<'a, 'tcx, F>(hcx: &mut HashContext<'a, 'tcx>,
34-
opt_path_buf: Option<PathBuf>,
35-
encode: F)
36-
where F: FnOnce(&mut HashContext<'a, 'tcx>, &mut Encoder) -> io::Result<()>
37-
{
38-
let tcx = hcx.tcx;
36+
pub fn save_work_products(sess: &Session, local_crate_name: &str) {
37+
debug!("save_work_products()");
38+
let _ignore = sess.dep_graph.in_ignore();
39+
let path = sess_work_products_path(sess, local_crate_name);
40+
save_in(sess, path, |e| encode_work_products(sess, e));
41+
}
3942

43+
fn save_in<F>(sess: &Session,
44+
opt_path_buf: Option<PathBuf>,
45+
encode: F)
46+
where F: FnOnce(&mut Encoder) -> io::Result<()>
47+
{
4048
let path_buf = match opt_path_buf {
4149
Some(p) => p,
4250
None => return
@@ -49,7 +57,7 @@ fn save_in<'a, 'tcx, F>(hcx: &mut HashContext<'a, 'tcx>,
4957
match fs::remove_file(&path_buf) {
5058
Ok(()) => { }
5159
Err(err) => {
52-
tcx.sess.err(
60+
sess.err(
5361
&format!("unable to delete old dep-graph at `{}`: {}",
5462
path_buf.display(), err));
5563
return;
@@ -59,10 +67,10 @@ fn save_in<'a, 'tcx, F>(hcx: &mut HashContext<'a, 'tcx>,
5967

6068
// generate the data in a memory buffer
6169
let mut wr = Cursor::new(Vec::new());
62-
match encode(hcx, &mut Encoder::new(&mut wr)) {
70+
match encode(&mut Encoder::new(&mut wr)) {
6371
Ok(()) => { }
6472
Err(err) => {
65-
tcx.sess.err(
73+
sess.err(
6674
&format!("could not encode dep-graph to `{}`: {}",
6775
path_buf.display(), err));
6876
return;
@@ -77,7 +85,7 @@ fn save_in<'a, 'tcx, F>(hcx: &mut HashContext<'a, 'tcx>,
7785
{
7886
Ok(_) => { }
7987
Err(err) => {
80-
tcx.sess.err(
88+
sess.err(
8189
&format!("failed to write dep-graph to `{}`: {}",
8290
path_buf.display(), err));
8391
return;
@@ -192,3 +200,22 @@ pub fn encode_metadata_hashes<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>,
192200

193201
Ok(())
194202
}
203+
204+
pub fn encode_work_products(sess: &Session,
205+
encoder: &mut Encoder)
206+
-> io::Result<()>
207+
{
208+
let work_products: Vec<_> =
209+
sess.dep_graph.work_products()
210+
.iter()
211+
.map(|(id, work_product)| {
212+
SerializedWorkProduct {
213+
id: id.clone(),
214+
work_product: work_product.clone(),
215+
}
216+
})
217+
.collect();
218+
219+
work_products.encode(encoder)
220+
}
221+

0 commit comments

Comments
 (0)