-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add benchmarks from dashmap and hashbrown (#43)
- Loading branch information
1 parent
dbcb6af
commit 208cfcf
Showing
6 changed files
with
683 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
## Benchmarks | ||
|
||
Currently, benchmarks following those of [`dashmap`](https://github.com/xacrimon/dashmap/tree/master/benches) and [`hashbrown`](https://github.com/rust-lang/hashbrown/blob/master/benches/bench.rs) are provided. | ||
To compare against other hashmap implementations, the benchmarks located in the respective repositories may be executed. | ||
Note that `flurry`, like `dashmap`, uses [`criterion`](https://docs.rs/criterion/0.3.1/criterion/) (and [`rayon`](https://docs.rs/rayon/1.3.0/rayon/) for parallel testing), while `hashbrown` uses [`test::bench`](https://doc.rust-lang.org/test/bench/index.html). | ||
|
||
To run the `flurry` benchmarks, just run | ||
|
||
```console | ||
$ cargo bench | ||
``` | ||
|
||
or | ||
|
||
```console | ||
$ cargo bench <BENCHNAME> | ||
``` | ||
|
||
to only run benches containing `<BENCHNAME>` in their names. | ||
|
||
To run the original `dashmap` benchmarks: | ||
|
||
```console | ||
$ git clone https://github.com/xacrimon/dashmap.git | ||
$ cd dashmap | ||
$ cargo bench [<BENCHNAME>] | ||
``` | ||
|
||
To run the original `hashbrown` benchmarks: | ||
|
||
```console | ||
$ git clone https://github.com/rust-lang/hashbrown.git | ||
$ cd hashbrown | ||
$ cargo bench [<BENCHNAME>] | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2019 Acrimon | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
/* Benchmarks from `dashmap` (https://github.com/xacrimon/dashmap), | ||
* adapted to flurry for comparison: | ||
* | ||
* This benchmark suite contains benchmarks for concurrent insertion | ||
* and retrieval (get). | ||
* Currently, this file provides two versions of each test, one which | ||
* follows the original implementation in using `par_iter().for_each()`, | ||
* which necessitates creating a new guard for each operation since | ||
* guards are not `Send + Sync`, and one version which uses threads | ||
* spawned in scopes. The latter version is able to create only one | ||
* guard per thread, but incurs overhead from the setup of the more | ||
* heavyweight threading environment. | ||
* | ||
* For the associated license information, please refer to dashmap.LICENSE. | ||
*/ | ||
|
||
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput}; | ||
use flurry::{epoch, HashMap}; | ||
use rayon; | ||
use rayon::prelude::*; | ||
use std::sync::Arc; | ||
|
||
/* DASHMAP */ | ||
const ITER: u64 = 32 * 1024; | ||
|
||
fn task_insert_flurry_u64_u64_guard_every_it() -> HashMap<u64, u64> { | ||
let map = HashMap::with_capacity(ITER as usize); | ||
(0..ITER).into_par_iter().for_each(|i| { | ||
let guard = epoch::pin(); | ||
map.insert(i, i + 7, &guard); | ||
}); | ||
map | ||
} | ||
|
||
fn insert_flurry_u64_u64_guard_every_it(c: &mut Criterion) { | ||
let mut group = c.benchmark_group("insert_flurry_u64_u64_guard_every_it"); | ||
group.throughput(Throughput::Elements(ITER as u64)); | ||
let max = num_cpus::get(); | ||
|
||
for threads in 1..=max { | ||
group.bench_with_input( | ||
BenchmarkId::from_parameter(threads), | ||
&threads, | ||
|b, &threads| { | ||
let pool = rayon::ThreadPoolBuilder::new() | ||
.num_threads(threads) | ||
.build() | ||
.unwrap(); | ||
pool.install(|| b.iter(task_insert_flurry_u64_u64_guard_every_it)); | ||
}, | ||
); | ||
} | ||
|
||
group.finish(); | ||
} | ||
|
||
fn task_insert_flurry_u64_u64_guard_once(threads: usize) -> HashMap<u64, u64> { | ||
let map = Arc::new(HashMap::with_capacity(ITER as usize)); | ||
let inc = ITER / (threads as u64); | ||
|
||
rayon::scope(|s| { | ||
for t in 1..=(threads as u64) { | ||
let m = map.clone(); | ||
s.spawn(move |_| { | ||
let start = t * inc; | ||
let guard = epoch::pin(); | ||
for i in start..(start + inc) { | ||
m.insert(i, i + 7, &guard); | ||
} | ||
}); | ||
} | ||
}); | ||
Arc::try_unwrap(map).unwrap() | ||
} | ||
|
||
fn insert_flurry_u64_u64_guard_once(c: &mut Criterion) { | ||
let mut group = c.benchmark_group("insert_flurry_u64_u64_guard_once"); | ||
group.throughput(Throughput::Elements(ITER as u64)); | ||
let max = num_cpus::get(); | ||
|
||
for threads in 1..=max { | ||
group.bench_with_input( | ||
BenchmarkId::from_parameter(threads), | ||
&threads, | ||
|b, &threads| { | ||
let pool = rayon::ThreadPoolBuilder::new() | ||
.num_threads(threads) | ||
.build() | ||
.unwrap(); | ||
pool.install(|| b.iter(|| task_insert_flurry_u64_u64_guard_once(threads))); | ||
}, | ||
); | ||
} | ||
|
||
group.finish(); | ||
} | ||
|
||
fn task_get_flurry_u64_u64_guard_every_it(map: &HashMap<u64, u64>) { | ||
(0..ITER).into_par_iter().for_each(|i| { | ||
let guard = epoch::pin(); | ||
assert_eq!(*map.get(&i, &guard).unwrap(), i + 7); | ||
}); | ||
} | ||
|
||
fn get_flurry_u64_u64_guard_every_it(c: &mut Criterion) { | ||
let mut group = c.benchmark_group("get_flurry_u64_u64_guard_every_it"); | ||
group.throughput(Throughput::Elements(ITER as u64)); | ||
let max = num_cpus::get(); | ||
|
||
for threads in 1..=max { | ||
let map = task_insert_flurry_u64_u64_guard_every_it(); | ||
|
||
group.bench_with_input( | ||
BenchmarkId::from_parameter(threads), | ||
&threads, | ||
|b, &threads| { | ||
let pool = rayon::ThreadPoolBuilder::new() | ||
.num_threads(threads) | ||
.build() | ||
.unwrap(); | ||
pool.install(|| b.iter(|| task_get_flurry_u64_u64_guard_every_it(&map))); | ||
}, | ||
); | ||
} | ||
|
||
group.finish(); | ||
} | ||
|
||
fn task_get_flurry_u64_u64_guard_once(threads: usize, map: Arc<HashMap<u64, u64>>) { | ||
let inc = ITER / (threads as u64); | ||
|
||
rayon::scope(|s| { | ||
for t in 1..=(threads as u64) { | ||
let m = map.clone(); | ||
s.spawn(move |_| { | ||
let start = t * inc; | ||
let guard = epoch::pin(); | ||
for i in start..(start + inc) { | ||
if let Some(&v) = m.get(&i, &guard) { | ||
assert_eq!(v, i + 7); | ||
} | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
|
||
fn get_flurry_u64_u64_guard_once(c: &mut Criterion) { | ||
let mut group = c.benchmark_group("get_flurry_u64_u64_guard_once"); | ||
group.throughput(Throughput::Elements(ITER as u64)); | ||
let max = num_cpus::get(); | ||
|
||
for threads in 1..=max { | ||
let map = Arc::new(task_insert_flurry_u64_u64_guard_every_it()); | ||
|
||
group.bench_with_input( | ||
BenchmarkId::from_parameter(threads), | ||
&threads, | ||
|b, &threads| { | ||
let pool = rayon::ThreadPoolBuilder::new() | ||
.num_threads(threads) | ||
.build() | ||
.unwrap(); | ||
pool.install(|| { | ||
b.iter(|| task_get_flurry_u64_u64_guard_once(threads, map.clone())) | ||
}); | ||
}, | ||
); | ||
} | ||
|
||
group.finish(); | ||
} | ||
|
||
criterion_group!( | ||
benches, | ||
insert_flurry_u64_u64_guard_every_it, | ||
get_flurry_u64_u64_guard_every_it, | ||
insert_flurry_u64_u64_guard_once, | ||
get_flurry_u64_u64_guard_once, | ||
); | ||
criterion_main!(benches); |
Oops, something went wrong.