Commit 229ce538 authored by Hai Dang's avatar Hai Dang
Browse files

add mutex benchmark

parent 7eb427b3
Pipeline #42553 passed with stage
in 22 minutes and 44 seconds
......@@ -125,7 +125,7 @@ mod arena {
pub fn par<'arena, 'id, T: Send + Sync>(
num_threads: usize,
list: &NodeRef<'arena, 'id, T>,
list: NodeRef<'arena, 'id, T>,
token: &GhostToken<'id>,
print: impl Fn(&T) + Sync,
) {
......@@ -204,15 +204,15 @@ mod arena_rwlock {
self.next
}
/// Unlink the nodes adjacent to `node`. The node will have `next` and `prev` be `None` after this.
/// Unlink the nodes adjacent to `node`.
pub fn remove(node: NodeRef<'arena, T>) {
let mut node = node.write().unwrap();
let old_prev: Option<NodeRef<_>> = node.prev.take();
let old_next: Option<NodeRef<_>> = node.next.take();
if let Some(old_next) = &old_next {
let old_prev: Option<NodeRef<_>> = node.prev;
let old_next: Option<NodeRef<_>> = node.next;
if let Some(old_next) = old_next {
old_next.write().unwrap().prev = old_prev;
}
if let Some(old_prev) = &old_prev {
if let Some(old_prev) = old_prev {
old_prev.write().unwrap().next = old_next;
}
}
......@@ -228,7 +228,7 @@ mod arena_rwlock {
// Step 2: link node.next pointer and old_node_next.prev pointer to next.
let old_node_next: Option<NodeRef<T>> =
mem::replace(&mut node.write().unwrap().next, Some(next));
if let Some(old_node_next) = &old_node_next {
if let Some(old_node_next) = old_node_next {
old_node_next.write().unwrap().prev = Some(next);
}
......@@ -277,6 +277,114 @@ mod arena_rwlock {
}
}
mod arena_mutex {
use rayon::prelude::*;
use std::{mem, sync::Mutex};
use typed_arena::Arena as TypedArena;
pub struct Node<'arena, T> {
data: T,
prev: Option<NodeRef<'arena, T>>,
next: Option<NodeRef<'arena, T>>,
}
pub type NodeRef<'arena, T> = &'arena Mutex<Node<'arena, T>>;
impl<'arena, T> Node<'arena, T> {
pub fn new(
value: T,
arena: &'arena TypedArena<Mutex<Node<'arena, T>>>
) -> NodeRef<'arena, T> {
arena.alloc(Mutex::new(
Self {
data: value,
prev: None,
next: None,
}
))
}
pub fn prev(&self) -> Option<NodeRef<'arena, T>> {
self.prev
}
pub fn next(&self) -> Option<NodeRef<'arena, T>> {
self.next
}
/// Unlink the nodes adjacent to `node`.
pub fn remove(node: NodeRef<'arena, T>) {
let mut node = node.lock().unwrap();
let old_prev: Option<NodeRef<_>> = node.prev;
let old_next: Option<NodeRef<_>> = node.next;
if let Some(old_next) = old_next {
old_next.lock().unwrap().prev = old_prev;
}
if let Some(old_prev) = old_prev {
old_prev.lock().unwrap().next = old_next;
}
}
/// Insert `next` right after `node` in the list.
pub fn insert_next(
node: NodeRef<'arena, T>,
next: NodeRef<'arena, T>
) {
// Step 1: unlink the prev and next pointers nodes adjacent to next.
Self::remove(next);
// Step 2: link node.next pointer and old_node_next.prev pointer to next.
let old_node_next: Option<NodeRef<T>> =
mem::replace(&mut node.lock().unwrap().next, Some(next));
if let Some(old_node_next) = old_node_next {
old_node_next.lock().unwrap().prev = Some(next);
}
// Step 3: link next to node and old_node_next.
let next: &mut Node<T> = &mut next.lock().unwrap();
next.prev = Some(node);
next.next = old_node_next;
}
pub fn iterate(
node: NodeRef<'arena, T>,
f: impl Fn(&T),
) {
let mut cur: Option<NodeRef<T>> = Some(node);
while let Some(node) = cur {
let node: &Node<T> = &node.lock().unwrap();
f(&node.data);
cur = node.next;
}
}
}
/// Create a dlist segment.
pub fn init<'arena>(
arena: &'arena TypedArena<Mutex<Node<'arena, u32>>>,
list_size: u32) -> NodeRef<'arena, u32> {
let list: NodeRef<'arena, u32> = &*Node::new(0, &arena);
let mut tail = list;
(1..list_size).for_each(|i| {
let node = Node::new(i, &arena);
Node::insert_next(tail, &node);
tail = node;
});
list
}
pub fn par<'arena, T: Send + Sync>(
num_threads: usize,
list: NodeRef<'arena, T>,
f: impl Fn(&T) + Sync,
) {
(0..num_threads)
.into_par_iter()
.for_each(|_| Node::iterate(list, |n| f(n)));
}
}
use ghostcell::GhostToken;
fn bench_dlist(c: &mut Criterion) {
......@@ -341,6 +449,22 @@ fn bench_dlist(c: &mut Criterion) {
});
});
c.bench_function("dlist arena mutex init", |b| {
let arena = TypedArena::with_capacity(black_box(list_size as usize));
b.iter(|| {
black_box(arena_mutex::init(&arena, black_box(list_size)));
})
});
c.bench_function("dlist arena mutex par (×4)", |b| {
let arena = TypedArena::with_capacity(list_size as usize);
let list = arena_mutex::init(&arena, list_size);
b.iter(|| {
black_box(arena_mutex::par(4, &list, |n| {
black_box(n);
}));
});
});
c.bench_function("dlist arc ghostcell init", |b| {
GhostToken::new(|mut token| {
b.iter(|| {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment