Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature skiplist #3

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
459 changes: 259 additions & 200 deletions BENCHMARKS.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ readme = "README.md"

[dependencies]
owned-alloc = "0.2"
rand = "0.8"
5 changes: 5 additions & 0 deletions benchmark/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ publish = false
lockfree = { path = "../" }
benchsuite = { path = "benchsuite" }
thread_local = "*"
rand = "0.8"

[workspace]
members = ["benchsuite", "."]
Expand Down Expand Up @@ -55,3 +56,7 @@ path = "src/spmc.rs"
[[bin]]
name = "mpmc"
path = "src/mpmc.rs"

[[bin]]
name = "skiplist"
path = "src/skiplist.rs"
151 changes: 151 additions & 0 deletions benchmark/src/skiplist.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#[macro_use]
extern crate benchsuite;
extern crate lockfree;
extern crate rand;

use benchsuite::exec::Target;
use lockfree::skiplist::SkipList;
use std::{
collections::BTreeMap,
sync::{Arc, Mutex},
};

type MutexBTreeMapInner = Arc<Mutex<BTreeMap<u8, u8>>>;

type LockfreeInner = Arc<SkipList<u8, u8>>;

fn randomize(mut i: usize) -> usize {
i ^= i >> 12;
i ^= i << 25;
i ^ i >> 27
}

#[derive(Debug, Clone, Default)]
struct MutexBTreeMapInsert {
inner: MutexBTreeMapInner,
seed: usize,
}

impl Target for MutexBTreeMapInsert {
#[inline(always)]
fn round(&mut self) {
let i = randomize(self.seed);

self.inner.lock().unwrap().insert(i as u8, i as u8);

self.seed = i;
}
}

#[derive(Debug, Clone, Default)]
struct LockfreeInsert {
inner: LockfreeInner,
seed: usize,
}

impl Target for LockfreeInsert {
#[inline(always)]
fn round(&mut self) {
let i = randomize(self.seed);

self.inner.insert(i as u8, i as u8);

self.seed = i;
}
}

#[derive(Debug, Clone, Default)]
struct MutexBTreeMapGet {
inner: MutexBTreeMapInner,
seed: usize,
}

impl Target for MutexBTreeMapGet {
#[inline(always)]
fn round(&mut self) {
let i = randomize(self.seed);

self.inner.lock().unwrap().get(&(i as u8));

self.seed = i;
}
}

#[derive(Debug, Clone, Default)]
struct LockfreeGet {
inner: LockfreeInner,
seed: usize,
}

impl Target for LockfreeGet {
#[inline(always)]
fn round(&mut self) {
let i = randomize(self.seed);

self.inner.get(&(i as u8));

self.seed = i;
}
}

#[derive(Debug, Clone, Default)]
struct MutexBTreeMapPopFirst {
inner: MutexBTreeMapInner,
}

impl Target for MutexBTreeMapPopFirst {
#[inline(always)]
fn round(&mut self) {
self.inner.lock().unwrap().pop_first();
}
}

#[derive(Debug, Clone, Default)]
struct LockfreePopFirst {
inner: LockfreeInner,
}

impl Target for LockfreePopFirst {
#[inline(always)]
fn round(&mut self) {
self.inner.pop_first();
}
}

