-
Notifications
You must be signed in to change notification settings - Fork 13k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Loading the dependency graph in the background #46560
Conversation
(rust_highfive has picked a reviewer for you, use r? to override) |
|
||
if self.cleanup_needed { | ||
if let Err(err) = delete_all_session_dir_contents(sess) { | ||
sess.err(&format!("Failed to delete invalidated or incompatible incremental compilation session \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tidy error.
[00:04:24] tidy error: /checkout/src/librustc_incremental/persist/load.rs:95: line longer than 100 chars
@@ -60,7 +59,7 @@ pub fn write_file_header<W: io::Write>(stream: &mut W) -> io::Result<()> { | |||
/// incompatible version of the compiler. | |||
/// - Returns `Err(..)` if some kind of IO error occurred while reading the | |||
/// file. | |||
pub fn read_file(sess: &Session, path: &Path) -> io::Result<Option<(Vec<u8>, usize)>> { | |||
pub fn read_file(report_incremental_info: bool, path: &Path) -> io::Result<Option<(Vec<u8>, usize)>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tidy error.
[00:04:24] tidy error: /checkout/src/librustc_incremental/persist/file_format.rs:62: line longer than 100 chars
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your PR, @Yoric!
I've left some comments below. I think the story around LoadResult
is not factored quite cleanly yet.
src/librustc_driver/driver.rs
Outdated
let prev_dep_graph = time(time_passes, "load prev dep-graph", || { | ||
// If necessary, compute the dependency graph (in the background). | ||
let future_dep_graph = if sess.opts.build_dep_graph() { | ||
Some(time(time_passes, "load prev dep-graph", || { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This time()
call will only measure spawning the thread. I think it would make more sense to measure the duration spent in the new thread.
pub struct LoadResult<T> { | ||
data: T, | ||
cleanup_needed: bool, | ||
warnings: Option<String> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we are calling Session::err()
with these, errors
would be a better name (warning implies something non-fatal while error will abort the compilation process.
match file_format::read_file(report_incremental_info, path) { | ||
Ok(Some(data_and_pos)) => LoadResult { | ||
data: Some(data_and_pos), | ||
..LoadResult::default() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I usually prefer listing fields exhaustively in situations like this, as it makes the code easier to read.
Ok(None) => { | ||
// The file either didn't exist or was produced by an incompatible | ||
// compiler version. Neither is an error. | ||
LoadResult::default() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cleanup_needed
must be set to true here (only the Ok(Some(..))
branch returned without the cleanup).
fn load_data(sess: &Session, path: &Path) -> Option<(Vec<u8>, usize)> { | ||
match file_format::read_file(sess, path) { | ||
Ok(Some(data_and_pos)) => return Some(data_and_pos), | ||
pub struct LoadResult<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like this should be an enum. Something like:
enum LoadResult {
Ok { data: T },
DataOutOfDate,
Error { message: String },
}
if sess.opts.incremental.is_none() { | ||
return empty | ||
} | ||
let aux = move || { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you make this just one closure that is directly passed to thread::spawn()
? Having one closure nested inside of another feels a bit roundabout.
(updated) |
e3a6b96
to
2130e5e
Compare
I don't really understand the tests that fail :/ |
These tests make sure that some expected paths in the dep-graph exist and that others don't. That all the output is missing makes me suspect that the graph is not loaded at all or not generated. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! This looks much cleaner now.
I think the failing tests are because the compiler crashes because we enable the dependency graph in these cases but don't specify a cache directory. This case was previously covered by 2130e5e#diff-8f003505e6f30ad2197a2883c43cb5c2L109.
To verify this, I'll run the tests locally and look at the actual test output (which can be found in text files within the build directory).
pub fn open(self, sess: &Session) -> PreviousDepGraph { | ||
match self { | ||
LoadResult::Error { message } => { | ||
sess.err(&message) /* never returns */; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sess.err()
actually does return (the compilation process is aborted at a later time, possible after more errors have been reported). But you can just use sess.fatal()
to get the desired effect.
}, | ||
LoadResult::DataOutOfDate => { | ||
if let Err(err) = delete_all_session_dir_contents(sess) { | ||
sess.err(&format!("Failed to delete invalidated or incompatible \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can also use sess.fatal()
here too.
{ | ||
let is_incremental = sess.opts.incremental.is_some(); | ||
let report_incremental_info = sess.opts.debugging_opts.incremental_info; | ||
let path = dep_graph_path_from(&sess.incr_comp_session_dir()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line might be crashing if the dependency graph is enabled but we don't have a caching directory. This can happen in the failing test cases. I'll verify this later.
It looks like 2130e5e#diff-8f003505e6f30ad2197a2883c43cb5c2R140 really is the problem. |
7d3c8f2
to
67a085c
Compare
…graph to background thread
Ok, tests now pass :) |
📌 Commit a0fb93d has been approved by |
⌛ Testing commit a0fb93d with merge cfd66a768a71a322d1d0e0ffc6116db5ad4b3b33... |
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`.
☀️ Test successful - status-appveyor, status-travis |
Patch is a bit longer than I expected, due to the fact that most of this code relies upon a
Session
value, which is notSync
.