Skip to content

Instantly share code, notes, and snippets.

@siddontang
Created January 9, 2018 03:22
Show Gist options
  • Save siddontang/9d9800f9f4981fea02145ca52f4687a9 to your computer and use it in GitHub Desktop.
Save siddontang/9d9800f9f4981fea02145ca52f4687a9 to your computer and use it in GitHub Desktop.
#![feature(test)]
#![feature(integer_atomics)]
extern crate test;
extern crate libc;
use std::f64;
use std::sync::atomic::{AtomicU64 as StdAtomicU64, Ordering};
pub struct AtomicF64 {
inner: StdAtomicU64,
}
impl AtomicF64 {
pub fn new(val: f64) -> AtomicF64 {
AtomicF64 {
inner: StdAtomicU64::new(f64_to_u64(val)),
}
}
#[inline]
pub fn get(&self) -> f64 {
u64_to_f64(self.inner.load(Ordering::Relaxed))
}
#[inline]
pub fn set(&self, val: f64) {
self.inner.store(f64_to_u64(val), Ordering::Relaxed)
}
#[inline]
pub fn inc_by(&self, delta: f64) {
loop {
let current = self.inner.load(Ordering::Acquire);
let new = u64_to_f64(current) + delta;
let swapped = self.inner
.compare_and_swap(current, f64_to_u64(new), Ordering::Release);
if swapped == current {
return;
}
}
}
}
fn u64_to_f64(val: u64) -> f64 {
f64::from_bits(val)
}
fn f64_to_u64(val: f64) -> u64 {
f64::to_bits(val)
}
pub struct AtomicU64 {
inner: StdAtomicU64,
}
impl AtomicU64 {
pub fn new(val: u64) -> AtomicU64 {
AtomicU64 {
inner: StdAtomicU64::new(val),
}
}
#[inline]
pub fn get(&self) -> u64 {
self.inner.load(Ordering::Acquire)
}
#[inline]
pub fn inc_by(&self, delta: u64) {
self.inner.fetch_add(delta, Ordering::Release);
}
}
fn get_cpuid() -> usize {
unsafe {
libc::sched_getcpu() as usize
}
}
#[cfg(test)]
mod tests {
use super::*;
use test::Bencher;
#[bench]
fn bench_getcpuid(b: &mut Bencher) {
b.iter(|| get_cpuid(); );
}
#[bench]
fn bench_f64_inc(b: &mut Bencher) {
let v = AtomicF64::new(0.0);
b.iter(|| v.inc_by(1.0); );
}
#[bench]
fn bench_u64_inc(b: &mut Bencher) {
let v = AtomicU64::new(0);
b.iter(|| v.inc_by(1); );
}
#[bench]
fn bench_use_cpuid(b: &mut Bencher) {
let mut v = Vec::new();
for _ in 0..1024 {
v.push(AtomicF64::new(1.0));
}
b.iter(|| {
let i = get_cpuid();
v[i].inc_by(1.0);
});
}
#[bench]
fn bench_global(b: &mut Bencher) {
let v = AtomicF64::new(0.0);
b.iter(||{v.inc_by(1.0);});
}
#[bench]
fn bench_local(b: &mut Bencher) {
let mut i = 0;
let v = AtomicF64::new(0.0);
let mut lv = 0.0;
b.iter(||{
i += 1;
lv += 1.0;
if i == 100 {
i = 0;
v.inc_by(lv);
lv = 0.0;
}
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment