-
Notifications
You must be signed in to change notification settings - Fork 13.1k
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
[WIP] Prerequisites from dep graph refactoring #60559
Closed
Closed
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
88e0226
Add a Worker type which allows executing code in the background
Zoxc 42bd80a
Fix inherent_impls
Zoxc f186b83
Add an AtomicCell abstraction
Zoxc 9bdd397
Add compare_and_swap
Zoxc c052998
Add get_mut
Zoxc 86e1d91
Update Cargo.lock
Zoxc File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
use super::{Lrc, Lock}; | ||
|
||
pub trait Worker: super::Send { | ||
type Message: super::Send; | ||
type Result: super::Send; | ||
|
||
fn message(&mut self, msg: Self::Message); | ||
fn complete(self) -> Self::Result; | ||
} | ||
|
||
pub use executor::WorkerExecutor; | ||
|
||
#[cfg(parallel_compiler)] | ||
mod executor { | ||
use super::*; | ||
use crate::jobserver; | ||
use parking_lot::Condvar; | ||
use std::mem; | ||
|
||
struct WorkerQueue<T: Worker> { | ||
scheduled: bool, | ||
complete: bool, | ||
messages: Vec<T::Message>, | ||
result: Option<T::Result>, | ||
} | ||
|
||
/// Allows executing a worker on any Rayon thread, | ||
/// sending it messages and waiting for it to complete its computation. | ||
pub struct WorkerExecutor<T: Worker> { | ||
queue: Lock<WorkerQueue<T>>, | ||
worker: Lock<Option<T>>, | ||
#[cfg(parallel_compiler)] | ||
cond_var: Condvar, | ||
} | ||
|
||
impl<T: Worker> WorkerExecutor<T> { | ||
pub fn new(worker: T) -> Self { | ||
WorkerExecutor { | ||
queue: Lock::new(WorkerQueue { | ||
scheduled: false, | ||
complete: false, | ||
messages: Vec::new(), | ||
result: None, | ||
}), | ||
worker: Lock::new(Some(worker)), | ||
#[cfg(parallel_compiler)] | ||
cond_var: Condvar::new(), | ||
} | ||
} | ||
|
||
fn try_run_worker(&self) { | ||
if let Some(mut worker) = self.worker.try_lock() { | ||
self.run_worker(&mut *worker); | ||
} | ||
} | ||
|
||
fn run_worker(&self, worker: &mut Option<T>) { | ||
let worker_ref = if let Some(worker_ref) = worker.as_mut() { | ||
worker_ref | ||
} else { | ||
return | ||
}; | ||
loop { | ||
let msgs = { | ||
let mut queue = self.queue.lock(); | ||
let msgs = mem::replace(&mut queue.messages, Vec::new()); | ||
if msgs.is_empty() { | ||
queue.scheduled = false; | ||
if queue.complete { | ||
queue.result = Some(worker.take().unwrap().complete()); | ||
self.cond_var.notify_all(); | ||
} | ||
break; | ||
} | ||
msgs | ||
}; | ||
for msg in msgs { | ||
worker_ref.message(msg); | ||
} | ||
} | ||
} | ||
|
||
pub fn complete(&self) -> T::Result { | ||
let mut queue = self.queue.lock(); | ||
assert!(!queue.complete); | ||
queue.complete = true; | ||
if !queue.scheduled { | ||
// The worker is not scheduled to run, just run it on the current thread. | ||
queue.scheduled = true; | ||
mem::drop(queue); | ||
self.run_worker(&mut *self.worker.lock()); | ||
queue = self.queue.lock(); | ||
} else if let Some(mut worker) = self.worker.try_lock() { | ||
// Try to run the worker on the current thread. | ||
// It was scheduled to run, but it may not have started yet. | ||
// If we are using a single thread, it may never start at all. | ||
mem::drop(queue); | ||
self.run_worker(&mut *worker); | ||
queue = self.queue.lock(); | ||
} else { | ||
// The worker must be running on some other thread, | ||
// and will eventually look at the queue again, since queue.scheduled is true. | ||
// Wait for it. | ||
|
||
#[cfg(parallel_compiler)] | ||
{ | ||
// Wait for the result | ||
jobserver::release_thread(); | ||
self.cond_var.wait(&mut queue); | ||
jobserver::acquire_thread(); | ||
} | ||
} | ||
queue.result.take().unwrap() | ||
} | ||
|
||
fn queue_message(&self, msg: T::Message) -> bool { | ||
let mut queue = self.queue.lock(); | ||
queue.messages.push(msg); | ||
let was_scheduled = queue.scheduled; | ||
if !was_scheduled { | ||
queue.scheduled = true; | ||
} | ||
was_scheduled | ||
} | ||
|
||
pub fn message_in_pool(self: &Lrc<Self>, msg: T::Message) | ||
where | ||
T: 'static | ||
{ | ||
if !self.queue_message(msg) { | ||
let this = self.clone(); | ||
#[cfg(parallel_compiler)] | ||
rayon::spawn(move || this.try_run_worker()); | ||
#[cfg(not(parallel_compiler))] | ||
this.try_run_worker(); | ||
} | ||
} | ||
} | ||
} | ||
|
||
#[cfg(not(parallel_compiler))] | ||
mod executor { | ||
use super::*; | ||
|
||
pub struct WorkerExecutor<T: Worker> { | ||
worker: Lock<Option<T>>, | ||
} | ||
|
||
impl<T: Worker> WorkerExecutor<T> { | ||
pub fn new(worker: T) -> Self { | ||
WorkerExecutor { | ||
worker: Lock::new(Some(worker)), | ||
} | ||
} | ||
|
||
#[inline] | ||
pub fn complete(&self) -> T::Result { | ||
self.worker.lock().take().unwrap().complete() | ||
} | ||
|
||
#[inline] | ||
pub fn message_in_pool(self: &Lrc<Self>, msg: T::Message) | ||
where | ||
T: 'static | ||
{ | ||
self.worker.lock().as_mut().unwrap().message(msg); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,6 @@ | |
//! `tcx.inherent_impls(def_id)`). That value, however, | ||
//! is computed by selecting an idea from this table. | ||
|
||
use rustc::dep_graph::DepKind; | ||
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; | ||
use rustc::hir; | ||
use rustc::hir::itemlikevisit::ItemLikeVisitor; | ||
|
@@ -36,35 +35,11 @@ pub fn crate_inherent_impls<'tcx>( | |
pub fn inherent_impls<'tcx>(tcx: TyCtxt<'tcx>, ty_def_id: DefId) -> &'tcx [DefId] { | ||
assert!(ty_def_id.is_local()); | ||
|
||
// NB. Until we adopt the red-green dep-tracking algorithm (see | ||
// [the plan] for details on that), we do some hackery here to get | ||
// the dependencies correct. Basically, we use a `with_ignore` to | ||
// read the result we want. If we didn't have the `with_ignore`, | ||
// we would wind up with a dependency on the entire crate, which | ||
// we don't want. Then we go and add dependencies on all the impls | ||
// in the result (which is what we wanted). | ||
// | ||
// The result is a graph with an edge from `Hir(I)` for every impl | ||
// `I` defined on some type `T` to `CoherentInherentImpls(T)`, | ||
// thus ensuring that if any of those impls change, the set of | ||
// inherent impls is considered dirty. | ||
// | ||
// [the plan]: https://github.com/rust-lang/rust-roadmap/issues/4 | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice find! |
||
let result = tcx.dep_graph.with_ignore(|| { | ||
let crate_map = tcx.crate_inherent_impls(ty_def_id.krate); | ||
match crate_map.inherent_impls.get(&ty_def_id) { | ||
Some(v) => &v[..], | ||
None => &[], | ||
} | ||
}); | ||
|
||
for &impl_def_id in &result[..] { | ||
let def_path_hash = tcx.def_path_hash(impl_def_id); | ||
tcx.dep_graph.read(def_path_hash.to_dep_node(DepKind::Hir)); | ||
let crate_map = tcx.crate_inherent_impls(ty_def_id.krate); | ||
match crate_map.inherent_impls.get(&ty_def_id) { | ||
Some(v) => &v[..], | ||
None => &[], | ||
} | ||
|
||
result | ||
} | ||
|
||
struct InherentCollect<'tcx> { | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Can you add module level documentation here that describes what this is? In particular: