redb 0.12.1

Rust Embedded DataBase
Documentation
use std::hint::black_box;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::{Mutex, RwLock};
use std::thread;
use std::time::SystemTime;

const ITERATIONS: usize = 1000 * 1000;

fn baseline(num_threads: usize) {
    let start = SystemTime::now();
    for _ in 0..num_threads {
        thread::scope(|s| {
            s.spawn(|| {
                let mut value = 0u64;
                for _ in 0..ITERATIONS {
                    let value = black_box(&mut value);
                    *value += 1;
                }
                for _ in 0..ITERATIONS {
                    let value = black_box(&mut value);
                    *value -= 1;
                }
            });
        });
    }

    let end = SystemTime::now();
    let duration = end.duration_since(start).unwrap();
    println!(
        "baseline (NOT atomic) ({} threads): {} ops in {}ms",
        num_threads,
        2 * ITERATIONS,
        duration.as_millis(),
    );
}

fn atomics(num_threads: usize) {
    let start = SystemTime::now();
    let value = AtomicU64::new(0);
    for _ in 0..num_threads {
        thread::scope(|s| {
            s.spawn(|| {
                for _ in 0..ITERATIONS {
                    let value = black_box(&value);
                    value.fetch_add(1, Ordering::Release);
                }
                for _ in 0..ITERATIONS {
                    let value = black_box(&value);
                    value.fetch_sub(1, Ordering::Release);
                }
            });
        });
    }
    assert_eq!(0, value.load(Ordering::Acquire));

    let end = SystemTime::now();
    let duration = end.duration_since(start).unwrap();
    println!(
        "atomics ({} threads): {} ops in {}ms",
        num_threads,
        2 * ITERATIONS,
        duration.as_millis(),
    );
}

fn mutex(num_threads: usize) {
    let start = SystemTime::now();
    let value = Mutex::new(0u64);
    for _ in 0..num_threads {
        thread::scope(|s| {
            s.spawn(|| {
                for _ in 0..ITERATIONS {
                    let value = black_box(&value);
                    *value.lock().unwrap() += 1;
                }
                for _ in 0..ITERATIONS {
                    let value = black_box(&value);
                    *value.lock().unwrap() -= 1;
                }
            });
        });
    }
    assert_eq!(0u64, *value.lock().unwrap());

    let end = SystemTime::now();
    let duration = end.duration_since(start).unwrap();
    println!(
        "mutex ({} threads): {} ops in {}ms",
        num_threads,
        2 * ITERATIONS,
        duration.as_millis(),
    );
}

fn rw_lock(num_threads: usize) {
    let start = SystemTime::now();
    let value = RwLock::new(0u64);
    for _ in 0..num_threads {
        thread::scope(|s| {
            s.spawn(|| {
                for _ in 0..ITERATIONS {
                    let value = black_box(&value);
                    *value.write().unwrap() += 1;
                }
                for _ in 0..ITERATIONS {
                    let value = black_box(&value);
                    *value.write().unwrap() -= 1;
                }
            });
        });
    }
    assert_eq!(0u64, *value.read().unwrap());

    let end = SystemTime::now();
    let duration = end.duration_since(start).unwrap();
    println!(
        "rwlock ({} threads): {} ops in {}ms",
        num_threads,
        2 * ITERATIONS,
        duration.as_millis(),
    );
}

fn main() {
    for threads in [1, 2, 4, 8, 16, 32, 64] {
        baseline(threads);
        atomics(threads);
        mutex(threads);
        rw_lock(threads);
        println!();
    }
}