Skip to content

Commit b3392f8

Browse files
committed
Auto merge of #46560 - Yoric:incr, r=michaelwoerister
Loading the dependency graph in the background Patch is a bit longer than I expected, due to the fact that most of this code relies upon a `Session` value, which is not `Sync`.
2 parents 39cb4c6 + a0fb93d commit b3392f8

File tree

5 files changed

+136
-62
lines changed

5 files changed

+136
-62
lines changed

Diff for: src/librustc_data_structures/indexed_vec.rs

+4
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,10 @@ pub struct IndexVec<I: Idx, T> {
330330
_marker: PhantomData<Fn(&I)>
331331
}
332332

333+
// Whether `IndexVec` is `Send` depends only on the data,
334+
// not the phantom data.
335+
unsafe impl<I: Idx, T> Send for IndexVec<I, T> where T: Send {}
336+
333337
impl<I: Idx, T: serialize::Encodable> serialize::Encodable for IndexVec<I, T> {
334338
fn encode<S: serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
335339
serialize::Encodable::encode(&self.raw, s)

Diff for: src/librustc_driver/driver.rs

+15-7
Original file line numberDiff line numberDiff line change
@@ -646,14 +646,11 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
646646
disambiguator,
647647
);
648648

649-
let dep_graph = if sess.opts.build_dep_graph() {
650-
let prev_dep_graph = time(time_passes, "load prev dep-graph", || {
651-
rustc_incremental::load_dep_graph(sess)
652-
});
653-
654-
DepGraph::new(prev_dep_graph)
649+
// If necessary, compute the dependency graph (in the background).
650+
let future_dep_graph = if sess.opts.build_dep_graph() {
651+
Some(rustc_incremental::load_dep_graph(sess, time_passes))
655652
} else {
656-
DepGraph::new_disabled()
653+
None
657654
};
658655

659656
time(time_passes, "recursion limit", || {
@@ -881,6 +878,17 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
881878
})?;
882879

883880
// Lower ast -> hir.
881+
// First, we need to collect the dep_graph.
882+
let dep_graph = match future_dep_graph {
883+
None => DepGraph::new_disabled(),
884+
Some(future) => {
885+
let prev_graph = future
886+
.open()
887+
.expect("Could not join with background dep_graph thread")
888+
.open(sess);
889+
DepGraph::new(prev_graph)
890+
}
891+
};
884892
let hir_forest = time(time_passes, "lowering ast -> hir", || {
885893
let hir_crate = lower_crate(sess, cstore, &dep_graph, &krate, &mut resolver);
886894

Diff for: src/librustc_incremental/persist/file_format.rs

+8-7
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ use std::path::Path;
2424
use std::fs::File;
2525
use std::env;
2626

27-
use rustc::session::Session;
2827
use rustc::session::config::nightly_options;
2928

3029
/// The first few bytes of files generated by incremental compilation
@@ -60,7 +59,9 @@ pub fn write_file_header<W: io::Write>(stream: &mut W) -> io::Result<()> {
6059
/// incompatible version of the compiler.
6160
/// - Returns `Err(..)` if some kind of IO error occurred while reading the
6261
/// file.
63-
pub fn read_file(sess: &Session, path: &Path) -> io::Result<Option<(Vec<u8>, usize)>> {
62+
pub fn read_file(report_incremental_info: bool, path: &Path)
63+
-> io::Result<Option<(Vec<u8>, usize)>>
64+
{
6465
if !path.exists() {
6566
return Ok(None);
6667
}
@@ -79,7 +80,7 @@ pub fn read_file(sess: &Session, path: &Path) -> io::Result<Option<(Vec<u8>, usi
7980
let mut file_magic = [0u8; 4];
8081
file.read_exact(&mut file_magic)?;
8182
if file_magic != FILE_MAGIC {
82-
report_format_mismatch(sess, path, "Wrong FILE_MAGIC");
83+
report_format_mismatch(report_incremental_info, path, "Wrong FILE_MAGIC");
8384
return Ok(None)
8485
}
8586
}
@@ -93,7 +94,7 @@ pub fn read_file(sess: &Session, path: &Path) -> io::Result<Option<(Vec<u8>, usi
9394
((header_format_version[1] as u16) << 8);
9495

9596
if header_format_version != HEADER_FORMAT_VERSION {
96-
report_format_mismatch(sess, path, "Wrong HEADER_FORMAT_VERSION");
97+
report_format_mismatch(report_incremental_info, path, "Wrong HEADER_FORMAT_VERSION");
9798
return Ok(None)
9899
}
99100
}
@@ -108,7 +109,7 @@ pub fn read_file(sess: &Session, path: &Path) -> io::Result<Option<(Vec<u8>, usi
108109
file.read_exact(&mut buffer)?;
109110

110111
if buffer != rustc_version().as_bytes() {
111-
report_format_mismatch(sess, path, "Different compiler version");
112+
report_format_mismatch(report_incremental_info, path, "Different compiler version");
112113
return Ok(None);
113114
}
114115
}
@@ -117,10 +118,10 @@ pub fn read_file(sess: &Session, path: &Path) -> io::Result<Option<(Vec<u8>, usi
117118
Ok(Some((file.into_inner(), post_header_start_pos)))
118119
}
119120

120-
fn report_format_mismatch(sess: &Session, file: &Path, message: &str) {
121+
fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: &str) {
121122
debug!("read_file: {}", message);
122123

123-
if sess.opts.debugging_opts.incremental_info {
124+
if report_incremental_info {
124125
println!("[incremental] ignoring cache artifact `{}`: {}",
125126
file.file_name().unwrap().to_string_lossy(),
126127
message);

Diff for: src/librustc_incremental/persist/fs.rs

+3
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,9 @@ const INT_ENCODE_BASE: u64 = 36;
142142
pub fn dep_graph_path(sess: &Session) -> PathBuf {
143143
in_incr_comp_dir_sess(sess, DEP_GRAPH_FILENAME)
144144
}
145+
pub fn dep_graph_path_from(incr_comp_session_dir: &Path) -> PathBuf {
146+
in_incr_comp_dir(incr_comp_session_dir, DEP_GRAPH_FILENAME)
147+
}
145148

146149
pub fn work_products_path(sess: &Session) -> PathBuf {
147150
in_incr_comp_dir_sess(sess, WORK_PRODUCTS_FILENAME)

Diff for: src/librustc_incremental/persist/load.rs

+106-48
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ use rustc::dep_graph::{PreviousDepGraph, SerializedDepGraph};
1414
use rustc::session::Session;
1515
use rustc::ty::TyCtxt;
1616
use rustc::ty::maps::OnDiskCache;
17+
use rustc::util::common::time;
1718
use rustc_serialize::Decodable as RustcDecodable;
1819
use rustc_serialize::opaque::Decoder;
1920
use std::path::Path;
21+
use std;
2022

2123
use super::data::*;
2224
use super::fs::*;
@@ -39,7 +41,9 @@ pub fn dep_graph_tcx_init<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
3941
}
4042

4143
let work_products_path = work_products_path(tcx.sess);
42-
if let Some((work_products_data, start_pos)) = load_data(tcx.sess, &work_products_path) {
44+
let load_result = load_data(tcx.sess.opts.debugging_opts.incremental_info, &work_products_path);
45+
46+
if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result {
4347
// Decode the list of work_products
4448
let mut work_product_decoder = Decoder::new(&work_products_data[..], start_pos);
4549
let work_products: Vec<SerializedWorkProduct> =
@@ -74,27 +78,50 @@ pub fn dep_graph_tcx_init<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
7478
}
7579
}
7680

77-
fn load_data(sess: &Session, path: &Path) -> Option<(Vec<u8>, usize)> {
78-
match file_format::read_file(sess, path) {
79-
Ok(Some(data_and_pos)) => return Some(data_and_pos),
81+
pub enum LoadResult<T> {
82+
Ok { data: T },
83+
DataOutOfDate,
84+
Error { message: String },
85+
}
86+
87+
88+
impl LoadResult<PreviousDepGraph> {
89+
pub fn open(self, sess: &Session) -> PreviousDepGraph {
90+
match self {
91+
LoadResult::Error { message } => {
92+
sess.fatal(&message) /* never returns */
93+
},
94+
LoadResult::DataOutOfDate => {
95+
if let Err(err) = delete_all_session_dir_contents(sess) {
96+
sess.err(&format!("Failed to delete invalidated or incompatible \
97+
incremental compilation session directory contents `{}`: {}.",
98+
dep_graph_path(sess).display(), err));
99+
}
100+
PreviousDepGraph::new(SerializedDepGraph::new())
101+
}
102+
LoadResult::Ok { data } => data
103+
}
104+
}
105+
}
106+
107+
108+
fn load_data(report_incremental_info: bool, path: &Path) -> LoadResult<(Vec<u8>, usize)> {
109+
match file_format::read_file(report_incremental_info, path) {
110+
Ok(Some(data_and_pos)) => LoadResult::Ok {
111+
data: data_and_pos
112+
},
80113
Ok(None) => {
81114
// The file either didn't exist or was produced by an incompatible
82115
// compiler version. Neither is an error.
116+
LoadResult::DataOutOfDate
83117
}
84118
Err(err) => {
85-
sess.err(
86-
&format!("could not load dep-graph from `{}`: {}",
87-
path.display(), err));
119+
LoadResult::Error {
120+
message: format!("could not load dep-graph from `{}`: {}",
121+
path.display(), err)
122+
}
88123
}
89124
}
90-
91-
if let Err(err) = delete_all_session_dir_contents(sess) {
92-
sess.err(&format!("could not clear incompatible incremental \
93-
compilation session directory `{}`: {}",
94-
path.display(), err));
95-
}
96-
97-
None
98125
}
99126

100127
fn delete_dirty_work_product(tcx: TyCtxt,
@@ -103,41 +130,73 @@ fn delete_dirty_work_product(tcx: TyCtxt,
103130
work_product::delete_workproduct_files(tcx.sess, &swp.work_product);
104131
}
105132

106-
pub fn load_dep_graph(sess: &Session) -> PreviousDepGraph {
107-
let empty = PreviousDepGraph::new(SerializedDepGraph::new());
108-
109-
if sess.opts.incremental.is_none() {
110-
return empty
133+
/// Either a result that has already be computed or a
134+
/// handle that will let us wait until it is computed
135+
/// by a background thread.
136+
pub enum MaybeAsync<T> {
137+
Sync(T),
138+
Async(std::thread::JoinHandle<T>)
139+
}
140+
impl<T> MaybeAsync<T> {
141+
pub fn open(self) -> std::thread::Result<T> {
142+
match self {
143+
MaybeAsync::Sync(result) => Ok(result),
144+
MaybeAsync::Async(handle) => handle.join()
145+
}
111146
}
147+
}
112148

113-
if let Some((bytes, start_pos)) = load_data(sess, &dep_graph_path(sess)) {
114-
let mut decoder = Decoder::new(&bytes, start_pos);
115-
let prev_commandline_args_hash = u64::decode(&mut decoder)
116-
.expect("Error reading commandline arg hash from cached dep-graph");
117-
118-
if prev_commandline_args_hash != sess.opts.dep_tracking_hash() {
119-
if sess.opts.debugging_opts.incremental_info {
120-
println!("[incremental] completely ignoring cache because of \
121-
differing commandline arguments");
122-
}
123-
// We can't reuse the cache, purge it.
124-
debug!("load_dep_graph_new: differing commandline arg hashes");
149+
/// Launch a thread and load the dependency graph in the background.
150+
pub fn load_dep_graph(sess: &Session, time_passes: bool) ->
151+
MaybeAsync<LoadResult<PreviousDepGraph>>
152+
{
153+
// Since `sess` isn't `Sync`, we perform all accesses to `sess`
154+
// before we fire the background thread.
125155

126-
delete_all_session_dir_contents(sess)
127-
.expect("Failed to delete invalidated incr. comp. session \
128-
directory contents.");
156+
if sess.opts.incremental.is_none() {
157+
// No incremental compilation.
158+
return MaybeAsync::Sync(LoadResult::Ok {
159+
data: PreviousDepGraph::new(SerializedDepGraph::new())
160+
});
161+
}
129162

130-
// No need to do any further work
131-
return empty
132-
}
163+
// Calling `sess.incr_comp_session_dir()` will panic if `sess.opts.incremental.is_none()`.
164+
// Fortunately, we just checked that this isn't the case.
165+
let path = dep_graph_path_from(&sess.incr_comp_session_dir());
166+
let report_incremental_info = sess.opts.debugging_opts.incremental_info;
167+
let expected_hash = sess.opts.dep_tracking_hash();
168+
169+
MaybeAsync::Async(std::thread::spawn(move || {
170+
time(time_passes, "background load prev dep-graph", move || {
171+
match load_data(report_incremental_info, &path) {
172+
LoadResult::DataOutOfDate => LoadResult::DataOutOfDate,
173+
LoadResult::Error { message } => LoadResult::Error { message },
174+
LoadResult::Ok { data: (bytes, start_pos) } => {
175+
176+
let mut decoder = Decoder::new(&bytes, start_pos);
177+
let prev_commandline_args_hash = u64::decode(&mut decoder)
178+
.expect("Error reading commandline arg hash from cached dep-graph");
179+
180+
if prev_commandline_args_hash != expected_hash {
181+
if report_incremental_info {
182+
println!("[incremental] completely ignoring cache because of \
183+
differing commandline arguments");
184+
}
185+
// We can't reuse the cache, purge it.
186+
debug!("load_dep_graph_new: differing commandline arg hashes");
187+
188+
// No need to do any further work
189+
return LoadResult::DataOutOfDate;
190+
}
133191

134-
let dep_graph = SerializedDepGraph::decode(&mut decoder)
135-
.expect("Error reading cached dep-graph");
192+
let dep_graph = SerializedDepGraph::decode(&mut decoder)
193+
.expect("Error reading cached dep-graph");
136194

137-
PreviousDepGraph::new(dep_graph)
138-
} else {
139-
empty
140-
}
195+
LoadResult::Ok { data: PreviousDepGraph::new(dep_graph) }
196+
}
197+
}
198+
})
199+
}))
141200
}
142201

143202
pub fn load_query_result_cache<'sess>(sess: &'sess Session) -> OnDiskCache<'sess> {
@@ -146,9 +205,8 @@ pub fn load_query_result_cache<'sess>(sess: &'sess Session) -> OnDiskCache<'sess
146205
return OnDiskCache::new_empty(sess.codemap());
147206
}
148207

149-
if let Some((bytes, start_pos)) = load_data(sess, &query_cache_path(sess)) {
150-
OnDiskCache::new(sess, bytes, start_pos)
151-
} else {
152-
OnDiskCache::new_empty(sess.codemap())
208+
match load_data(sess.opts.debugging_opts.incremental_info, &query_cache_path(sess)) {
209+
LoadResult::Ok{ data: (bytes, start_pos) } => OnDiskCache::new(sess, bytes, start_pos),
210+
_ => OnDiskCache::new_empty(sess.codemap())
153211
}
154212
}

0 commit comments

Comments
 (0)