Rollup merge of #109758 - nnethercote:parallel-cleanups, r=cjgillot
Parallel compiler cleanups A few small improvements I found while looking closely at this code. r? `@cjgillot` cc `@Zoxc,` `@SparrowLii`
This commit is contained in:
commit
249198c1f8
4 changed files with 45 additions and 36 deletions
|
@ -5,7 +5,7 @@ use std::collections::hash_map::RawEntryMut;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Default)]
|
||||||
#[cfg_attr(parallel_compiler, repr(align(64)))]
|
#[cfg_attr(parallel_compiler, repr(align(64)))]
|
||||||
struct CacheAligned<T>(T);
|
struct CacheAligned<T>(T);
|
||||||
|
|
||||||
|
@ -21,7 +21,6 @@ const SHARD_BITS: usize = 0;
|
||||||
pub const SHARDS: usize = 1 << SHARD_BITS;
|
pub const SHARDS: usize = 1 << SHARD_BITS;
|
||||||
|
|
||||||
/// An array of cache-line aligned inner locked structures with convenience methods.
|
/// An array of cache-line aligned inner locked structures with convenience methods.
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Sharded<T> {
|
pub struct Sharded<T> {
|
||||||
shards: [CacheAligned<Lock<T>>; SHARDS],
|
shards: [CacheAligned<Lock<T>>; SHARDS],
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
//! `rustc_erase_owner!` erases an `OwningRef` owner into `Erased` for the
|
||||||
//! It internally uses `parking_lot::Mutex` if cfg!(parallel_compiler) is true,
|
//! serial version and `Erased + Send + Sync` for the parallel version.
|
||||||
//! `RefCell` otherwise.
|
|
||||||
//!
|
//!
|
||||||
//! `RwLock` is a read-write lock.
|
//! Types
|
||||||
//! It internally uses `parking_lot::RwLock` if cfg!(parallel_compiler) is true,
|
//! -----
|
||||||
//! `RefCell` otherwise.
|
//! 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
|
//! [^1] `MTLock` is similar to `Lock`, but the serial version avoids the cost
|
||||||
//! depending on the value of cfg!(parallel_compiler).
|
//! of a `RefCell`. This is appropriate when interior mutability is not
|
||||||
|
//! required.
|
||||||
|
//!
|
||||||
|
//! [^2] `MTLockRef` is a typedef.
|
||||||
|
|
||||||
use crate::owning_ref::{Erased, OwningRef};
|
use crate::owning_ref::{Erased, OwningRef};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -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)]
|
#[derive(Debug, Default)]
|
||||||
pub struct MTLock<T>(T);
|
pub struct MTLock<T>(T);
|
||||||
|
@ -267,7 +292,7 @@ cfg_if! {
|
||||||
pub use std::sync::Arc as Lrc;
|
pub use std::sync::Arc as Lrc;
|
||||||
pub use std::sync::Weak as Weak;
|
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)]
|
#[derive(Debug, Default)]
|
||||||
pub struct MTLock<T>(Lock<T>);
|
pub struct MTLock<T>(Lock<T>);
|
||||||
|
@ -553,18 +578,6 @@ impl<T> RwLock<T> {
|
||||||
self.write()
|
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))]
|
#[cfg(not(parallel_compiler))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn leak(&self) -> &T {
|
pub fn leak(&self) -> &T {
|
||||||
|
|
|
@ -174,7 +174,7 @@
|
||||||
//! regardless of whether it is actually needed or not.
|
//! regardless of whether it is actually needed or not.
|
||||||
|
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
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 as hir;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
|
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
|
||||||
|
@ -341,8 +341,8 @@ pub fn collect_crate_mono_items(
|
||||||
let recursion_limit = tcx.recursion_limit();
|
let recursion_limit = tcx.recursion_limit();
|
||||||
|
|
||||||
{
|
{
|
||||||
let visited: MTRef<'_, _> = &mut visited;
|
let visited: MTLockRef<'_, _> = &mut visited;
|
||||||
let inlining_map: MTRef<'_, _> = &mut inlining_map;
|
let inlining_map: MTLockRef<'_, _> = &mut inlining_map;
|
||||||
|
|
||||||
tcx.sess.time("monomorphization_collector_graph_walk", || {
|
tcx.sess.time("monomorphization_collector_graph_walk", || {
|
||||||
par_for_each_in(roots, |root| {
|
par_for_each_in(roots, |root| {
|
||||||
|
@ -407,10 +407,10 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec<MonoItem<
|
||||||
fn collect_items_rec<'tcx>(
|
fn collect_items_rec<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
starting_point: Spanned<MonoItem<'tcx>>,
|
starting_point: Spanned<MonoItem<'tcx>>,
|
||||||
visited: MTRef<'_, MTLock<FxHashSet<MonoItem<'tcx>>>>,
|
visited: MTLockRef<'_, FxHashSet<MonoItem<'tcx>>>,
|
||||||
recursion_depths: &mut DefIdMap<usize>,
|
recursion_depths: &mut DefIdMap<usize>,
|
||||||
recursion_limit: Limit,
|
recursion_limit: Limit,
|
||||||
inlining_map: MTRef<'_, MTLock<InliningMap<'tcx>>>,
|
inlining_map: MTLockRef<'_, InliningMap<'tcx>>,
|
||||||
) {
|
) {
|
||||||
if !visited.lock_mut().insert(starting_point.node) {
|
if !visited.lock_mut().insert(starting_point.node) {
|
||||||
// We've been here already, no need to search again.
|
// We've been here already, no need to search again.
|
||||||
|
|
|
@ -21,9 +21,6 @@ pub trait QueryCache: Sized {
|
||||||
type Value: Copy + Debug;
|
type Value: Copy + Debug;
|
||||||
|
|
||||||
/// Checks if the query is already computed and in the cache.
|
/// 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 lookup(&self, key: &Self::Key) -> Option<(Self::Value, DepNodeIndex)>;
|
||||||
|
|
||||||
fn complete(&self, key: Self::Key, value: Self::Value, index: DepNodeIndex);
|
fn complete(&self, key: Self::Key, value: Self::Value, index: DepNodeIndex);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue