Skip to content

Commit

Permalink
Merge pull request #52 from paolobarbolini/main
Browse files Browse the repository at this point in the history
Replace `atomic-shim::AtomicU64` with `crossbeam-utils::atomic::AtomicCell<u64>`
  • Loading branch information
tobz authored Aug 4, 2021
2 parents b8221cc + 9f4eb7b commit 177be77
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 45 deletions.
8 changes: 1 addition & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,14 @@ prost = ["prost-types"]
[dependencies]
once_cell = "1.4"
prost-types = { version = "0.7", optional = true }
atomic-shim = "0.1.0"
crossbeam-utils = "0.8"

[target.'cfg(target_arch = "x86")'.dependencies]
raw-cpuid = "9.0"

[target.'cfg(target_arch = "x86_64")'.dependencies]
raw-cpuid = "9.0"

[target.'cfg(target_arch = "mips")'.dependencies]
ctor = "0.1"

[target.'cfg(target_arch = "powerpc")'.dependencies]
ctor = "0.1"

[target.'cfg(all(not(target_os = "macos"), not(target_os = "ios"), not(target_os = "windows"), not(target_arch = "wasm32")))'.dependencies]
libc = "0.2"

Expand Down
38 changes: 12 additions & 26 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,9 @@
//! [clock_gettime]: https://linux.die.net/man/3/clock_gettime
//! [prost_types_timestamp]: https://docs.rs/prost-types/0.7.0/prost_types/struct.Timestamp.html
//! [windows.performance.now]: https://developer.mozilla.org/en-US/docs/Web/API/Performance/now
use atomic_shim::AtomicU64;
use crossbeam_utils::atomic::AtomicCell;
use std::time::Duration;
use std::{
cell::RefCell,
sync::{atomic::Ordering, Arc},
};
use std::{cell::RefCell, sync::Arc};

use once_cell::sync::OnceCell;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Expand All @@ -149,19 +146,7 @@ use self::stats::Variance;

static GLOBAL_CLOCK: OnceCell<Clock> = OnceCell::new();

#[cfg(any(target_arch = "mips", target_arch = "powerpc"))]
mod atomic_compat {
use super::AtomicU64;
use ctor::ctor;

#[ctor]
pub static GLOBAL_RECENT: AtomicU64 = AtomicU64::new(0);
}
#[cfg(any(target_arch = "mips", target_arch = "powerpc"))]
use self::atomic_compat::GLOBAL_RECENT;

#[cfg(not(any(target_arch = "mips", target_arch = "powerpc")))]
static GLOBAL_RECENT: AtomicU64 = AtomicU64::new(0);
static GLOBAL_RECENT: AtomicCell<u64> = AtomicCell::new(0);

static GLOBAL_CALIBRATION: OnceCell<Calibration> = OnceCell::new();

Expand All @@ -182,7 +167,7 @@ const MAXIMUM_CAL_TIME: Duration = Duration::from_millis(200);
#[derive(Debug)]
enum ClockType {
Monotonic(Monotonic),
Counter(AtomicU64, Monotonic, Counter, Calibration),
Counter(AtomicCell<u64>, Monotonic, Counter, Calibration),
Mock(Arc<Mock>),
}

Expand Down Expand Up @@ -317,7 +302,7 @@ impl Clock {
calibration.calibrate(&reference, &source);
calibration
});
ClockType::Counter(AtomicU64::new(0), reference, source, *calibration)
ClockType::Counter(AtomicCell::new(0), reference, source, *calibration)
} else {
ClockType::Monotonic(reference)
};
Expand Down Expand Up @@ -351,7 +336,8 @@ impl Clock {
let now = counter.now();
// Update the last timestamp with `now`, if `now` is greater
// than the current value.
let last = last.fetch_max(now, Ordering::AcqRel);
// TODO: replace with `AtomicCell::fetch_max` once `crossbeam-utils` implements it.
let last = last.fetch_update(|current| Some(current.max(now))).unwrap();
// `fetch_max` always returns the previous value, so we need to
// see which is *actually* the max.
let actual = std::cmp::max(now, last);
Expand Down Expand Up @@ -476,7 +462,7 @@ impl Clock {
pub fn recent(&self) -> Instant {
match &self.inner {
ClockType::Mock(mock) => Instant(mock.value()),
_ => Instant(GLOBAL_RECENT.load(Ordering::Relaxed)),
_ => Instant(GLOBAL_RECENT.load()),
}
}

Expand All @@ -485,7 +471,7 @@ impl Clock {
/// Most callers should use the existing [`Builder`] machinery for spawning a background thread
/// to handle upkeep, rather than calling [`upkeep`] directly.
pub fn upkeep(value: Instant) {
GLOBAL_RECENT.store(value.0, Ordering::Release);
GLOBAL_RECENT.store(value.0);
}
}

Expand All @@ -502,7 +488,7 @@ impl Clone for ClockType {
ClockType::Mock(mock) => ClockType::Mock(mock.clone()),
ClockType::Monotonic(monotonic) => ClockType::Monotonic(monotonic.clone()),
ClockType::Counter(last, monotonic, counter, calibration) => ClockType::Counter(
AtomicU64::new(last.load(Ordering::Acquire)),
AtomicCell::new(last.load()),
monotonic.clone(),
counter.clone(),
*calibration,
Expand Down Expand Up @@ -530,7 +516,7 @@ pub fn with_clock<T>(clock: &Clock, f: impl FnOnce() -> T) -> T {
/// recent time is updated. For example, programs using an asynchronous runtime may prefer to
/// schedule a task that does the updating, avoiding an extra thread.
pub fn set_recent(instant: Instant) {
GLOBAL_RECENT.store(instant.as_u64(), Ordering::Release);
GLOBAL_RECENT.store(instant.as_u64());
}

#[inline]
Expand All @@ -550,7 +536,7 @@ pub(crate) fn get_recent() -> Instant {
//
// Given that global recent time shouldn't ever be getting _actually_ updated in tests, this
// should be a reasonable trade-off.
let recent = GLOBAL_RECENT.load(Ordering::Acquire);
let recent = GLOBAL_RECENT.load();
if recent != 0 {
Instant(recent)
} else {
Expand Down
19 changes: 7 additions & 12 deletions src/mock.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
#![allow(dead_code)]
use atomic_shim::AtomicU64;
use std::{
sync::{atomic::Ordering, Arc},
time::Duration,
};
use crossbeam_utils::atomic::AtomicCell;
use std::{sync::Arc, time::Duration};

/// Type which can be converted into a nanosecond representation.
///
Expand Down Expand Up @@ -36,30 +33,28 @@ impl IntoNanoseconds for Duration {
/// testing that code can handle large shifts in time.
#[derive(Debug, Clone)]
pub struct Mock {
offset: Arc<AtomicU64>,
offset: Arc<AtomicCell<u64>>,
}

impl Mock {
pub(crate) fn new() -> Self {
Self {
offset: Arc::new(AtomicU64::new(0)),
offset: Arc::new(AtomicCell::new(0)),
}
}

/// Increments the time by the given amount.
pub fn increment<N: IntoNanoseconds>(&self, amount: N) {
self.offset
.fetch_add(amount.into_nanos(), Ordering::Release);
self.offset.fetch_add(amount.into_nanos());
}

/// Decrements the time by the given amount.
pub fn decrement<N: IntoNanoseconds>(&self, amount: N) {
self.offset
.fetch_sub(amount.into_nanos(), Ordering::Release);
self.offset.fetch_sub(amount.into_nanos());
}

/// Gets the current value of this `Mock`.
pub fn value(&self) -> u64 {
self.offset.load(Ordering::Acquire)
self.offset.load()
}
}

2 comments on commit 177be77

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bench-ubuntu-latest

Benchmark suite Current: 177be77 Previous: 8e133cf Ratio
stdlib/instant_now 29 ns/iter (± 1) 33 ns/iter (± 0) 0.88
stdlib/instant_delta 66 ns/iter (± 2) 73 ns/iter (± 0) 0.90
quanta/quanta_now 26 ns/iter (± 0) 35 ns/iter (± 0) 0.74
quanta/quanta_now_delta 55 ns/iter (± 1) 74 ns/iter (± 0) 0.74
quanta/quanta_instant_now 30 ns/iter (± 1) 39 ns/iter (± 0) 0.77
quanta/quanta_raw 17 ns/iter (± 0) 20 ns/iter (± 0) 0.85
quanta/quanta_raw_scaled 22 ns/iter (± 1) 26 ns/iter (± 0) 0.85
quanta/quanta_raw_delta 42 ns/iter (± 1) 50 ns/iter (± 0) 0.84
quanta/quanta_start 23 ns/iter (± 1) 28 ns/iter (± 0) 0.82
quanta/quanta_start_scaled 29 ns/iter (± 1) 33 ns/iter (± 0) 0.88
quanta/quanta_end 24 ns/iter (± 0) 28 ns/iter (± 0) 0.86
quanta/quanta_end_scaled 29 ns/iter (± 1) 34 ns/iter (± 0) 0.85
quanta/quanta_start/end_delta 56 ns/iter (± 2) 61 ns/iter (± 1) 0.92
quanta/quanta_recent 2 ns/iter (± 0) 3 ns/iter (± 0) 0.67
quanta/quanta_instant_recent 2 ns/iter (± 0) 2 ns/iter (± 0) 1

This comment was automatically generated by workflow using github-action-benchmark.

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'bench-ubuntu-latest'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 0.1.

Benchmark suite Current: 177be77 Previous: 8e133cf Ratio
stdlib/instant_now 29 ns/iter (± 1) 33 ns/iter (± 0) 0.88
stdlib/instant_delta 66 ns/iter (± 2) 73 ns/iter (± 0) 0.90
quanta/quanta_now 26 ns/iter (± 0) 35 ns/iter (± 0) 0.74
quanta/quanta_now_delta 55 ns/iter (± 1) 74 ns/iter (± 0) 0.74
quanta/quanta_instant_now 30 ns/iter (± 1) 39 ns/iter (± 0) 0.77
quanta/quanta_raw 17 ns/iter (± 0) 20 ns/iter (± 0) 0.85
quanta/quanta_raw_scaled 22 ns/iter (± 1) 26 ns/iter (± 0) 0.85
quanta/quanta_raw_delta 42 ns/iter (± 1) 50 ns/iter (± 0) 0.84
quanta/quanta_start 23 ns/iter (± 1) 28 ns/iter (± 0) 0.82
quanta/quanta_start_scaled 29 ns/iter (± 1) 33 ns/iter (± 0) 0.88
quanta/quanta_end 24 ns/iter (± 0) 28 ns/iter (± 0) 0.86
quanta/quanta_end_scaled 29 ns/iter (± 1) 34 ns/iter (± 0) 0.85
quanta/quanta_start/end_delta 56 ns/iter (± 2) 61 ns/iter (± 1) 0.92
quanta/quanta_recent 2 ns/iter (± 0) 3 ns/iter (± 0) 0.67
quanta/quanta_instant_recent 2 ns/iter (± 0) 2 ns/iter (± 0) 1

This comment was automatically generated by workflow using github-action-benchmark.

CC: @metrics-rs/maintainers

Please sign in to comment.