Skip to content

Commit

Permalink
Auto merge of #56614 - Zoxc:query-perf2, r=michaelwoerister
Browse files Browse the repository at this point in the history
Replace LockCell with atomic types

Split from #56509

r? @michaelwoerister
  • Loading branch information
bors committed Jan 9, 2019
2 parents 8c97b6f + 9b47acf commit 664c779
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 178 deletions.
47 changes: 28 additions & 19 deletions src/librustc/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ use util::common::{duration_to_secs_str, ErrorReported};
use util::common::ProfileQueriesMsg;

use rustc_data_structures::base_n;
use rustc_data_structures::sync::{self, Lrc, Lock, LockCell, OneThread, Once, RwLock};
use rustc_data_structures::sync::{
self, Lrc, Lock, OneThread, Once, RwLock, AtomicU64, AtomicUsize, Ordering,
Ordering::SeqCst,
};

use errors::{self, DiagnosticBuilder, DiagnosticId, Applicability};
use errors::emitter::{Emitter, EmitterWriter};
Expand All @@ -41,13 +44,19 @@ use std::io::Write;
use std::path::PathBuf;
use std::time::Duration;
use std::sync::mpsc;
use std::sync::atomic::{AtomicUsize, Ordering};

mod code_stats;
pub mod config;
pub mod filesearch;
pub mod search_paths;

pub struct OptimizationFuel {
/// If -zfuel=crate=n is specified, initially set to n. Otherwise 0.
remaining: u64,
/// We're rejecting all further optimizations.
out_of_fuel: bool,
}

