forked from tokio-rs/tokio-uring
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- tokio-rs#148 exposed Runtime. It is now possible to use Criterions async support directly. Do so - Adds criterion support for flamegraph generation of only the benchmarked code (pprof) - Now crashes on second call to block_on, as the AsyncFd still exists Introduced in tokio-rs#142
- Loading branch information
ollie-etl
authored and
ollie-etl
committed
Oct 27, 2022
1 parent
e44a2c9
commit cb676c8
Showing
2 changed files
with
45 additions
and
43 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 |
---|---|---|
@@ -1,85 +1,84 @@ | ||
use criterion::{ | ||
criterion_group, criterion_main, BenchmarkId, Criterion, SamplingMode, Throughput, | ||
criterion_group, criterion_main, BenchmarkId, Criterion, Throughput, | ||
}; | ||
use std::time::{Duration, Instant}; | ||
use pprof::criterion::{Output, PProfProfiler}; | ||
|
||
use tokio::task::JoinSet; | ||
|
||
// To be upstreamed into Criterion, on next release (> 0.3.0) | ||
struct AsyncRuntime(tokio_uring::Runtime); | ||
|
||
impl criterion::async_executor::AsyncExecutor for &AsyncRuntime { | ||
fn block_on<T>(&self, future: impl futures::Future<Output = T>) -> T { | ||
self.0.block_on(future) | ||
} | ||
} | ||
|
||
#[derive(Clone)] | ||
struct Options { | ||
iterations: usize, | ||
concurrency: usize, | ||
sq_size: usize, | ||
cq_size: usize, | ||
} | ||
|
||
impl Default for Options { | ||
fn default() -> Self { | ||
Self { | ||
iterations: 100000, | ||
concurrency: 1, | ||
sq_size: 128, | ||
cq_size: 256, | ||
} | ||
} | ||
} | ||
|
||
fn run_no_ops(opts: &Options, count: u64) -> Duration { | ||
let mut ring_opts = tokio_uring::uring_builder(); | ||
ring_opts | ||
.setup_cqsize(opts.cq_size as _) | ||
// .setup_sqpoll(10) | ||
// .setup_sqpoll_cpu(1) | ||
; | ||
|
||
let mut m = Duration::ZERO; | ||
|
||
// Run the required number of iterations | ||
for _ in 0..count { | ||
m += tokio_uring::builder() | ||
.entries(opts.sq_size as _) | ||
.uring_builder(&ring_opts) | ||
.start(async move { | ||
let mut js = JoinSet::new(); | ||
|
||
for _ in 0..opts.iterations { | ||
js.spawn_local(tokio_uring::no_op()); | ||
} | ||
|
||
let start = Instant::now(); | ||
async fn run_no_ops(opts: &Options) { | ||
let mut js = JoinSet::new(); | ||
|
||
while let Some(res) = js.join_next().await { | ||
res.unwrap().unwrap(); | ||
} | ||
for _ in 0..opts.iterations { | ||
js.spawn_local(tokio_uring::no_op()); | ||
} | ||
|
||
start.elapsed() | ||
}) | ||
while let Some(res) = js.join_next().await { | ||
res.unwrap().unwrap(); | ||
} | ||
m | ||
} | ||
|
||
fn bench(c: &mut Criterion) { | ||
let mut group = c.benchmark_group("no_op"); | ||
let mut opts = Options::default(); | ||
|
||
let mut ring_opts = tokio_uring::uring_builder(); | ||
ring_opts | ||
.setup_cqsize(256) | ||
// .setup_sqpoll(10) | ||
// .setup_sqpoll_cpu(1) | ||
; | ||
|
||
let mut builder = tokio_uring::builder(); | ||
builder.entries(128).uring_builder(&ring_opts); | ||
|
||
let runtime = AsyncRuntime(tokio_uring::Runtime::new(&builder).unwrap()); | ||
let runtime = &runtime; | ||
|
||
for concurrency in [1, 32, 64, 256].iter() { | ||
opts.concurrency = *concurrency; | ||
|
||
// We perform long running benchmarks: this is the best mode | ||
group.sampling_mode(SamplingMode::Flat); | ||
|
||
group.throughput(Throughput::Elements(opts.iterations as u64)); | ||
group.bench_with_input( | ||
BenchmarkId::from_parameter(concurrency), | ||
&opts, | ||
|b, opts| { | ||
// Custom iterator used because we don't expose access to runtime, | ||
// which is required to do async benchmarking with criterion | ||
b.iter_custom(move |iter| run_no_ops(opts, iter)); | ||
b.to_async(runtime).iter(|| run_no_ops(opts)); | ||
}, | ||
); | ||
} | ||
group.finish(); | ||
} | ||
|
||
criterion_group!(benches, bench); | ||
criterion_group! { | ||
name = benches; | ||
config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None))); | ||
targets = bench | ||
} | ||
criterion_main!(benches); |