mirror of
https://github.com/tokio-rs/tokio.git
synced 2025-10-01 12:20:39 +00:00
chore: fix thread_pool benchmarks (#1947)
Update the rotted thread_pool benchmarks. These benchmarks are not the greatest, but as of now it is all we have for micro benchmarks. Adds a little yielding in the parker as it helps a bit.
This commit is contained in:
parent
24cd6d67f7
commit
c0953d41a5
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
||||||
use tokio::executor::thread_pool::{Builder, Spawner};
|
use tokio::runtime::Builder;
|
||||||
use tokio::sync::oneshot;
|
use tokio::sync::oneshot;
|
||||||
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
@ -28,13 +28,11 @@ impl Future for Backoff {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const NUM_THREADS: usize = 6;
|
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn spawn_many(b: &mut test::Bencher) {
|
fn spawn_many(b: &mut test::Bencher) {
|
||||||
const NUM_SPAWN: usize = 10_000;
|
const NUM_SPAWN: usize = 10_000;
|
||||||
|
|
||||||
let threadpool = Builder::new().num_threads(NUM_THREADS).build();
|
let rt = Builder::new().threaded_scheduler().build().unwrap();
|
||||||
|
|
||||||
let (tx, rx) = mpsc::sync_channel(1000);
|
let (tx, rx) = mpsc::sync_channel(1000);
|
||||||
let rem = Arc::new(AtomicUsize::new(0));
|
let rem = Arc::new(AtomicUsize::new(0));
|
||||||
@ -46,7 +44,7 @@ fn spawn_many(b: &mut test::Bencher) {
|
|||||||
let tx = tx.clone();
|
let tx = tx.clone();
|
||||||
let rem = rem.clone();
|
let rem = rem.clone();
|
||||||
|
|
||||||
threadpool.spawn(async move {
|
rt.spawn(async move {
|
||||||
if 1 == rem.fetch_sub(1, Relaxed) {
|
if 1 == rem.fetch_sub(1, Relaxed) {
|
||||||
tx.send(()).unwrap();
|
tx.send(()).unwrap();
|
||||||
}
|
}
|
||||||
@ -62,7 +60,7 @@ fn yield_many(b: &mut test::Bencher) {
|
|||||||
const NUM_YIELD: usize = 1_000;
|
const NUM_YIELD: usize = 1_000;
|
||||||
const TASKS_PER_CPU: usize = 50;
|
const TASKS_PER_CPU: usize = 50;
|
||||||
|
|
||||||
let threadpool = Builder::new().num_threads(NUM_THREADS).build();
|
let rt = Builder::new().threaded_scheduler().build().unwrap();
|
||||||
|
|
||||||
let tasks = TASKS_PER_CPU * num_cpus::get_physical();
|
let tasks = TASKS_PER_CPU * num_cpus::get_physical();
|
||||||
let (tx, rx) = mpsc::sync_channel(tasks);
|
let (tx, rx) = mpsc::sync_channel(tasks);
|
||||||
@ -71,7 +69,7 @@ fn yield_many(b: &mut test::Bencher) {
|
|||||||
for _ in 0..tasks {
|
for _ in 0..tasks {
|
||||||
let tx = tx.clone();
|
let tx = tx.clone();
|
||||||
|
|
||||||
threadpool.spawn(async move {
|
rt.spawn(async move {
|
||||||
let backoff = Backoff(NUM_YIELD);
|
let backoff = Backoff(NUM_YIELD);
|
||||||
backoff.await;
|
backoff.await;
|
||||||
tx.send(()).unwrap();
|
tx.send(()).unwrap();
|
||||||
@ -88,7 +86,7 @@ fn yield_many(b: &mut test::Bencher) {
|
|||||||
fn ping_pong(b: &mut test::Bencher) {
|
fn ping_pong(b: &mut test::Bencher) {
|
||||||
const NUM_PINGS: usize = 1_000;
|
const NUM_PINGS: usize = 1_000;
|
||||||
|
|
||||||
let threadpool = Builder::new().num_threads(NUM_THREADS).build();
|
let rt = Builder::new().threaded_scheduler().build().unwrap();
|
||||||
|
|
||||||
let (done_tx, done_rx) = mpsc::sync_channel(1000);
|
let (done_tx, done_rx) = mpsc::sync_channel(1000);
|
||||||
let rem = Arc::new(AtomicUsize::new(0));
|
let rem = Arc::new(AtomicUsize::new(0));
|
||||||
@ -98,20 +96,16 @@ fn ping_pong(b: &mut test::Bencher) {
|
|||||||
let rem = rem.clone();
|
let rem = rem.clone();
|
||||||
rem.store(NUM_PINGS, Relaxed);
|
rem.store(NUM_PINGS, Relaxed);
|
||||||
|
|
||||||
let spawner = threadpool.spawner().clone();
|
rt.spawn(async move {
|
||||||
|
|
||||||
threadpool.spawn(async move {
|
|
||||||
for _ in 0..NUM_PINGS {
|
for _ in 0..NUM_PINGS {
|
||||||
let rem = rem.clone();
|
let rem = rem.clone();
|
||||||
let done_tx = done_tx.clone();
|
let done_tx = done_tx.clone();
|
||||||
|
|
||||||
let spawner2 = spawner.clone();
|
tokio::spawn(async move {
|
||||||
|
|
||||||
spawner.spawn(async move {
|
|
||||||
let (tx1, rx1) = oneshot::channel();
|
let (tx1, rx1) = oneshot::channel();
|
||||||
let (tx2, rx2) = oneshot::channel();
|
let (tx2, rx2) = oneshot::channel();
|
||||||
|
|
||||||
spawner2.spawn(async move {
|
tokio::spawn(async move {
|
||||||
rx1.await.unwrap();
|
rx1.await.unwrap();
|
||||||
tx2.send(()).unwrap();
|
tx2.send(()).unwrap();
|
||||||
});
|
});
|
||||||
@ -134,15 +128,14 @@ fn ping_pong(b: &mut test::Bencher) {
|
|||||||
fn chained_spawn(b: &mut test::Bencher) {
|
fn chained_spawn(b: &mut test::Bencher) {
|
||||||
const ITER: usize = 1_000;
|
const ITER: usize = 1_000;
|
||||||
|
|
||||||
let threadpool = Builder::new().num_threads(NUM_THREADS).build();
|
let rt = Builder::new().threaded_scheduler().build().unwrap();
|
||||||
|
|
||||||
fn iter(spawner: Spawner, done_tx: mpsc::SyncSender<()>, n: usize) {
|
fn iter(done_tx: mpsc::SyncSender<()>, n: usize) {
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
done_tx.send(()).unwrap();
|
done_tx.send(()).unwrap();
|
||||||
} else {
|
} else {
|
||||||
let s2 = spawner.clone();
|
tokio::spawn(async move {
|
||||||
spawner.spawn(async move {
|
iter(done_tx, n - 1);
|
||||||
iter(s2, done_tx, n - 1);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,9 +144,8 @@ fn chained_spawn(b: &mut test::Bencher) {
|
|||||||
|
|
||||||
b.iter(move || {
|
b.iter(move || {
|
||||||
let done_tx = done_tx.clone();
|
let done_tx = done_tx.clone();
|
||||||
let spawner = threadpool.spawner().clone();
|
rt.spawn(async move {
|
||||||
threadpool.spawn(async move {
|
iter(done_tx, ITER);
|
||||||
iter(spawner, done_tx, ITER);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
done_rx.recv().unwrap();
|
done_rx.recv().unwrap();
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
use crate::loom::sync::{Arc, Mutex, Condvar};
|
use crate::loom::sync::{Arc, Mutex, Condvar};
|
||||||
use crate::loom::sync::atomic::AtomicUsize;
|
use crate::loom::sync::atomic::AtomicUsize;
|
||||||
|
use crate::loom::thread;
|
||||||
use crate::park::{Park, Unpark};
|
use crate::park::{Park, Unpark};
|
||||||
use crate::runtime::time;
|
use crate::runtime::time;
|
||||||
use crate::util::TryLock;
|
use crate::util::TryLock;
|
||||||
@ -113,12 +114,16 @@ impl Unpark for Unparker {
|
|||||||
impl Inner {
|
impl Inner {
|
||||||
/// Park the current thread for at most `dur`.
|
/// Park the current thread for at most `dur`.
|
||||||
fn park(&self) {
|
fn park(&self) {
|
||||||
|
for _ in 0..3 {
|
||||||
// If we were previously notified then we consume this notification and
|
// If we were previously notified then we consume this notification and
|
||||||
// return quickly.
|
// return quickly.
|
||||||
if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
|
if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
thread::yield_now();
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(mut driver) = self.shared.driver.try_lock() {
|
if let Some(mut driver) = self.shared.driver.try_lock() {
|
||||||
self.park_driver(&mut driver);
|
self.park_driver(&mut driver);
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user