/// Represents the data associated with a compilation
/// session for a single crate.
pub struct Session {
Expand Down Expand Up @@ -137,16 +146,15 @@ pub struct Session {

/// If -zfuel=crate=n is specified, Some(crate).
optimization_fuel_crate: Option<String>,
/// If -zfuel=crate=n is specified, initially set to n. Otherwise 0.
optimization_fuel_limit: LockCell<u64>,
/// We're rejecting all further optimizations.
out_of_fuel: LockCell<bool>,

/// Tracks fuel info if If -zfuel=crate=n is specified
optimization_fuel: Lock<OptimizationFuel>,

// The next two are public because the driver needs to read them.
/// If -zprint-fuel=crate, Some(crate).
pub print_fuel_crate: Option<String>,
/// Always set to zero and incremented so that we can print fuel expended by a crate.
pub print_fuel: LockCell<u64>,
pub print_fuel: AtomicU64,

/// Loaded up early on in the initialization of this `Session` to avoid
/// false positives about a job server in our environment.
Expand Down Expand Up @@ -871,20 +879,20 @@ impl Session {
if let Some(ref c) = self.optimization_fuel_crate {
if c == crate_name {
assert_eq!(self.query_threads(), 1);
let fuel = self.optimization_fuel_limit.get();
ret = fuel != 0;
if fuel == 0 && !self.out_of_fuel.get() {
let mut fuel = self.optimization_fuel.lock();
ret = fuel.remaining != 0;
if fuel.remaining == 0 && !fuel.out_of_fuel {
eprintln!("optimization-fuel-exhausted: {}", msg());
self.out_of_fuel.set(true);
} else if fuel > 0 {
self.optimization_fuel_limit.set(fuel - 1);
fuel.out_of_fuel = true;
} else if fuel.remaining > 0 {
fuel.remaining -= 1;
}
}
}
if let Some(ref c) = self.print_fuel_crate {
if c == crate_name {
assert_eq!(self.query_threads(), 1);
self.print_fuel.set(self.print_fuel.get() + 1);
self.print_fuel.fetch_add(1, SeqCst);
}
}
ret
Expand Down Expand Up @@ -1134,10 +1142,12 @@ pub fn build_session_(
local_crate_source_file.map(|path| file_path_mapping.map_prefix(path).0);

let optimization_fuel_crate = sopts.debugging_opts.fuel.as_ref().map(|i| i.0.clone());
let optimization_fuel_limit =
LockCell::new(sopts.debugging_opts.fuel.as_ref().map(|i| i.1).unwrap_or(0));
let optimization_fuel = Lock::new(OptimizationFuel {
remaining: sopts.debugging_opts.fuel.as_ref().map(|i| i.1).unwrap_or(0),
out_of_fuel: false,
});
let print_fuel_crate = sopts.debugging_opts.print_fuel.clone();
let print_fuel = LockCell::new(0);
let print_fuel = AtomicU64::new(0);

let working_dir = env::current_dir().unwrap_or_else(|e|
p_s.span_diagnostic
Expand Down Expand Up @@ -1199,10 +1209,9 @@ pub fn build_session_(
},
code_stats: Default::default(),
optimization_fuel_crate,
optimization_fuel_limit,
optimization_fuel,
print_fuel_crate,
print_fuel,
out_of_fuel: LockCell::new(false),
// Note that this is unsafe because it may misinterpret file descriptors
// on Unix as jobserver file descriptors. We hopefully execute this near
// the beginning of the process though to ensure we don't get false
Expand Down
1 change: 1 addition & 0 deletions src/librustc_data_structures/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#![feature(hash_raw_entry)]
#![feature(stmt_expr_attributes)]
#![feature(core_intrinsics)]
#![feature(integer_atomics)]

#![cfg_attr(unix, feature(libc))]
#![cfg_attr(test, feature(test))]
Expand Down
210 changes: 61 additions & 149 deletions src/librustc_data_structures/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@
//! It internally uses `parking_lot::RwLock` if cfg!(parallel_queries) is true,
//! `RefCell` otherwise.
//!
//! `LockCell` is a thread safe version of `Cell`, with `set` and `get` operations.
//! It can never deadlock. It uses `Cell` when
//! cfg!(parallel_queries) is false, otherwise it is a `Lock`.
//!
//! `MTLock` is a mutex which disappears if cfg!(parallel_queries) is false.
//!
//! `MTRef` is a immutable reference if cfg!(parallel_queries), and an mutable reference otherwise.
Expand All @@ -23,11 +19,7 @@

use std::collections::HashMap;
use std::hash::{Hash, BuildHasher};
use std::cmp::Ordering;
use std::marker::PhantomData;
use std::fmt::Debug;
use std::fmt::Formatter;
use std::fmt;
use std::ops::{Deref, DerefMut};
use owning_ref::{Erased, OwningRef};

Expand All @@ -54,6 +46,9 @@ pub fn serial_scope<F, R>(f: F) -> R
f(&SerialScope)
}

pub use std::sync::atomic::Ordering::SeqCst;
pub use std::sync::atomic::Ordering;

cfg_if! {
if #[cfg(not(parallel_queries))] {
pub auto trait Send {}
Expand All @@ -69,6 +64,62 @@ cfg_if! {
}
}

use std::ops::Add;

#[derive(Debug)]
pub struct Atomic<T: Copy>(Cell<T>);

impl<T: Copy> Atomic<T> {
pub fn new(v: T) -> Self {
Atomic(Cell::new(v))
}
}

impl<T: Copy + PartialEq> Atomic<T> {
pub fn into_inner(self) -> T {
self.0.into_inner()
}

pub fn load(&self, _: Ordering) -> T {
self.0.get()
}

pub fn store(&self, val: T, _: Ordering) {
self.0.set(val)
}

pub fn swap(&self, val: T, _: Ordering) -> T {
self.0.replace(val)
}

pub fn compare_exchange(&self,
current: T,
new: T,
_: Ordering,
_: Ordering)
-> Result<T, T> {
let read = self.0.get();
if read == current {
self.0.set(new);
Ok(read)
} else {
Err(read)
}
}
}

impl<T: Add<Output=T> + Copy> Atomic<T> {
pub fn fetch_add(&self, val: T, _: Ordering) -> T {
let old = self.0.get();
self.0.set(old + val);
old
}
}

pub type AtomicUsize = Atomic<usize>;
pub type AtomicBool = Atomic<bool>;
pub type AtomicU64 = Atomic<u64>;

pub use self::serial_join as join;
pub use self::serial_scope as scope;

Expand Down Expand Up @@ -160,47 +211,6 @@ cfg_if! {
MTLock(self.0.clone())
}
}

pub struct LockCell<T>(Cell<T>);

impl<T> LockCell<T> {
#[inline(always)]
pub fn new(inner: T) -> Self {
LockCell(Cell::new(inner))
}

#[inline(always)]
pub fn into_inner(self) -> T {
self.0.into_inner()
}

#[inline(always)]
pub fn set(&self, new_inner: T) {
self.0.set(new_inner);
}

#[inline(always)]
pub fn get(&self) -> T where T: Copy {
self.0.get()
}

#[inline(always)]
pub fn set_mut(&mut self, new_inner: T) {
self.0.set(new_inner);
}

#[inline(always)]
pub fn get_mut(&mut self) -> T where T: Copy {
self.0.get()
}
}

impl<T> LockCell<Option<T>> {
#[inline(always)]
pub fn take(&self) -> Option<T> {
unsafe { (*self.0.as_ptr()).take() }
}
}
} else {
pub use std::marker::Send as Send;
pub use std::marker::Sync as Sync;
Expand All @@ -213,6 +223,8 @@ cfg_if! {
pub use parking_lot::MutexGuard as LockGuard;
pub use parking_lot::MappedMutexGuard as MappedLockGuard;

pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU64};

pub use std::sync::Arc as Lrc;
pub use std::sync::Weak as Weak;

Expand Down Expand Up @@ -278,47 +290,6 @@ cfg_if! {
v.erase_send_sync_owner()
}}
}

pub struct LockCell<T>(Lock<T>);

impl<T> LockCell<T> {
#[inline(always)]
pub fn new(inner: T) -> Self {
LockCell(Lock::new(inner))
}

#[inline(always)]
pub fn into_inner(self) -> T {
self.0.into_inner()
}

#[inline(always)]
pub fn set(&self, new_inner: T) {
*self.0.lock() = new_inner;
}

#[inline(always)]
pub fn get(&self) -> T where T: Copy {
*self.0.lock()
}

#[inline(always)]
pub fn set_mut(&mut self, new_inner: T) {
*self.0.get_mut() = new_inner;
}

#[inline(always)]
pub fn get_mut(&mut self) -> T where T: Copy {
*self.0.get_mut()
}
}

impl<T> LockCell<Option<T>> {
#[inline(always)]
pub fn take(&self) -> Option<T> {
self.0.lock().take()
}
}
}
}