fn main() {
let mutex = MutexBTreeMapInner::default();
let lockfree = LockfreeInner::default();
bench! {
levels 1, 2, 4, 8, 16, 32;
"mutex btree_map insert" => MutexBTreeMapInsert {
inner: mutex.clone(),
seed: rand::random::<usize>(),
},
"lockfree insert" => LockfreeInsert {
inner: lockfree.clone(),
seed: rand::random::<usize>(),
},
}

bench! {
levels 1, 2, 4, 8, 16, 32;
"mutex btree_map get" => MutexBTreeMapGet {
inner: mutex.clone(),
seed: rand::random::<usize>(),
},
"lockfree get" => LockfreeGet {
inner: lockfree.clone(),
seed: rand::random::<usize>(),
},
}

bench! {
levels 1, 2, 4, 8, 16, 32;
"mutex btree_map pop_first" => MutexBTreeMapPopFirst {
inner: mutex.clone(),
},
"lockfree get pop_first" => LockfreePopFirst {
inner: lockfree.clone(),
},
}
}
4 changes: 2 additions & 2 deletions benchmark/src/tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,15 @@ thread_local! {
impl Target for BlockingTarget {
#[inline(always)]
fn round(&mut self) {
let cell = self.inner.get_or(|| Box::new(Cell::new(0)));
let cell = self.inner.get_or(|| *Box::new(Cell::new(0)));
cell.set(cell.get().wrapping_add(1));
}
}

impl Target for BlkCachedTarget {
#[inline(always)]
fn round(&mut self) {
let cell = self.inner.get_or(|| Box::new(Cell::new(0)));
let cell = self.inner.get_or(|| *Box::new(Cell::new(0)));
cell.set(cell.get().wrapping_add(1));
}
}
Expand Down
30 changes: 18 additions & 12 deletions build-benchmarks.sh
Original file line number Diff line number Diff line change
Expand Up @@ -69,20 +69,26 @@ cargo run --bin mpmc --release >> $FILE || exit 1
echo '```' >> $FILE
echo '' >> $FILE

echo '## REQUEST PROGRAM' >> $FILE
echo '```' >> $FILE
cargo run --bin request --release >> $FILE || exit 1
echo '```' >> $FILE
echo '' >> $FILE
# echo '## REQUEST PROGRAM' >> $FILE
# echo '```' >> $FILE
# cargo run --bin request --release >> $FILE || exit 1
# echo '```' >> $FILE
# echo '' >> $FILE

echo '## MESSAGE REVERB PROGRAM' >> $FILE
echo '```' >> $FILE
cargo run --bin reverb --release >> $FILE || exit 1
echo '```' >> $FILE
echo '' >> $FILE
# echo '## MESSAGE REVERB PROGRAM' >> $FILE
# echo '```' >> $FILE
# cargo run --bin reverb --release >> $FILE || exit 1
# echo '```' >> $FILE
# echo '' >> $FILE

# echo '## HASH MINING' >> $FILE
# echo '```' >> $FILE
# cargo run --bin mining --release >> $FILE || exit 1
# echo '```' >> $FILE
# echo '' >> $FILE

echo '## HASH MINING' >> $FILE
echo '## SKIPLIST' >> $FILE
echo '```' >> $FILE
cargo run --bin mining --release >> $FILE || exit 1
cargo run --bin skiplist --release >> $FILE || exit 1
echo '```' >> $FILE
echo '' >> $FILE
4 changes: 4 additions & 0 deletions fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,9 @@ path = "fuzz_targets/spmc.rs"
name = "mpmc"
path = "fuzz_targets/mpmc.rs"

[[bin]]
name = "skiplist"
path = "fuzz_targets/skiplist.rs"

[profile.release]
lto = "off"
51 changes: 51 additions & 0 deletions fuzz/fuzz_targets/skiplist.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#![no_main]
#[macro_use]
extern crate libfuzzer_sys;
extern crate fuzzsuite;
extern crate lockfree;

use fuzzsuite::*;
use lockfree::prelude::*;
use std::sync::Arc;

#[derive(Debug, Clone, Default)]
struct SkipListMachine {
list: Arc<SkipList<Box<u16>, Box<u16>>>,
}

impl Spawn for SkipListMachine {
fn spawn() -> Self {
Self::default()
}

fn fork(&self) -> Self {
self.clone()
}
}

impl Machine for SkipListMachine {
fn interpret(&mut self, mut byte: u8, bytecode: &mut Bytecode) {
loop {
match byte % 4 {
0 | 1 => {
let val = ((bytecode.next().unwrap_or(0) as u16) << 8)
+ bytecode.next().unwrap_or(0) as u16;
self.list.remove(&Box::new(val));
break;
},

2 | 3 => {
let val = ((bytecode.next().unwrap_or(0) as u16) << 8)
+ bytecode.next().unwrap_or(0) as u16;
self.list.insert(Box::new(val), Box::new(val));
break;
},
_ => unreachable!(),
}
}
}
}

fuzz_target!(|data: &[u8]| {
let _ = test::<SkipListMachine>(Bytecode::no_symbols(data));
});
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
//! - `[x]` [Set](set::Set)
//! - `[x]` [Stack](stack::Stack)
//! - `[x]` [Queue](queue::Queue)
//! - `[x]` [SkipList](skiplist::SkipList)
//! - `[ ]` Deque
//!
//! # Performance Guide
Expand Down Expand Up @@ -55,6 +56,9 @@ pub mod map;
/// A lock-free set.
pub mod set;

/// A lock-free skip list.
pub mod skiplist;

/// Collection of lock-free FIFO channels. These channels are fully asynchronous
/// and their receivers do not provide any sort of `wait-for-message` operation.
/// It would be blocking otherwise, thus not lock-free. If you need such a
Expand Down
1 change: 1 addition & 0 deletions src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ pub use channel::{mpmc, mpsc, spmc, spsc};
pub use map::Map;
pub use queue::Queue;
pub use set::Set;
pub use skiplist::SkipList;
pub use stack::Stack;
pub use tls::ThreadLocal;
Loading