713 lines
19 KiB
Rust
713 lines
19 KiB
Rust
#![feature(test)]
|
|
|
|
extern crate test;
|
|
|
|
use crossbeam_channel::{bounded, unbounded};
|
|
use crossbeam_utils::thread::scope;
|
|
use test::Bencher;
|
|
|
|
const TOTAL_STEPS: usize = 40_000;
|
|
|
|
mod unbounded {
|
|
use super::*;
|
|
|
|
#[bench]
|
|
fn create(b: &mut Bencher) {
|
|
b.iter(unbounded::<i32>);
|
|
}
|
|
|
|
#[bench]
|
|
fn oneshot(b: &mut Bencher) {
|
|
b.iter(|| {
|
|
let (s, r) = unbounded::<i32>();
|
|
s.send(0).unwrap();
|
|
r.recv().unwrap();
|
|
});
|
|
}
|
|
|
|
#[bench]
|
|
fn inout(b: &mut Bencher) {
|
|
let (s, r) = unbounded::<i32>();
|
|
b.iter(|| {
|
|
s.send(0).unwrap();
|
|
r.recv().unwrap();
|
|
});
|
|
}
|
|
|
|
#[bench]
|
|
fn par_inout(b: &mut Bencher) {
|
|
let threads = num_cpus::get();
|
|
let steps = TOTAL_STEPS / threads;
|
|
let (s, r) = unbounded::<i32>();
|
|
|
|
let (s1, r1) = bounded(0);
|
|
let (s2, r2) = bounded(0);
|
|
scope(|scope| {
|
|
for _ in 0..threads {
|
|
scope.spawn(|_| {
|
|
while r1.recv().is_ok() {
|
|
for i in 0..steps {
|
|
s.send(i as i32).unwrap();
|
|
r.recv().unwrap();
|
|
}
|
|
s2.send(()).unwrap();
|
|
}
|
|
});
|
|
}
|
|
|
|
b.iter(|| {
|
|
for _ in 0..threads {
|
|
s1.send(()).unwrap();
|
|
}
|
|
for _ in 0..threads {
|
|
r2.recv().unwrap();
|
|
}
|
|
});
|
|
drop(s1);
|
|
})
|
|
.unwrap();
|
|
}
|
|
|
|
#[bench]
|
|
fn spsc(b: &mut Bencher) {
|
|
let steps = TOTAL_STEPS;
|
|
let (s, r) = unbounded::<i32>();
|
|
|
|
let (s1, r1) = bounded(0);
|
|
let (s2, r2) = bounded(0);
|
|
scope(|scope| {
|
|
scope.spawn(|_| {
|
|
while r1.recv().is_ok() {
|
|
for i in 0..steps {
|
|
s.send(i as i32).unwrap();
|
|
}
|
|
s2.send(()).unwrap();
|
|
}
|
|
});
|
|
|
|
b.iter(|| {
|
|
s1.send(()).unwrap();
|
|
for _ in 0..steps {
|
|
r.recv().unwrap();
|
|
}
|
|
r2.recv().unwrap();
|
|
});
|
|
drop(s1);
|
|
})
|
|
.unwrap();
|
|
}
|
|
|
|
#[bench]
|
|
fn spmc(b: &mut Bencher) {
|
|
let threads = num_cpus::get() - 1;
|
|
let steps = TOTAL_STEPS / threads;
|
|
let (s, r) = unbounded::<i32>();
|
|
|
|
let (s1, r1) = bounded(0);
|
|
let (s2, r2) = bounded(0);
|
|
scope(|scope| {
|
|
for _ in 0..threads {
|
|
scope.spawn(|_| {
|
|
while r1.recv().is_ok() {
|
|
for _ in 0..steps {
|
|
r.recv().unwrap();
|
|
}
|
|
s2.send(()).unwrap();
|
|
}
|
|
});
|
|
}
|
|
|
|
b.iter(|| {
|
|
for _ in 0..threads {
|
|
s1.send(()).unwrap();
|
|
}
|
|
for i in 0..steps * threads {
|
|
s.send(i as i32).unwrap();
|
|
}
|
|
for _ in 0..threads {
|
|
r2.recv().unwrap();
|
|
}
|
|
});
|
|
drop(s1);
|
|
})
|
|
.unwrap();
|
|
}
|
|
|
|
#[bench]
|
|
fn mpsc(b: &mut Bencher) {
|
|
let threads = num_cpus::get() - 1;
|
|
let steps = TOTAL_STEPS / threads;
|
|
let (s, r) = unbounded::<i32>();
|
|
|
|
let (s1, r1) = bounded(0);
|
|
let (s2, r2) = bounded(0);
|
|
scope(|scope| {
|
|
for _ in 0..threads {
|
|
scope.spawn(|_| {
|
|
while r1.recv().is_ok() {
|
|
for i in 0..steps {
|
|
s.send(i as i32).unwrap();
|
|
}
|
|
s2.send(()).unwrap();
|
|
}
|
|
});
|
|
}
|
|
|
|
b.iter(|| {
|
|
for _ in 0..threads {
|
|
s1.send(()).unwrap();
|
|
}
|
|
for _ in 0..steps * threads {
|
|
r.recv().unwrap();
|
|
}
|
|
for _ in 0..threads {
|
|
r2.recv().unwrap();
|
|
}
|
|
});
|
|
drop(s1);
|
|
})
|
|
.unwrap();
|
|
}
|
|
|
|
#[bench]
|
|
fn mpmc(b: &mut Bencher) {
|
|
let threads = num_cpus::get();
|
|
let steps = TOTAL_STEPS / threads;
|
|
let (s, r) = unbounded::<i32>();
|
|
|
|
let (s1, r1) = bounded(0);
|
|
let (s2, r2) = bounded(0);
|
|
scope(|scope| {
|
|
for _ in 0..threads / 2 {
|
|
scope.spawn(|_| {
|
|
while r1.recv().is_ok() {
|
|
for i in 0..steps {
|
|
s.send(i as i32).unwrap();
|
|
}
|
|
s2.send(()).unwrap();
|
|
}
|
|
});
|
|
}
|
|
for _ in 0..threads / 2 {
|
|
scope.spawn(|_| {
|
|
while r1.recv().is_ok() {
|
|
for _ in 0..steps {
|
|
r.recv().unwrap();
|
|
}
|
|
s2.send(()).unwrap();
|
|
}
|
|
});
|
|
}
|
|
|
|
b.iter(|| {
|
|
for _ in 0..threads {
|
|
s1.send(()).unwrap();
|
|
}
|
|
for _ in 0..threads {
|
|
r2.recv().unwrap();
|
|
}
|
|
});
|
|
drop(s1);
|
|
})
|
|
.unwrap();
|
|
}
|
|
}
|
|
|
|
mod bounded_n {
|
|
use super::*;
|
|
|
|
#[bench]
|
|
fn spsc(b: &mut Bencher) {
|
|
let steps = TOTAL_STEPS;
|
|
let (s, r) = bounded::<i32>(steps);
|
|
|
|
let (s1, r1) = bounded(0);
|
|
let (s2, r2) = bounded(0);
|
|
scope(|scope| {
|
|
scope.spawn(|_| {
|
|
while r1.recv().is_ok() {
|
|
for i in 0..steps {
|
|
s.send(i as i32).unwrap();
|
|
}
|
|
s2.send(()).unwrap();
|
|
}
|
|
});
|
|
|
|
b.iter(|| {
|
|
s1.send(()).unwrap();
|
|
for _ in 0..steps {
|
|
r.recv().unwrap();
|
|
}
|
|
r2.recv().unwrap();
|
|
});
|
|
drop(s1);
|
|
})
|
|
.unwrap();
|
|
}
|
|
|
|
#[bench]
|
|
fn spmc(b: &mut Bencher) {
|
|
let threads = num_cpus::get() - 1;
|
|
let steps = TOTAL_STEPS / threads;
|
|
let (s, r) = bounded::<i32>(steps * threads);
|
|
|
|
let (s1, r1) = bounded(0);
|
|
let (s2, r2) = bounded(0);
|
|
scope(|scope| {
|
|
for _ in 0..threads {
|
|
scope.spawn(|_| {
|
|
while r1.recv().is_ok() {
|
|
for _ in 0..steps {
|
|
r.recv().unwrap();
|
|
}
|
|
s2.send(()).unwrap();
|
|
}
|
|
});
|
|
}
|
|
|
|
b.iter(|| {
|
|
for _ in 0..threads {
|
|
s1.send(()).unwrap();
|
|
}
|
|
for i in 0..steps * threads {
|
|
s.send(i as i32).unwrap();
|
|
}
|
|
for _ in 0..threads {
|
|
r2.recv().unwrap();
|
|
}
|
|
});
|
|
drop(s1);
|
|
})
|
|
.unwrap();
|
|
}
|
|
|
|
#[bench]
|
|
fn mpsc(b: &mut Bencher) {
|
|
let threads = num_cpus::get() - 1;
|
|
let steps = TOTAL_STEPS / threads;
|
|
let (s, r) = bounded::<i32>(steps * threads);
|
|
|
|
let (s1, r1) = bounded(0);
|
|
let (s2, r2) = bounded(0);
|
|
scope(|scope| {
|
|
for _ in 0..threads {
|
|
scope.spawn(|_| {
|
|
while r1.recv().is_ok() {
|
|
for i in 0..steps {
|
|
s.send(i as i32).unwrap();
|
|
}
|
|
s2.send(()).unwrap();
|
|
}
|
|
});
|
|
}
|
|
|
|
b.iter(|| {
|
|
for _ in 0..threads {
|
|
s1.send(()).unwrap();
|
|
}
|
|
for _ in 0..steps * threads {
|
|
r.recv().unwrap();
|
|
}
|
|
for _ in 0..threads {
|
|
r2.recv().unwrap();
|
|
}
|
|
});
|
|
drop(s1);
|
|
})
|
|
.unwrap();
|
|
}
|
|
|
|
#[bench]
|
|
fn par_inout(b: &mut Bencher) {
|
|
let threads = num_cpus::get();
|
|
let steps = TOTAL_STEPS / threads;
|
|
let (s, r) = bounded::<i32>(threads);
|
|
|
|
let (s1, r1) = bounded(0);
|
|
let (s2, r2) = bounded(0);
|
|
scope(|scope| {
|
|
for _ in 0..threads {
|
|
scope.spawn(|_| {
|
|
while r1.recv().is_ok() {
|
|
for i in 0..steps {
|
|
s.send(i as i32).unwrap();
|
|
r.recv().unwrap();
|
|
}
|
|
s2.send(()).unwrap();
|
|
}
|
|
});
|
|
}
|
|
|
|
b.iter(|| {
|
|
for _ in 0..threads {
|
|
s1.send(()).unwrap();
|
|
}
|
|
for _ in 0..threads {
|
|
r2.recv().unwrap();
|
|
}
|
|
});
|
|
drop(s1);
|
|
})
|
|
.unwrap();
|
|
}
|
|
|
|
#[bench]
|
|
fn mpmc(b: &mut Bencher) {
|
|
let threads = num_cpus::get();
|
|
assert_eq!(threads % 2, 0);
|
|
let steps = TOTAL_STEPS / threads;
|
|
let (s, r) = bounded::<i32>(steps * threads);
|
|
|
|
let (s1, r1) = bounded(0);
|
|
let (s2, r2) = bounded(0);
|
|
scope(|scope| {
|
|
for _ in 0..threads / 2 {
|
|
scope.spawn(|_| {
|
|
while r1.recv().is_ok() {
|
|
for i in 0..steps {
|
|
s.send(i as i32).unwrap();
|
|
}
|
|
s2.send(()).unwrap();
|
|
}
|
|
});
|
|
}
|
|
for _ in 0..threads / 2 {
|
|
scope.spawn(|_| {
|
|
while r1.recv().is_ok() {
|
|
for _ in 0..steps {
|
|
r.recv().unwrap();
|
|
}
|
|
s2.send(()).unwrap();
|
|
}
|
|
});
|
|
}
|
|
|
|
b.iter(|| {
|
|
for _ in 0..threads {
|
|
s1.send(()).unwrap();
|
|
}
|
|
for _ in 0..threads {
|
|
r2.recv().unwrap();
|
|
}
|
|
});
|
|
drop(s1);
|
|
})
|
|
.unwrap();
|
|
}
|
|
}
|
|
|
|
mod bounded_1 {
|
|
use super::*;
|
|
|
|
#[bench]
|
|
fn create(b: &mut Bencher) {
|
|
b.iter(|| bounded::<i32>(1));
|
|
}
|
|
|
|
#[bench]
|
|
fn oneshot(b: &mut Bencher) {
|
|
b.iter(|| {
|
|
let (s, r) = bounded::<i32>(1);
|
|
s.send(0).unwrap();
|
|
r.recv().unwrap();
|
|
});
|
|
}
|
|
|
|
#[bench]
|
|
fn spsc(b: &mut Bencher) {
|
|
let steps = TOTAL_STEPS;
|
|
let (s, r) = bounded::<i32>(1);
|
|
|
|
let (s1, r1) = bounded(0);
|
|
let (s2, r2) = bounded(0);
|
|
scope(|scope| {
|
|
scope.spawn(|_| {
|
|
while r1.recv().is_ok() {
|
|
for i in 0..steps {
|
|
s.send(i as i32).unwrap();
|
|
}
|
|
s2.send(()).unwrap();
|
|
}
|
|
});
|
|
|
|
b.iter(|| {
|
|
s1.send(()).unwrap();
|
|
for _ in 0..steps {
|
|
r.recv().unwrap();
|
|
}
|
|
r2.recv().unwrap();
|
|
});
|
|
drop(s1);
|
|
})
|
|
.unwrap();
|
|
}
|
|
|
|
#[bench]
|
|
fn spmc(b: &mut Bencher) {
|
|
let threads = num_cpus::get() - 1;
|
|
let steps = TOTAL_STEPS / threads;
|
|
let (s, r) = bounded::<i32>(1);
|
|
|
|
let (s1, r1) = bounded(0);
|
|
let (s2, r2) = bounded(0);
|
|
scope(|scope| {
|
|
for _ in 0..threads {
|
|
scope.spawn(|_| {
|
|
while r1.recv().is_ok() {
|
|
for _ in 0..steps {
|
|
r.recv().unwrap();
|
|
}
|
|
s2.send(()).unwrap();
|
|
}
|
|
});
|
|
}
|
|
|
|
b.iter(|| {
|
|
for _ in 0..threads {
|
|
s1.send(()).unwrap();
|
|
}
|
|
for i in 0..steps * threads {
|
|
s.send(i as i32).unwrap();
|
|
}
|
|
for _ in 0..threads {
|
|
r2.recv().unwrap();
|
|
}
|
|
});
|
|
drop(s1);
|
|
})
|
|
.unwrap();
|
|
}
|
|
|
|
#[bench]
|
|
fn mpsc(b: &mut Bencher) {
|
|
let threads = num_cpus::get() - 1;
|
|
let steps = TOTAL_STEPS / threads;
|
|
let (s, r) = bounded::<i32>(1);
|
|
|
|
let (s1, r1) = bounded(0);
|
|
let (s2, r2) = bounded(0);
|
|
scope(|scope| {
|
|
for _ in 0..threads {
|
|
scope.spawn(|_| {
|
|
while r1.recv().is_ok() {
|
|
for i in 0..steps {
|
|
s.send(i as i32).unwrap();
|
|
}
|
|
s2.send(()).unwrap();
|
|
}
|
|
});
|
|
}
|
|
|
|
b.iter(|| {
|
|
for _ in 0..threads {
|
|
s1.send(()).unwrap();
|
|
}
|
|
for _ in 0..steps * threads {
|
|
r.recv().unwrap();
|
|
}
|
|
for _ in 0..threads {
|
|
r2.recv().unwrap();
|
|
}
|
|
});
|
|
drop(s1);
|
|
})
|
|
.unwrap();
|
|
}
|
|
|
|
#[bench]
|
|
fn mpmc(b: &mut Bencher) {
|
|
let threads = num_cpus::get();
|
|
let steps = TOTAL_STEPS / threads;
|
|
let (s, r) = bounded::<i32>(1);
|
|
|
|
let (s1, r1) = bounded(0);
|
|
let (s2, r2) = bounded(0);
|
|
scope(|scope| {
|
|
for _ in 0..threads / 2 {
|
|
scope.spawn(|_| {
|
|
while r1.recv().is_ok() {
|
|
for i in 0..steps {
|
|
s.send(i as i32).unwrap();
|
|
}
|
|
s2.send(()).unwrap();
|
|
}
|
|
});
|
|
}
|
|
for _ in 0..threads / 2 {
|
|
scope.spawn(|_| {
|
|
while r1.recv().is_ok() {
|
|
for _ in 0..steps {
|
|
r.recv().unwrap();
|
|
}
|
|
s2.send(()).unwrap();
|
|
}
|
|
});
|
|
}
|
|
|
|
b.iter(|| {
|
|
for _ in 0..threads {
|
|
s1.send(()).unwrap();
|
|
}
|
|
for _ in 0..threads {
|
|
r2.recv().unwrap();
|
|
}
|
|
});
|
|
drop(s1);
|
|
})
|
|
.unwrap();
|
|
}
|
|
}
|
|
|
|
mod bounded_0 {
|
|
use super::*;
|
|
|
|
#[bench]
|
|
fn create(b: &mut Bencher) {
|
|
b.iter(|| bounded::<i32>(0));
|
|
}
|
|
|
|
#[bench]
|
|
fn spsc(b: &mut Bencher) {
|
|
let steps = TOTAL_STEPS;
|
|
let (s, r) = bounded::<i32>(0);
|
|
|
|
let (s1, r1) = bounded(0);
|
|
let (s2, r2) = bounded(0);
|
|
scope(|scope| {
|
|
scope.spawn(|_| {
|
|
while r1.recv().is_ok() {
|
|
for i in 0..steps {
|
|
s.send(i as i32).unwrap();
|
|
}
|
|
s2.send(()).unwrap();
|
|
}
|
|
});
|
|
|
|
b.iter(|| {
|
|
s1.send(()).unwrap();
|
|
for _ in 0..steps {
|
|
r.recv().unwrap();
|
|
}
|
|
r2.recv().unwrap();
|
|
});
|
|
drop(s1);
|
|
})
|
|
.unwrap();
|
|
}
|
|
|
|
#[bench]
|
|
fn spmc(b: &mut Bencher) {
|
|
let threads = num_cpus::get() - 1;
|
|
let steps = TOTAL_STEPS / threads;
|
|
let (s, r) = bounded::<i32>(0);
|
|
|
|
let (s1, r1) = bounded(0);
|
|
let (s2, r2) = bounded(0);
|
|
scope(|scope| {
|
|
for _ in 0..threads {
|
|
scope.spawn(|_| {
|
|
while r1.recv().is_ok() {
|
|
for _ in 0..steps {
|
|
r.recv().unwrap();
|
|
}
|
|
s2.send(()).unwrap();
|
|
}
|
|
});
|
|
}
|
|
|
|
b.iter(|| {
|
|
for _ in 0..threads {
|
|
s1.send(()).unwrap();
|
|
}
|
|
for i in 0..steps * threads {
|
|
s.send(i as i32).unwrap();
|
|
}
|
|
for _ in 0..threads {
|
|
r2.recv().unwrap();
|
|
}
|
|
});
|
|
drop(s1);
|
|
})
|
|
.unwrap();
|
|
}
|
|
|
|
#[bench]
|
|
fn mpsc(b: &mut Bencher) {
|
|
let threads = num_cpus::get() - 1;
|
|
let steps = TOTAL_STEPS / threads;
|
|
let (s, r) = bounded::<i32>(0);
|
|
|
|
let (s1, r1) = bounded(0);
|
|
let (s2, r2) = bounded(0);
|
|
scope(|scope| {
|
|
for _ in 0..threads {
|
|
scope.spawn(|_| {
|
|
while r1.recv().is_ok() {
|
|
for i in 0..steps {
|
|
s.send(i as i32).unwrap();
|
|
}
|
|
s2.send(()).unwrap();
|
|
}
|
|
});
|
|
}
|
|
|
|
b.iter(|| {
|
|
for _ in 0..threads {
|
|
s1.send(()).unwrap();
|
|
}
|
|
for _ in 0..steps * threads {
|
|
r.recv().unwrap();
|
|
}
|
|
for _ in 0..threads {
|
|
r2.recv().unwrap();
|
|
}
|
|
});
|
|
drop(s1);
|
|
})
|
|
.unwrap();
|
|
}
|
|
|
|
#[bench]
|
|
fn mpmc(b: &mut Bencher) {
|
|
let threads = num_cpus::get();
|
|
let steps = TOTAL_STEPS / threads;
|
|
let (s, r) = bounded::<i32>(0);
|
|
|
|
let (s1, r1) = bounded(0);
|
|
let (s2, r2) = bounded(0);
|
|
scope(|scope| {
|
|
for _ in 0..threads / 2 {
|
|
scope.spawn(|_| {
|
|
while r1.recv().is_ok() {
|
|
for i in 0..steps {
|
|
s.send(i as i32).unwrap();
|
|
}
|
|
s2.send(()).unwrap();
|
|
}
|
|
});
|
|
}
|
|
for _ in 0..threads / 2 {
|
|
scope.spawn(|_| {
|
|
while r1.recv().is_ok() {
|
|
for _ in 0..steps {
|
|
r.recv().unwrap();
|
|
}
|
|
s2.send(()).unwrap();
|
|
}
|
|
});
|
|
}
|
|
|
|
b.iter(|| {
|
|
for _ in 0..threads {
|
|
s1.send(()).unwrap();
|
|
}
|
|
for _ in 0..threads {
|
|
r2.recv().unwrap();
|
|
}
|
|
});
|
|
drop(s1);
|
|
})
|
|
.unwrap();
|
|
}
|
|
}
|