Auto merge of #111713 - Zoxc:lock-switch, r=nnethercote
Use conditional synchronization for Lock This changes `Lock` to use synchronization only if `mode::is_dyn_thread_safe` could be true. This reduces overhead for the parallel compiler running with 1 thread. The emitters are changed to use `DynSend` instead of `Send` so they can still use `Lock`. A Rayon thread pool is not used with 1 thread anymore, as session globals contains `Lock`s which are no longer `Sync`. Performance improvement with 1 thread and `cfg(parallel_compiler)`: <table><tr><td rowspan="2">Benchmark</td><td colspan="1"><b>Before</b></th><td colspan="2"><b>After</b></th></tr><tr><td align="right">Time</td><td align="right">Time</td><td align="right">%</th></tr><tr><td>🟣 <b>clap</b>:check</td><td align="right">1.7665s</td><td align="right">1.7336s</td><td align="right">💚 -1.86%</td></tr><tr><td>🟣 <b>hyper</b>:check</td><td align="right">0.2780s</td><td align="right">0.2736s</td><td align="right">💚 -1.61%</td></tr><tr><td>🟣 <b>regex</b>:check</td><td align="right">0.9994s</td><td align="right">0.9824s</td><td align="right">💚 -1.70%</td></tr><tr><td>🟣 <b>syn</b>:check</td><td align="right">1.5875s</td><td align="right">1.5656s</td><td align="right">💚 -1.38%</td></tr><tr><td>🟣 <b>syntex_syntax</b>:check</td><td align="right">6.0682s</td><td align="right">5.9532s</td><td align="right">💚 -1.90%</td></tr><tr><td>Total</td><td align="right">10.6997s</td><td align="right">10.5083s</td><td align="right">💚 -1.79%</td></tr><tr><td>Summary</td><td align="right">1.0000s</td><td align="right">0.9831s</td><td align="right">💚 -1.69%</td></tr></table> cc `@SparrowLii`
This commit is contained in:
commit
61efe9d298
13 changed files with 368 additions and 139 deletions
|
@ -137,10 +137,8 @@ fn get_stack_size() -> Option<usize> {
|
|||
env::var_os("RUST_MIN_STACK").is_none().then_some(STACK_SIZE)
|
||||
}
|
||||
|
||||
#[cfg(not(parallel_compiler))]
|
||||
pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
|
||||
pub(crate) fn run_in_thread_with_globals<F: FnOnce() -> R + Send, R: Send>(
|
||||
edition: Edition,
|
||||
_threads: usize,
|
||||
f: F,
|
||||
) -> R {
|
||||
// The "thread pool" is a single spawned thread in the non-parallel
|
||||
|
@ -171,18 +169,37 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
|
|||
})
|
||||
}
|
||||
|
||||
#[cfg(not(parallel_compiler))]
|
||||
pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
|
||||
edition: Edition,
|
||||
_threads: usize,
|
||||
f: F,
|
||||
) -> R {
|
||||
run_in_thread_with_globals(edition, f)
|
||||
}
|
||||
|
||||
#[cfg(parallel_compiler)]
|
||||
pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
|
||||
edition: Edition,
|
||||
threads: usize,
|
||||
f: F,
|
||||
) -> R {
|
||||
use rustc_data_structures::jobserver;
|
||||
use rustc_data_structures::{jobserver, sync::FromDyn};
|
||||
use rustc_middle::ty::tls;
|
||||
use rustc_query_impl::QueryCtxt;
|
||||
use rustc_query_system::query::{deadlock, QueryContext};
|
||||
|
||||
let registry = sync::Registry::new(threads);
|
||||
|
||||
if !sync::is_dyn_thread_safe() {
|
||||
return run_in_thread_with_globals(edition, || {
|
||||
// Register the thread for use with the `WorkerLocal` type.
|
||||
registry.register();
|
||||
|
||||
f()
|
||||
});
|
||||
}
|
||||
|
||||
let mut builder = rayon::ThreadPoolBuilder::new()
|
||||
.thread_name(|_| "rustc".to_string())
|
||||
.acquire_thread_handler(jobserver::acquire_thread)
|
||||
|
@ -191,13 +208,13 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
|
|||
.deadlock_handler(|| {
|
||||
// On deadlock, creates a new thread and forwards information in thread
|
||||
// locals to it. The new thread runs the deadlock handler.
|
||||
let query_map = tls::with(|tcx| {
|
||||
let query_map = FromDyn::from(tls::with(|tcx| {
|
||||
QueryCtxt::new(tcx)
|
||||
.try_collect_active_jobs()
|
||||
.expect("active jobs shouldn't be locked in deadlock handler")
|
||||
});
|
||||
}));
|
||||
let registry = rayon_core::Registry::current();
|
||||
thread::spawn(move || deadlock(query_map, ®istry));
|
||||
thread::spawn(move || deadlock(query_map.into_inner(), ®istry));
|
||||
});
|
||||
if let Some(size) = get_stack_size() {
|
||||
builder = builder.stack_size(size);
|
||||
|
@ -209,6 +226,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
|
|||
// `Send` in the parallel compiler.
|
||||
rustc_span::create_session_globals_then(edition, || {
|
||||
rustc_span::with_session_globals(|session_globals| {
|
||||
let session_globals = FromDyn::from(session_globals);
|
||||
builder
|
||||
.build_scoped(
|
||||
// Initialize each new worker thread when created.
|
||||
|
@ -216,7 +234,9 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
|
|||
// Register the thread for use with the `WorkerLocal` type.
|
||||
registry.register();
|
||||
|
||||
rustc_span::set_session_globals_then(session_globals, || thread.run())
|
||||
rustc_span::set_session_globals_then(session_globals.into_inner(), || {
|
||||
thread.run()
|
||||
})
|
||||
},
|
||||
// Run `f` on the first thread in the thread pool.
|
||||
move |pool: &rayon::ThreadPool| pool.install(f),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue