#![feature(test)]
extern crate test;
use test::Bencher;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::Relaxed;
use std::sync::{mpsc, Arc};
use std::thread;
use async_std::task;
use crossbeam_channel::{bounded, Sender};
use futures::channel::oneshot;
#[derive(Clone)]
struct AtomicCounter(Sender<()>);
impl Drop for AtomicCounter {
fn drop(&mut self) {
let _ = self.0.send(()); }
}
#[bench]
fn async_std_spawn_empty_many(b: &mut Bencher) {
let (send, recv) = bounded(1);
b.iter(move || {
{
let counter = Arc::new(AtomicCounter(send.clone()));
let counter0 = counter.clone();
let counter1 = counter.clone();
let counter2 = counter.clone();
let counter3 = counter.clone();
thread::spawn(move || {
for _ in 0..2500 {
let counter_copy = counter0.clone();
let _ = task::spawn(async move {
drop(counter_copy);
});
}
});
thread::spawn(move || {
for _ in 2500..5000 {
let counter_copy = counter1.clone();
let _ = task::spawn(async move {
drop(counter_copy);
});
}
});
thread::spawn(move || {
for _ in 5000..7500 {
let counter_copy = counter2.clone();
let _ = task::spawn(async move {
drop(counter_copy);
});
}
});
thread::spawn(move || {
for _ in 7500..10000 {
let counter_copy = counter3.clone();
let _ = task::spawn(async move {
drop(counter_copy);
});
}
});
}
let _ = recv.clone().recv().unwrap();
});
}
#[bench]
fn async_std_await_empty_many(b: &mut Bencher) {
let (send, recv) = bounded(1);
b.iter(move || {
{
let counter = Arc::new(AtomicCounter(send.clone()));
let counter0 = counter.clone();
let counter1 = counter.clone();
let counter2 = counter.clone();
let counter3 = counter.clone();
task::spawn(async move {
for _ in 0..2500 {
let counter_copy = counter0.clone();
async move {
drop(counter_copy);
}
.await;
}
});
task::spawn(async move {
for _ in 2500..5000 {
let counter_copy = counter1.clone();
async move {
drop(counter_copy);
}
.await;
}
});
task::spawn(async move {
for _ in 5000..7500 {
let counter_copy = counter2.clone();
async move {
drop(counter_copy);
}
.await;
}
});
task::spawn(async move {
for _ in 7500..10000 {
let counter_copy = counter3.clone();
async move {
drop(counter_copy);
}
.await;
}
});
}
let _ = recv.clone().recv().unwrap();
});
}
#[bench]
fn async_std_spawn_many(b: &mut Bencher) {
let (send, recv) = bounded(1);
b.iter(move || {
{
let counter = Arc::new(AtomicCounter(send.clone()));
let counter0 = counter.clone();
let counter1 = counter.clone();
let counter2 = counter.clone();
let counter3 = counter.clone();
task::spawn(async move {
for _ in 0..2500 {
let counter_copy = counter0.clone();
let _ = task::spawn(async move {
drop(counter_copy);
});
}
});
task::spawn(async move {
for _ in 2500..5000 {
let counter_copy = counter1.clone();
let _ = task::spawn(async move {
drop(counter_copy);
});
}
});
task::spawn(async move {
for _ in 5000..7500 {
let counter_copy = counter2.clone();
let _ = task::spawn(async move {
drop(counter_copy);
});
}
});
task::spawn(async move {
for _ in 7500..10000 {
let counter_copy = counter3.clone();
let _ = task::spawn(async move {
drop(counter_copy);
});
}
});
}
let _ = recv.clone().recv().unwrap();
});
}
#[bench]
fn async_std_yield_many(b: &mut Bencher) {
const NUM_YIELD: usize = 1_000;
const TASKS: usize = 200;
let (tx, rx) = mpsc::sync_channel(TASKS);
b.iter(move || {
for _ in 0..TASKS {
let tx = tx.clone();
task::spawn(async move {
for _ in 0..NUM_YIELD {
task::yield_now().await;
}
tx.send(()).unwrap();
});
}
for _ in 0..TASKS {
let _ = rx.recv().unwrap();
}
});
}
#[bench]
fn async_std_ping_pong(b: &mut Bencher) {
const NUM_PINGS: usize = 1_000;
let rem = Arc::new(AtomicUsize::new(0));
b.iter(|| {
let (done_tx, done_rx) = bounded(1);
let rem = rem.clone();
rem.store(NUM_PINGS, Relaxed);
task::spawn(async {
task::spawn(async move {
for _ in 0..NUM_PINGS {
let rem = rem.clone();
let done_tx = done_tx.clone();
task::spawn(async move {
let (tx1, rx1) = oneshot::channel();
let (tx2, rx2) = oneshot::channel();
task::spawn(async move {
rx1.await.unwrap();
tx2.send(()).unwrap();
});
tx1.send(()).unwrap();
rx2.await.unwrap();
if 1 == rem.fetch_sub(1, Relaxed) {
done_tx.send(()).unwrap();
}
});
}
});
});
let _ = done_rx.recv().unwrap();
});
}
#[bench]
fn async_std_chained_spawn(b: &mut Bencher) {
const ITER: usize = 1_000;
fn iter(done_tx: mpsc::SyncSender<()>, n: usize) {
if n == 0 {
done_tx.send(()).unwrap();
} else {
task::spawn(async move {
iter(done_tx, n - 1);
});
}
}
let (done_tx, done_rx) = mpsc::sync_channel(1000);
b.iter(move || {
let done_tx = done_tx.clone();
task::block_on(async {
task::spawn(async move {
iter(done_tx, ITER);
});
done_rx.recv().unwrap();
});
});
}
#[bench]
fn async_std_spawn_one_to_one(b: &mut Bencher) {
let (send, recv) = bounded(1);
b.iter(move || {
{
let counter = Arc::new(AtomicCounter(send.clone()));
let counter0 = counter.clone();
let counter1 = counter.clone();
let counter2 = counter.clone();
let counter3 = counter.clone();
thread::spawn(move || {
for _ in 0..2500 {
let counter_copy = counter0.clone();
let _ = task::spawn(async move {
let _ = task::spawn(async move {
drop(counter_copy);
});
});
}
});
thread::spawn(move || {
for _ in 2500..5000 {
let counter_copy = counter1.clone();
let _ = task::spawn(async move {
let _ = task::spawn(async move {
drop(counter_copy);
});
});
}
});
thread::spawn(move || {
for _ in 5000..7500 {
let counter_copy = counter2.clone();
let _ = task::spawn(async move {
let _ = task::spawn(async move {
drop(counter_copy);
});
});
}
});
thread::spawn(move || {
for _ in 7500..10000 {
let counter_copy = counter3.clone();
let _ = task::spawn(async move {
let _ = task::spawn(async move {
drop(counter_copy);
});
});
}
});
}
let _ = recv.clone().recv().unwrap();
});
}