Skip to content

Parallel compiler cleanups #109758

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

Merged
merged 4 commits into from
Mar 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions compiler/rustc_data_structures/src/sharded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::collections::hash_map::RawEntryMut;
use std::hash::{Hash, Hasher};
use std::mem;

#[derive(Clone, Default)]
#[derive(Default)]
#[cfg_attr(parallel_compiler, repr(align(64)))]
struct CacheAligned<T>(T);

Expand All @@ -21,7 +21,6 @@ const SHARD_BITS: usize = 0;
pub const SHARDS: usize = 1 << SHARD_BITS;

/// An array of cache-line aligned inner locked structures with convenience methods.
#[derive(Clone)]
pub struct Sharded<T> {
shards: [CacheAligned<Lock<T>>; SHARDS],
}
Expand Down
65 changes: 39 additions & 26 deletions compiler/rustc_data_structures/src/sync.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,46 @@
//! This module defines types which are thread safe if cfg!(parallel_compiler) is true.
//! This module defines various operations and types that are implemented in
//! one way for the serial compiler, and another way the parallel compiler.
//!
//! `Lrc` is an alias of `Arc` if cfg!(parallel_compiler) is true, `Rc` otherwise.
//! Operations
//! ----------
//! The parallel versions of operations use Rayon to execute code in parallel,
//! while the serial versions degenerate straightforwardly to serial execution.
//! The operations include `join`, `parallel`, `par_iter`, and `par_for_each`.
//!
//! `Lock` is a mutex.
//! It internally uses `parking_lot::Mutex` if cfg!(parallel_compiler) is true,
//! `RefCell` otherwise.
//! `rustc_erase_owner!` erases an `OwningRef` owner into `Erased` for the
//! serial version and `Erased + Send + Sync` for the parallel version.
//!
//! `RwLock` is a read-write lock.
//! It internally uses `parking_lot::RwLock` if cfg!(parallel_compiler) is true,
//! `RefCell` otherwise.
//! Types
//! -----
//! The parallel versions of types provide various kinds of synchronization,
//! while the serial compiler versions do not.
//!
//! `MTLock` is a mutex which disappears if cfg!(parallel_compiler) is false.
//! The following table shows how the types are implemented internally. Except
//! where noted otherwise, the type in column one is defined as a
//! newtype around the type from column two or three.
//!
//! `MTRef` is an immutable reference if cfg!(parallel_compiler), and a mutable reference otherwise.
//! | Type | Serial version | Parallel version |
//! | ----------------------- | ------------------- | ------------------------------- |
//! | `Lrc<T>` | `rc::Rc<T>` | `sync::Arc<T>` |
//! |` Weak<T>` | `rc::Weak<T>` | `sync::Weak<T>` |
//! | | | |
//! | `AtomicBool` | `Cell<bool>` | `atomic::AtomicBool` |
//! | `AtomicU32` | `Cell<u32>` | `atomic::AtomicU32` |
//! | `AtomicU64` | `Cell<u64>` | `atomic::AtomicU64` |
//! | `AtomicUsize` | `Cell<usize>` | `atomic::AtomicUsize` |
//! | | | |
//! | `Lock<T>` | `RefCell<T>` | `parking_lot::Mutex<T>` |
//! | `RwLock<T>` | `RefCell<T>` | `parking_lot::RwLock<T>` |
//! | `MTLock<T>` [^1] | `T` | `Lock<T>` |
//! | `MTLockRef<'a, T>` [^2] | `&'a mut MTLock<T>` | `&'a MTLock<T>` |
//! | | | |
//! | `ParallelIterator` | `Iterator` | `rayon::iter::ParallelIterator` |
//!
//! `rustc_erase_owner!` erases an OwningRef owner into Erased or Erased + Send + Sync
//! depending on the value of cfg!(parallel_compiler).
//! [^1] `MTLock` is similar to `Lock`, but the serial version avoids the cost
//! of a `RefCell`. This is appropriate when interior mutability is not
//! required.
//!
//! [^2] `MTLockRef` is a typedef.

use crate::owning_ref::{Erased, OwningRef};
use std::collections::HashMap;
Expand Down Expand Up @@ -209,7 +234,7 @@ cfg_if! {
}
}

pub type MTRef<'a, T> = &'a mut T;
pub type MTLockRef<'a, T> = &'a mut MTLock<T>;

#[derive(Debug, Default)]
pub struct MTLock<T>(T);
Expand Down Expand Up @@ -267,7 +292,7 @@ cfg_if! {
pub use std::sync::Arc as Lrc;
pub use std::sync::Weak as Weak;

pub type MTRef<'a, T> = &'a T;
pub type MTLockRef<'a, T> = &'a MTLock<T>;

#[derive(Debug, Default)]
pub struct MTLock<T>(Lock<T>);
Expand Down Expand Up @@ -553,18 +578,6 @@ impl<T> RwLock<T> {
self.write()
}

#[cfg(not(parallel_compiler))]
#[inline(always)]
pub fn clone_guard<'a>(rg: &ReadGuard<'a, T>) -> ReadGuard<'a, T> {
ReadGuard::clone(rg)
}

#[cfg(parallel_compiler)]
#[inline(always)]
pub fn clone_guard<'a>(rg: &ReadGuard<'a, T>) -> ReadGuard<'a, T> {
ReadGuard::rwlock(&rg).read()
}

#[cfg(not(parallel_compiler))]
#[inline(always)]
pub fn leak(&self) -> &T {
Expand Down
10 changes: 5 additions & 5 deletions compiler/rustc_monomorphize/src/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@
//! regardless of whether it is actually needed or not.

use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::{par_for_each_in, MTLock, MTRef};
use rustc_data_structures::sync::{par_for_each_in, MTLock, MTLockRef};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
Expand Down Expand Up @@ -340,8 +340,8 @@ pub fn collect_crate_mono_items(
let recursion_limit = tcx.recursion_limit();

{
let visited: MTRef<'_, _> = &mut visited;
let inlining_map: MTRef<'_, _> = &mut inlining_map;
let visited: MTLockRef<'_, _> = &mut visited;
let inlining_map: MTLockRef<'_, _> = &mut inlining_map;

tcx.sess.time("monomorphization_collector_graph_walk", || {
par_for_each_in(roots, |root| {
Expand Down Expand Up @@ -406,10 +406,10 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec<MonoItem<
fn collect_items_rec<'tcx>(
tcx: TyCtxt<'tcx>,
starting_point: Spanned<MonoItem<'tcx>>,
visited: MTRef<'_, MTLock<FxHashSet<MonoItem<'tcx>>>>,
visited: MTLockRef<'_, FxHashSet<MonoItem<'tcx>>>,
recursion_depths: &mut DefIdMap<usize>,
recursion_limit: Limit,
inlining_map: MTRef<'_, MTLock<InliningMap<'tcx>>>,
inlining_map: MTLockRef<'_, InliningMap<'tcx>>,
) {
if !visited.lock_mut().insert(starting_point.node) {
// We've been here already, no need to search again.
Expand Down
3 changes: 0 additions & 3 deletions compiler/rustc_query_system/src/query/caches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ pub trait QueryCache: Sized {
type Value: Copy + Debug;

/// Checks if the query is already computed and in the cache.
/// It returns the shard index and a lock guard to the shard,
/// which will be used if the query is not in the cache and we need
/// to compute it.
fn lookup(&self, key: &Self::Key) -> Option<(Self::Value, DepNodeIndex)>;

fn complete(&self, key: Self::Key, value: Self::Value, index: DepNodeIndex);
Expand Down