Expand Down Expand Up @@ -467,65 +438,6 @@ impl<T> Once<T> {
}
}

impl<T: Copy + Debug> Debug for LockCell<T> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct("LockCell")
.field("value", &self.get())
.finish()
}
}

impl<T:Default> Default for LockCell<T> {
/// Creates a `LockCell<T>`, with the `Default` value for T.
#[inline]
fn default() -> LockCell<T> {
LockCell::new(Default::default())
}
}

impl<T:PartialEq + Copy> PartialEq for LockCell<T> {
#[inline]
fn eq(&self, other: &LockCell<T>) -> bool {
self.get() == other.get()
}
}

impl<T:Eq + Copy> Eq for LockCell<T> {}

impl<T:PartialOrd + Copy> PartialOrd for LockCell<T> {
#[inline]
fn partial_cmp(&self, other: &LockCell<T>) -> Option<Ordering> {
self.get().partial_cmp(&other.get())
}

#[inline]
fn lt(&self, other: &LockCell<T>) -> bool {
self.get() < other.get()
}

#[inline]
fn le(&self, other: &LockCell<T>) -> bool {
self.get() <= other.get()
}

#[inline]
fn gt(&self, other: &LockCell<T>) -> bool {
self.get() > other.get()
}

#[inline]
fn ge(&self, other: &LockCell<T>) -> bool {
self.get() >= other.get()
}
}

impl<T:Ord + Copy> Ord for LockCell<T> {
#[inline]
fn cmp(&self, other: &LockCell<T>) -> Ordering {
self.get().cmp(&other.get())
}
}

#[derive(Debug)]
pub struct Lock<T>(InnerLock<T>);

Expand Down
Loading

0 comments on commit 664c779

Please sign in to comment.