Skip to content

Commit 89604aa

Browse files
committed
Run linking and incremental saving / finalizing in parallel
1 parent ae9173d commit 89604aa

File tree

16 files changed

+316
-75
lines changed

16 files changed

+316
-75
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -3545,6 +3545,7 @@ dependencies = [
35453545
"portable-atomic",
35463546
"rustc-hash 2.1.1",
35473547
"rustc-rayon",
3548+
"rustc-rayon-core",
35483549
"rustc-stable-hash",
35493550
"rustc_arena",
35503551
"rustc_graphviz",

compiler/rustc_codegen_cranelift/src/lib.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
// Note: please avoid adding other feature gates where possible
88
#![feature(rustc_private)]
99
// Note: please avoid adding other feature gates where possible
10+
#![recursion_limit = "256"]
1011
#![warn(rust_2018_idioms)]
1112
#![warn(unreachable_pub)]
1213
#![warn(unused_lifetimes)]
@@ -43,6 +44,7 @@ use cranelift_codegen::isa::TargetIsa;
4344
use cranelift_codegen::settings::{self, Configurable};
4445
use rustc_codegen_ssa::CodegenResults;
4546
use rustc_codegen_ssa::traits::CodegenBackend;
47+
use rustc_data_structures::sync::{DynSend, downcast_box_any_dyn_send};
4648
use rustc_metadata::EncodedMetadata;
4749
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
4850
use rustc_session::Session;
@@ -207,7 +209,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
207209
tcx: TyCtxt<'_>,
208210
metadata: EncodedMetadata,
209211
need_metadata_module: bool,
210-
) -> Box<dyn Any> {
212+
) -> Box<dyn Any + DynSend> {
211213
info!("codegen crate {}", tcx.crate_name(LOCAL_CRATE));
212214
let config = self.config.clone().unwrap_or_else(|| {
213215
BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args)
@@ -226,11 +228,13 @@ impl CodegenBackend for CraneliftCodegenBackend {
226228

227229
fn join_codegen(
228230
&self,
229-
ongoing_codegen: Box<dyn Any>,
231+
ongoing_codegen: Box<dyn Any + DynSend>,
230232
sess: &Session,
231233
outputs: &OutputFilenames,
232234
) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
233-
ongoing_codegen.downcast::<driver::aot::OngoingCodegen>().unwrap().join(sess, outputs)
235+
downcast_box_any_dyn_send::<driver::aot::OngoingCodegen>(ongoing_codegen)
236+
.unwrap()
237+
.join(sess, outputs)
234238
}
235239
}
236240

compiler/rustc_codegen_gcc/src/lib.rs

+6-7
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ use rustc_codegen_ssa::base::codegen_crate;
104104
use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, WriteBackendMethods};
105105
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
106106
use rustc_data_structures::fx::FxIndexMap;
107-
use rustc_data_structures::sync::IntoDynSyncSend;
107+
use rustc_data_structures::sync::{DynSend, IntoDynSyncSend, downcast_box_any_dyn_send};
108108
use rustc_errors::DiagCtxtHandle;
109109
use rustc_metadata::EncodedMetadata;
110110
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
@@ -230,12 +230,12 @@ impl CodegenBackend for GccCodegenBackend {
230230
providers.global_backend_features = |tcx, ()| gcc_util::global_gcc_features(tcx.sess, true)
231231
}
232232

233-
fn codegen_crate(
233+
fn codegen_crate<'tcx>(
234234
&self,
235-
tcx: TyCtxt<'_>,
235+
tcx: TyCtxt<'tcx>,
236236
metadata: EncodedMetadata,
237237
need_metadata_module: bool,
238-
) -> Box<dyn Any> {
238+
) -> Box<dyn Any + DynSend> {
239239
let target_cpu = target_cpu(tcx.sess);
240240
let res = codegen_crate(
241241
self.clone(),
@@ -250,12 +250,11 @@ impl CodegenBackend for GccCodegenBackend {
250250

251251
fn join_codegen(
252252
&self,
253-
ongoing_codegen: Box<dyn Any>,
253+
ongoing_codegen: Box<dyn Any + DynSend>,
254254
sess: &Session,
255255
_outputs: &OutputFilenames,
256256
) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
257-
ongoing_codegen
258-
.downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<GccCodegenBackend>>()
257+
downcast_box_any_dyn_send::<rustc_codegen_ssa::back::write::OngoingCodegen<GccCodegenBackend>>( ongoing_codegen)
259258
.expect("Expected GccCodegenBackend's OngoingCodegen, found Box<Any>")
260259
.join(sess)
261260
}

compiler/rustc_codegen_llvm/src/lib.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#![feature(rustdoc_internals)]
2020
#![feature(slice_as_array)]
2121
#![feature(try_blocks)]
22+
#![recursion_limit = "256"]
2223
// tidy-alphabetical-end
2324

2425
use std::any::Any;
@@ -39,6 +40,7 @@ use rustc_codegen_ssa::back::write::{
3940
use rustc_codegen_ssa::traits::*;
4041
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
4142
use rustc_data_structures::fx::FxIndexMap;
43+
use rustc_data_structures::sync::{DynSend, downcast_box_any_dyn_send};
4244
use rustc_errors::{DiagCtxtHandle, FatalError};
4345
use rustc_metadata::EncodedMetadata;
4446
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
@@ -347,7 +349,7 @@ impl CodegenBackend for LlvmCodegenBackend {
347349
tcx: TyCtxt<'tcx>,
348350
metadata: EncodedMetadata,
349351
need_metadata_module: bool,
350-
) -> Box<dyn Any> {
352+
) -> Box<dyn Any + DynSend> {
351353
Box::new(rustc_codegen_ssa::base::codegen_crate(
352354
LlvmCodegenBackend(()),
353355
tcx,
@@ -359,14 +361,15 @@ impl CodegenBackend for LlvmCodegenBackend {
359361

360362
fn join_codegen(
361363
&self,
362-
ongoing_codegen: Box<dyn Any>,
364+
ongoing_codegen: Box<dyn Any + DynSend>,
363365
sess: &Session,
364366
outputs: &OutputFilenames,
365367
) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
366-
let (codegen_results, work_products) = ongoing_codegen
367-
.downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<LlvmCodegenBackend>>()
368-
.expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")
369-
.join(sess);
368+
let (codegen_results, work_products) = downcast_box_any_dyn_send::<
369+
rustc_codegen_ssa::back::write::OngoingCodegen<LlvmCodegenBackend>,
370+
>(ongoing_codegen)
371+
.expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<dyn Any + DynSend>")
372+
.join(sess);
370373

371374
if sess.opts.unstable_opts.llvm_time_trace {
372375
sess.time("llvm_dump_timing_file", || {

compiler/rustc_codegen_ssa/src/traits/backend.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub trait BackendTypes {
3636
type DIVariable: Copy;
3737
}
3838

39-
pub trait CodegenBackend {
39+
pub trait CodegenBackend: DynSync + DynSend {
4040
/// Locale resources for diagnostic messages - a string the content of the Fluent resource.
4141
/// Called before `init` so that all other functions are able to emit translatable diagnostics.
4242
fn locale_resource(&self) -> &'static str;
@@ -73,16 +73,16 @@ pub trait CodegenBackend {
7373
tcx: TyCtxt<'tcx>,
7474
metadata: EncodedMetadata,
7575
need_metadata_module: bool,
76-
) -> Box<dyn Any>;
76+
) -> Box<dyn Any + DynSend>;
7777

78-
/// This is called on the returned `Box<dyn Any>` from [`codegen_crate`](Self::codegen_crate)
78+
/// This is called on the returned `Box<dyn Any + DynSend>` from [`codegen_crate`](Self::codegen_crate)
7979
///
8080
/// # Panics
8181
///
82-
/// Panics when the passed `Box<dyn Any>` was not returned by [`codegen_crate`](Self::codegen_crate).
82+
/// Panics when the passed `Box<dyn Any + DynSend>` was not returned by [`codegen_crate`](Self::codegen_crate).
8383
fn join_codegen(
8484
&self,
85-
ongoing_codegen: Box<dyn Any>,
85+
ongoing_codegen: Box<dyn Any + DynSend>,
8686
sess: &Session,
8787
outputs: &OutputFilenames,
8888
) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>);

compiler/rustc_data_structures/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ jobserver_crate = { version = "0.1.28", package = "jobserver" }
1515
measureme = "12.0.1"
1616
rustc-hash = "2.0.0"
1717
rustc-rayon = { version = "0.5.1", features = ["indexmap"] }
18+
rustc-rayon-core = { version = "0.5.0" }
1819
rustc-stable-hash = { version = "0.1.0", features = ["nightly"] }
1920
rustc_arena = { path = "../rustc_arena" }
2021
rustc_graphviz = { path = "../rustc_graphviz" }

compiler/rustc_data_structures/src/marker.rs

+37-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::alloc::Allocator;
2+
use std::any::Any;
23

34
#[rustc_on_unimplemented(message = "`{Self}` doesn't implement `DynSend`. \
45
Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Send`")]
@@ -51,9 +52,20 @@ macro_rules! already_send {
5152

5253
// These structures are already `Send`.
5354
already_send!(
54-
[std::backtrace::Backtrace][std::io::Stdout][std::io::Stderr][std::io::Error][std::fs::File]
55-
[rustc_arena::DroplessArena][crate::memmap::Mmap][crate::profiling::SelfProfiler]
56-
[crate::owned_slice::OwnedSlice]
55+
[std::backtrace::Backtrace]
56+
[std::io::Stdout]
57+
[std::io::Stderr]
58+
[std::io::Error]
59+
[std::fs::File]
60+
[std::sync::Condvar]
61+
[jobserver_crate::Client]
62+
[jobserver_crate::HelperThread]
63+
[jobserver_crate::Acquired]
64+
[Box<dyn Any + Send>]
65+
[rustc_arena::DroplessArena]
66+
[crate::memmap::Mmap]
67+
[crate::profiling::SelfProfiler]
68+
[crate::owned_slice::OwnedSlice]
5769
);
5870

5971
macro_rules! impl_dyn_send {
@@ -64,10 +76,14 @@ macro_rules! impl_dyn_send {
6476

6577
impl_dyn_send!(
6678
[std::sync::atomic::AtomicPtr<T> where T]
67-
[std::sync::Mutex<T> where T: ?Sized+ DynSend]
79+
[std::sync::Mutex<T> where T: ?Sized + DynSend]
80+
[std::sync::RwLock<T> where T: ?Sized + DynSend]
6881
[std::sync::mpsc::Sender<T> where T: DynSend]
82+
[std::sync::mpsc::Receiver<T> where T: DynSend]
6983
[std::sync::Arc<T> where T: ?Sized + DynSync + DynSend]
84+
[std::sync::OnceLock<T> where T: DynSend]
7085
[std::sync::LazyLock<T, F> where T: DynSend, F: DynSend]
86+
[std::thread::JoinHandle<T> where T]
7187
[std::collections::HashSet<K, S> where K: DynSend, S: DynSend]
7288
[std::collections::HashMap<K, V, S> where K: DynSend, V: DynSend, S: DynSend]
7389
[std::collections::BTreeMap<K, V, A> where K: DynSend, V: DynSend, A: std::alloc::Allocator + Clone + DynSend]
@@ -119,9 +135,9 @@ macro_rules! already_sync {
119135
// These structures are already `Sync`.
120136
already_sync!(
121137
[std::sync::atomic::AtomicBool][std::sync::atomic::AtomicUsize][std::sync::atomic::AtomicU8]
122-
[std::sync::atomic::AtomicU32][std::backtrace::Backtrace][std::io::Error][std::fs::File]
123-
[jobserver_crate::Client][crate::memmap::Mmap][crate::profiling::SelfProfiler]
124-
[crate::owned_slice::OwnedSlice]
138+
[std::sync::atomic::AtomicU32][std::backtrace::Backtrace][std::sync::Condvar]
139+
[std::io::Error][std::fs::File][jobserver_crate::Client][crate::memmap::Mmap]
140+
[crate::profiling::SelfProfiler][crate::owned_slice::OwnedSlice]
125141
);
126142

127143
// Use portable AtomicU64 for targets without native 64-bit atomics
@@ -142,7 +158,9 @@ impl_dyn_sync!(
142158
[std::sync::OnceLock<T> where T: DynSend + DynSync]
143159
[std::sync::Mutex<T> where T: ?Sized + DynSend]
144160
[std::sync::Arc<T> where T: ?Sized + DynSync + DynSend]
161+
[std::sync::RwLock<T> where T: ?Sized + DynSend + DynSync]
145162
[std::sync::LazyLock<T, F> where T: DynSend + DynSync, F: DynSend]
163+
[std::sync::mpsc::SyncSender<T> where T: DynSend]
146164
[std::collections::HashSet<K, S> where K: DynSync, S: DynSync]
147165
[std::collections::HashMap<K, V, S> where K: DynSync, V: DynSync, S: DynSync]
148166
[std::collections::BTreeMap<K, V, A> where K: DynSync, V: DynSync, A: std::alloc::Allocator + Clone + DynSync]
@@ -224,3 +242,15 @@ impl<T> std::ops::DerefMut for IntoDynSyncSend<T> {
224242
&mut self.0
225243
}
226244
}
245+
246+
#[inline]
247+
pub fn downcast_box_any_dyn_send<T: Any>(this: Box<dyn Any + DynSend>) -> Result<Box<T>, ()> {
248+
if <dyn Any>::is::<T>(&*this) {
249+
unsafe {
250+
let (raw, alloc): (*mut (dyn Any + DynSend), _) = Box::into_raw_with_allocator(this);
251+
Ok(Box::from_raw_in(raw as *mut T, alloc))
252+
}
253+
} else {
254+
Err(())
255+
}
256+
}

compiler/rustc_data_structures/src/sync.rs

+4
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ pub use self::worker_local::{Registry, WorkerLocal};
5050
pub use crate::marker::*;
5151

5252
mod freeze;
53+
54+
mod task;
55+
pub use task::{Task, task};
56+
5357
mod lock;
5458
mod parallel;
5559
mod vec;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
use std::any::Any;
2+
use std::mem;
3+
use std::panic::{self, AssertUnwindSafe};
4+
use std::sync::Arc;
5+
6+
use parking_lot::{Condvar, Mutex};
7+
8+
use crate::jobserver;
9+
use crate::sync::{DynSend, FromDyn, IntoDynSyncSend, mode};
10+
11+
enum TaskState<T: DynSend + 'static> {
12+
Unexecuted(Box<dyn FnOnce() -> T + DynSend>),
13+
Running,
14+
Joined,
15+
Result(Result<T, IntoDynSyncSend<Box<dyn Any + Send + 'static>>>),
16+
}
17+
18+
struct TaskData<T: DynSend + 'static> {
19+
state: Mutex<TaskState<T>>,
20+
waiter: Condvar,
21+
}
22+
23+
#[must_use]
24+
pub struct Task<T: DynSend + 'static> {
25+
data: Arc<TaskData<T>>,
26+
}
27+
28+
/// This attempts to run a closure in a background thread. It returns a `Task` type which
29+
/// you must call `join` on to ensure that the closure runs.
30+
pub fn task<T: DynSend>(f: impl FnOnce() -> T + DynSend + 'static) -> Task<T> {
31+
let task = Task {
32+
data: Arc::new(TaskData {
33+
state: Mutex::new(TaskState::Unexecuted(Box::new(f))),
34+
waiter: Condvar::new(),
35+
}),
36+
};
37+
38+
if mode::is_dyn_thread_safe() {
39+
let data = FromDyn::from(Arc::clone(&task.data));
40+
41+
// Try to execute the task on a separate thread.
42+
rayon::spawn(move || {
43+
let data = data.into_inner();
44+
let mut state = data.state.lock();
45+
if matches!(*state, TaskState::Unexecuted(..)) {
46+
if let TaskState::Unexecuted(f) = mem::replace(&mut *state, TaskState::Running) {
47+
drop(state);
48+
let result = panic::catch_unwind(AssertUnwindSafe(f));
49+
50+
let unblock = {
51+
let mut state = data.state.lock();
52+
let unblock = matches!(*state, TaskState::Joined);
53+
*state = TaskState::Result(result.map_err(|e| IntoDynSyncSend(e)));
54+
unblock
55+
};
56+
57+
if unblock {
58+
rayon_core::mark_unblocked(&rayon_core::Registry::current());
59+
}
60+
61+
data.waiter.notify_one();
62+
}
63+
}
64+
});
65+
}
66+
67+
task
68+
}
69+
70+
#[inline]
71+
fn unwind<T>(result: Result<T, IntoDynSyncSend<Box<dyn Any + Send + 'static>>>) -> T {
72+
match result {
73+
Ok(r) => r,
74+
Err(err) => panic::resume_unwind(err.0),
75+
}
76+
}
77+
78+
impl<T: DynSend> Task<T> {
79+
pub fn join(self) -> T {
80+
let mut state_guard = self.data.state.lock();
81+
82+
match mem::replace(&mut *state_guard, TaskState::Joined) {
83+
TaskState::Unexecuted(f) => f(),
84+
TaskState::Result(result) => unwind(result),
85+
TaskState::Running => {
86+
rayon_core::mark_blocked();
87+
jobserver::release_thread();
88+
89+
self.data.waiter.wait(&mut state_guard);
90+
91+
jobserver::acquire_thread();
92+
93+
match mem::replace(&mut *state_guard, TaskState::Joined) {
94+
TaskState::Result(result) => unwind(result),
95+
_ => panic!(),
96+
}
97+
}
98+
TaskState::Joined => panic!(),
99+
}
100+
}
101+
}

compiler/rustc_driver_impl/src/lib.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -380,13 +380,14 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
380380
}
381381
}
382382

383-
Some(Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend))
383+
Some(Linker::codegen_and_build_linker(tcx, compiler))
384384
});
385385

386386
// Linking is done outside the `compiler.enter()` so that the
387387
// `GlobalCtxt` within `Queries` can be freed as early as possible.
388388
if let Some(linker) = linker {
389-
linker.link(sess, codegen_backend);
389+
let _timer = sess.timer("waiting for linking");
390+
linker.join();
390391
}
391392
})
392393
}

0 commit comments

Comments
 (0)