Auto merge of #114894 - Zoxc:sharded-cfg-cleanup2, r=cjgillot
Remove conditional use of `Sharded` from query state `Sharded` is already a zero cost abstraction, so it shouldn't affect the performance of the single thread compiler if LLVM does its job. r? `@cjgillot`
This commit is contained in:
commit
6d32b298ed
@ -2,9 +2,12 @@ use crate::fx::{FxHashMap, FxHasher};
|
|||||||
#[cfg(parallel_compiler)]
|
#[cfg(parallel_compiler)]
|
||||||
use crate::sync::{is_dyn_thread_safe, CacheAligned};
|
use crate::sync::{is_dyn_thread_safe, CacheAligned};
|
||||||
use crate::sync::{Lock, LockGuard};
|
use crate::sync::{Lock, LockGuard};
|
||||||
|
#[cfg(parallel_compiler)]
|
||||||
|
use itertools::Either;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::collections::hash_map::RawEntryMut;
|
use std::collections::hash_map::RawEntryMut;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
use std::iter;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
// 32 shards is sufficient to reduce contention on an 8-core Ryzen 7 1700,
|
// 32 shards is sufficient to reduce contention on an 8-core Ryzen 7 1700,
|
||||||
@ -70,19 +73,27 @@ impl<T> Sharded<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lock_shards(&self) -> Vec<LockGuard<'_, T>> {
|
#[inline]
|
||||||
|
pub fn lock_shards(&self) -> impl Iterator<Item = LockGuard<'_, T>> {
|
||||||
match self {
|
match self {
|
||||||
Self::Single(single) => vec![single.lock()],
|
#[cfg(not(parallel_compiler))]
|
||||||
|
Self::Single(single) => iter::once(single.lock()),
|
||||||
#[cfg(parallel_compiler)]
|
#[cfg(parallel_compiler)]
|
||||||
Self::Shards(shards) => shards.iter().map(|shard| shard.0.lock()).collect(),
|
Self::Single(single) => Either::Left(iter::once(single.lock())),
|
||||||
|
#[cfg(parallel_compiler)]
|
||||||
|
Self::Shards(shards) => Either::Right(shards.iter().map(|shard| shard.0.lock())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_lock_shards(&self) -> Option<Vec<LockGuard<'_, T>>> {
|
#[inline]
|
||||||
|
pub fn try_lock_shards(&self) -> impl Iterator<Item = Option<LockGuard<'_, T>>> {
|
||||||
match self {
|
match self {
|
||||||
Self::Single(single) => Some(vec![single.try_lock()?]),
|
#[cfg(not(parallel_compiler))]
|
||||||
|
Self::Single(single) => iter::once(single.try_lock()),
|
||||||
#[cfg(parallel_compiler)]
|
#[cfg(parallel_compiler)]
|
||||||
Self::Shards(shards) => shards.iter().map(|shard| shard.0.try_lock()).collect(),
|
Self::Single(single) => Either::Left(iter::once(single.try_lock())),
|
||||||
|
#[cfg(parallel_compiler)]
|
||||||
|
Self::Shards(shards) => Either::Right(shards.iter().map(|shard| shard.0.try_lock())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -101,7 +112,7 @@ pub type ShardedHashMap<K, V> = Sharded<FxHashMap<K, V>>;
|
|||||||
|
|
||||||
impl<K: Eq, V> ShardedHashMap<K, V> {
|
impl<K: Eq, V> ShardedHashMap<K, V> {
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.lock_shards().iter().map(|shard| shard.len()).sum()
|
self.lock_shards().map(|shard| shard.len()).sum()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1296,25 +1296,26 @@ macro_rules! sty_debug_print {
|
|||||||
};
|
};
|
||||||
$(let mut $variant = total;)*
|
$(let mut $variant = total;)*
|
||||||
|
|
||||||
let shards = tcx.interners.type_.lock_shards();
|
for shard in tcx.interners.type_.lock_shards() {
|
||||||
let types = shards.iter().flat_map(|shard| shard.keys());
|
let types = shard.keys();
|
||||||
for &InternedInSet(t) in types {
|
for &InternedInSet(t) in types {
|
||||||
let variant = match t.internee {
|
let variant = match t.internee {
|
||||||
ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) |
|
ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) |
|
||||||
ty::Float(..) | ty::Str | ty::Never => continue,
|
ty::Float(..) | ty::Str | ty::Never => continue,
|
||||||
ty::Error(_) => /* unimportant */ continue,
|
ty::Error(_) => /* unimportant */ continue,
|
||||||
$(ty::$variant(..) => &mut $variant,)*
|
$(ty::$variant(..) => &mut $variant,)*
|
||||||
};
|
};
|
||||||
let lt = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER);
|
let lt = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER);
|
||||||
let ty = t.flags.intersects(ty::TypeFlags::HAS_TY_INFER);
|
let ty = t.flags.intersects(ty::TypeFlags::HAS_TY_INFER);
|
||||||
let ct = t.flags.intersects(ty::TypeFlags::HAS_CT_INFER);
|
let ct = t.flags.intersects(ty::TypeFlags::HAS_CT_INFER);
|
||||||
|
|
||||||
variant.total += 1;
|
variant.total += 1;
|
||||||
total.total += 1;
|
total.total += 1;
|
||||||
if lt { total.lt_infer += 1; variant.lt_infer += 1 }
|
if lt { total.lt_infer += 1; variant.lt_infer += 1 }
|
||||||
if ty { total.ty_infer += 1; variant.ty_infer += 1 }
|
if ty { total.ty_infer += 1; variant.ty_infer += 1 }
|
||||||
if ct { total.ct_infer += 1; variant.ct_infer += 1 }
|
if ct { total.ct_infer += 1; variant.ct_infer += 1 }
|
||||||
if lt && ty && ct { total.all_infer += 1; variant.all_infer += 1 }
|
if lt && ty && ct { total.all_infer += 1; variant.all_infer += 1 }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
writeln!(fmt, "Ty interner total ty lt ct all")?;
|
writeln!(fmt, "Ty interner total ty lt ct all")?;
|
||||||
$(writeln!(fmt, " {:18}: {uses:6} {usespc:4.1}%, \
|
$(writeln!(fmt, " {:18}: {uses:6} {usespc:4.1}%, \
|
||||||
|
@ -70,8 +70,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) {
|
fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) {
|
||||||
let shards = self.cache.lock_shards();
|
for shard in self.cache.lock_shards() {
|
||||||
for shard in shards.iter() {
|
|
||||||
for (k, v) in shard.iter() {
|
for (k, v) in shard.iter() {
|
||||||
f(k, &v.0, v.1);
|
f(k, &v.0, v.1);
|
||||||
}
|
}
|
||||||
@ -160,8 +159,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) {
|
fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) {
|
||||||
let shards = self.cache.lock_shards();
|
for shard in self.cache.lock_shards() {
|
||||||
for shard in shards.iter() {
|
|
||||||
for (k, v) in shard.iter_enumerated() {
|
for (k, v) in shard.iter_enumerated() {
|
||||||
if let Some(v) = v {
|
if let Some(v) = v {
|
||||||
f(&k, &v.0, v.1);
|
f(&k, &v.0, v.1);
|
||||||
|
@ -12,12 +12,13 @@ use crate::query::job::{report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobI
|
|||||||
use crate::query::SerializedDepNodeIndex;
|
use crate::query::SerializedDepNodeIndex;
|
||||||
use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame};
|
use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame};
|
||||||
use crate::HandleCycleError;
|
use crate::HandleCycleError;
|
||||||
|
#[cfg(parallel_compiler)]
|
||||||
|
use rustc_data_structures::cold_path;
|
||||||
use rustc_data_structures::fingerprint::Fingerprint;
|
use rustc_data_structures::fingerprint::Fingerprint;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
|
use rustc_data_structures::sharded::Sharded;
|
||||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
use rustc_data_structures::sync::Lock;
|
use rustc_data_structures::sync::Lock;
|
||||||
#[cfg(parallel_compiler)]
|
|
||||||
use rustc_data_structures::{cold_path, sharded::Sharded};
|
|
||||||
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, FatalError};
|
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, FatalError};
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
@ -30,10 +31,7 @@ use thin_vec::ThinVec;
|
|||||||
use super::QueryConfig;
|
use super::QueryConfig;
|
||||||
|
|
||||||
pub struct QueryState<K, D: DepKind> {
|
pub struct QueryState<K, D: DepKind> {
|
||||||
#[cfg(parallel_compiler)]
|
|
||||||
active: Sharded<FxHashMap<K, QueryResult<D>>>,
|
active: Sharded<FxHashMap<K, QueryResult<D>>>,
|
||||||
#[cfg(not(parallel_compiler))]
|
|
||||||
active: Lock<FxHashMap<K, QueryResult<D>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Indicates the state of a query for a given key in a query map.
|
/// Indicates the state of a query for a given key in a query map.
|
||||||
@ -52,15 +50,7 @@ where
|
|||||||
D: DepKind,
|
D: DepKind,
|
||||||
{
|
{
|
||||||
pub fn all_inactive(&self) -> bool {
|
pub fn all_inactive(&self) -> bool {
|
||||||
#[cfg(parallel_compiler)]
|
self.active.lock_shards().all(|shard| shard.is_empty())
|
||||||
{
|
|
||||||
let shards = self.active.lock_shards();
|
|
||||||
shards.iter().all(|shard| shard.is_empty())
|
|
||||||
}
|
|
||||||
#[cfg(not(parallel_compiler))]
|
|
||||||
{
|
|
||||||
self.active.lock().is_empty()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_collect_active_jobs<Qcx: Copy>(
|
pub fn try_collect_active_jobs<Qcx: Copy>(
|
||||||
@ -71,26 +61,10 @@ where
|
|||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
let mut active = Vec::new();
|
let mut active = Vec::new();
|
||||||
|
|
||||||
#[cfg(parallel_compiler)]
|
// We use try_lock_shards here since we are called from the
|
||||||
{
|
// deadlock handler, and this shouldn't be locked.
|
||||||
// We use try_lock_shards here since we are called from the
|
for shard in self.active.try_lock_shards() {
|
||||||
// deadlock handler, and this shouldn't be locked.
|
for (k, v) in shard?.iter() {
|
||||||
let shards = self.active.try_lock_shards()?;
|
|
||||||
for shard in shards.iter() {
|
|
||||||
for (k, v) in shard.iter() {
|
|
||||||
if let QueryResult::Started(ref job) = *v {
|
|
||||||
active.push((*k, job.clone()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[cfg(not(parallel_compiler))]
|
|
||||||
{
|
|
||||||
// We use try_lock here since we are called from the
|
|
||||||
// deadlock handler, and this shouldn't be locked.
|
|
||||||
// (FIXME: Is this relevant for non-parallel compilers? It doesn't
|
|
||||||
// really hurt much.)
|
|
||||||
for (k, v) in self.active.try_lock()?.iter() {
|
|
||||||
if let QueryResult::Started(ref job) = *v {
|
if let QueryResult::Started(ref job) = *v {
|
||||||
active.push((*k, job.clone()));
|
active.push((*k, job.clone()));
|
||||||
}
|
}
|
||||||
@ -184,10 +158,7 @@ where
|
|||||||
cache.complete(key, result, dep_node_index);
|
cache.complete(key, result, dep_node_index);
|
||||||
|
|
||||||
let job = {
|
let job = {
|
||||||
#[cfg(parallel_compiler)]
|
|
||||||
let mut lock = state.active.get_shard_by_value(&key).lock();
|
let mut lock = state.active.get_shard_by_value(&key).lock();
|
||||||
#[cfg(not(parallel_compiler))]
|
|
||||||
let mut lock = state.active.lock();
|
|
||||||
match lock.remove(&key).unwrap() {
|
match lock.remove(&key).unwrap() {
|
||||||
QueryResult::Started(job) => job,
|
QueryResult::Started(job) => job,
|
||||||
QueryResult::Poisoned => panic!(),
|
QueryResult::Poisoned => panic!(),
|
||||||
@ -209,10 +180,7 @@ where
|
|||||||
// Poison the query so jobs waiting on it panic.
|
// Poison the query so jobs waiting on it panic.
|
||||||
let state = self.state;
|
let state = self.state;
|
||||||
let job = {
|
let job = {
|
||||||
#[cfg(parallel_compiler)]
|
|
||||||
let mut shard = state.active.get_shard_by_value(&self.key).lock();
|
let mut shard = state.active.get_shard_by_value(&self.key).lock();
|
||||||
#[cfg(not(parallel_compiler))]
|
|
||||||
let mut shard = state.active.lock();
|
|
||||||
let job = match shard.remove(&self.key).unwrap() {
|
let job = match shard.remove(&self.key).unwrap() {
|
||||||
QueryResult::Started(job) => job,
|
QueryResult::Started(job) => job,
|
||||||
QueryResult::Poisoned => panic!(),
|
QueryResult::Poisoned => panic!(),
|
||||||
@ -336,10 +304,7 @@ where
|
|||||||
Qcx: QueryContext,
|
Qcx: QueryContext,
|
||||||
{
|
{
|
||||||
let state = query.query_state(qcx);
|
let state = query.query_state(qcx);
|
||||||
#[cfg(parallel_compiler)]
|
|
||||||
let mut state_lock = state.active.get_shard_by_value(&key).lock();
|
let mut state_lock = state.active.get_shard_by_value(&key).lock();
|
||||||
#[cfg(not(parallel_compiler))]
|
|
||||||
let mut state_lock = state.active.lock();
|
|
||||||
|
|
||||||
// For the parallel compiler we need to check both the query cache and query state structures
|
// For the parallel compiler we need to check both the query cache and query state structures
|
||||||
// while holding the state lock to ensure that 1) the query has not yet completed and 2) the
|
// while holding the state lock to ensure that 1) the query has not yet completed and 2) the
|
||||||
|
Loading…
x
Reference in New Issue
Block a user