From 155c2254e668b5429e232ac2c03dc8cd45a63421 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Mon, 11 Mar 2024 23:23:29 +0800 Subject: [PATCH 1/9] refactor(bench): rewrite fs bench --- compio/Cargo.toml | 1 + compio/benches/fs.rs | 422 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 351 insertions(+), 72 deletions(-) diff --git a/compio/Cargo.toml b/compio/Cargo.toml index a38e9f36..d8704910 100644 --- a/compio/Cargo.toml +++ b/compio/Cargo.toml @@ -51,6 +51,7 @@ compio-macros = { workspace = true } criterion = { workspace = true, features = ["async_tokio"] } futures-channel = { workspace = true } futures-util = { workspace = true } +rand = "0.8.5" tempfile = { workspace = true } tokio = { workspace = true, features = [ "fs", diff --git a/compio/benches/fs.rs b/compio/benches/fs.rs index 96dd78f0..735b3c41 100644 --- a/compio/benches/fs.rs +++ b/compio/benches/fs.rs @@ -1,92 +1,370 @@ -use criterion::{criterion_group, criterion_main, Criterion}; +use std::{ + io::{Read, Seek, SeekFrom, Write}, + path::Path, +}; + +use compio_buf::{IntoInner, IoBuf}; +use compio_io::{AsyncReadAtExt, AsyncWriteAtExt}; +use criterion::{criterion_group, criterion_main, Bencher, Criterion}; +use futures_util::{stream::FuturesUnordered, StreamExt}; +use rand::{thread_rng, Rng, RngCore}; use tempfile::NamedTempFile; +use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt}; criterion_group!(fs, read, write); criterion_main!(fs); +const BUFFER_SIZE: usize = 4096; + +fn read_std(b: &mut Bencher, (path, offsets): &(&Path, &[u64])) { + b.iter(|| { + #[allow(unused_mut)] + let mut file = std::fs::File::open(path).unwrap(); + let mut buffer = [0u8; BUFFER_SIZE]; + for &offset in *offsets { + #[cfg(windows)] + { + file.seek(SeekFrom::Start(offset)).unwrap(); + file.read_exact(&mut buffer).unwrap(); + } + #[cfg(unix)] + { + use std::os::unix::fs::FileExt; + file.read_exact_at(&mut buffer, offset).unwrap(); + } + } + buffer + }) +} + +fn read_tokio(b: &mut Bencher, (path, offsets): &(&Path, &[u64])) { + let runtime = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + b.to_async(&runtime).iter(|| async { + let mut file = tokio::fs::File::open(path).await.unwrap(); + let mut buffer = [0u8; BUFFER_SIZE]; + for &offset in *offsets { + file.seek(SeekFrom::Start(offset)).await.unwrap(); + file.read_exact(&mut buffer).await.unwrap(); + } + buffer + }) +} + +fn read_compio(b: &mut Bencher, (path, offsets): &(&Path, &[u64])) { + let runtime = compio::runtime::Runtime::new().unwrap(); + b.to_async(&runtime).iter(|| async { + let file = compio::fs::File::open(path).await.unwrap(); + let mut buffer = [0u8; BUFFER_SIZE]; + for &offset in *offsets { + (_, buffer) = file.read_exact_at(buffer, offset).await.unwrap(); + } + buffer + }) +} + +fn read_compio_join(b: &mut Bencher, (path, offsets): &(&Path, &[u64])) { + let runtime = compio::runtime::Runtime::new().unwrap(); + b.to_async(&runtime).iter(|| async { + let file = compio::fs::File::open(path).await.unwrap(); + offsets + .iter() + .map(|offset| async { + let buffer = [0u8; BUFFER_SIZE]; + let (_, buffer) = file.read_exact_at(buffer, *offset).await.unwrap(); + buffer + }) + .collect::>() + .collect::>() + .await + }) +} + +fn read_all_std(b: &mut Bencher, (path, len): &(&Path, u64)) { + b.iter(|| { + let mut file = std::fs::File::open(path).unwrap(); + let mut buffer = [0u8; BUFFER_SIZE]; + let mut read_len = 0; + while read_len < *len { + file.read_exact(&mut buffer).unwrap(); + read_len += BUFFER_SIZE as u64; + } + buffer + }) +} + +fn read_all_tokio(b: &mut Bencher, (path, len): &(&Path, u64)) { + let runtime = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + b.to_async(&runtime).iter(|| async { + let mut file = tokio::fs::File::open(path).await.unwrap(); + let mut buffer = [0u8; BUFFER_SIZE]; + let mut read_len = 0; + while read_len < *len { + file.read_exact(&mut buffer).await.unwrap(); + read_len += BUFFER_SIZE as u64; + } + buffer + }) +} + +fn read_all_compio(b: &mut Bencher, (path, len): &(&Path, u64)) { + let runtime = compio::runtime::Runtime::new().unwrap(); + b.to_async(&runtime).iter(|| async { + let file = compio::fs::File::open(path).await.unwrap(); + let mut buffer = [0u8; BUFFER_SIZE]; + let mut read_len = 0; + while read_len < *len { + (_, buffer) = file.read_exact_at(buffer, read_len).await.unwrap(); + read_len += BUFFER_SIZE as u64; + } + buffer + }) +} + +fn read_all_compio_join(b: &mut Bencher, (path, len): &(&Path, u64)) { + let runtime = compio::runtime::Runtime::new().unwrap(); + b.to_async(&runtime).iter(|| async { + let file = compio::fs::File::open(path).await.unwrap(); + let tasks = len / BUFFER_SIZE as u64; + (0..tasks) + .map(|offset| { + let file = &file; + async move { + let buffer = [0u8; BUFFER_SIZE]; + let (_, buffer) = file.read_exact_at(buffer, offset).await.unwrap(); + buffer + } + }) + .collect::>() + .collect::>() + .await + }) +} + fn read(c: &mut Criterion) { + const FILE_SIZE: u64 = 1024; + + let mut rng = thread_rng(); + + let mut file = NamedTempFile::new().unwrap(); + for _i in 0..FILE_SIZE { + let mut buffer = [0u8; BUFFER_SIZE]; + rng.fill_bytes(&mut buffer); + file.write_all(&buffer).unwrap(); + } + file.flush().unwrap(); + let path = file.into_temp_path(); + + let mut offsets = vec![]; + for _i in 0..64 { + let offset = rng.gen_range(0u64..FILE_SIZE) * BUFFER_SIZE as u64; + offsets.push(offset); + } + let mut group = c.benchmark_group("read"); - group.bench_function("std", |b| { - b.iter(|| { - use std::io::Read; - - let mut file = std::fs::File::open("Cargo.toml").unwrap(); - let mut buffer = Vec::with_capacity(1024); - file.read_to_end(&mut buffer).unwrap(); - buffer - }) - }); - - group.bench_function("tokio", |b| { - let runtime = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .unwrap(); - b.to_async(&runtime).iter(|| async { - use tokio::io::AsyncReadExt; - - let mut file = tokio::fs::File::open("Cargo.toml").await.unwrap(); - let mut buffer = Vec::with_capacity(1024); - file.read_to_end(&mut buffer).await.unwrap(); - buffer - }) - }); - - group.bench_function("compio", |b| { - let runtime = compio::runtime::Runtime::new().unwrap(); - b.to_async(&runtime).iter(|| async { - use compio::io::AsyncReadAtExt; - - let file = compio::fs::File::open("Cargo.toml").await.unwrap(); - let buffer = Vec::with_capacity(1024); - let (_, buffer) = file.read_to_end_at(buffer, 0).await.unwrap(); - buffer - }) - }); + group.bench_with_input::<_, _, (&Path, &[u64])>("std-random", &(&path, &offsets), read_std); + group.bench_with_input::<_, _, (&Path, &[u64])>("tokio-random", &(&path, &offsets), read_tokio); + group.bench_with_input::<_, _, (&Path, &[u64])>( + "compio-random", + &(&path, &offsets), + read_compio, + ); + group.bench_with_input::<_, _, (&Path, &[u64])>( + "compio-random-join", + &(&path, &offsets), + read_compio_join, + ); + + group.bench_with_input::<_, _, (&Path, u64)>("std-all", &(&path, FILE_SIZE), read_all_std); + group.bench_with_input::<_, _, (&Path, u64)>("tokio-all", &(&path, FILE_SIZE), read_all_tokio); + group.bench_with_input::<_, _, (&Path, u64)>( + "compio-all", + &(&path, FILE_SIZE), + read_all_compio, + ); + group.bench_with_input::<_, _, (&Path, u64)>( + "compio-all-join", + &(&path, FILE_SIZE), + read_all_compio_join, + ); group.finish(); } -static CONTENT: &[u8] = include_bytes!("../Cargo.toml"); +fn write_std(b: &mut Bencher, (path, offsets, content): &(&Path, &[u64], &[u8])) { + b.iter(|| { + let mut file = std::fs::OpenOptions::new().write(true).open(path).unwrap(); + for &offset in *offsets { + #[cfg(windows)] + { + file.seek(SeekFrom::Start(offset)).unwrap(); + file.write_all(content).unwrap(); + } + #[cfg(unix)] + { + use std::os::unix::fs::FileExt; + file.write_all_at(content, offset).unwrap(); + } + } + }) +} + +fn write_tokio(b: &mut Bencher, (path, offsets, content): &(&Path, &[u64], &[u8])) { + let runtime = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + b.to_async(&runtime).iter(|| async { + let mut file = tokio::fs::OpenOptions::new() + .write(true) + .open(path) + .await + .unwrap(); + for &offset in *offsets { + file.seek(SeekFrom::Start(offset)).await.unwrap(); + file.write_all(content).await.unwrap(); + } + }) +} + +fn write_compio(b: &mut Bencher, (path, offsets, content): &(&Path, &[u64], &[u8])) { + let runtime = compio::runtime::Runtime::new().unwrap(); + let content = content.to_vec(); + b.to_async(&runtime).iter(|| { + let mut content = content.clone(); + async { + let mut file = compio::fs::OpenOptions::new() + .write(true) + .open(path) + .await + .unwrap(); + for &offset in *offsets { + (_, content) = file.write_all_at(content, offset).await.unwrap(); + } + } + }) +} + +fn write_compio_join(b: &mut Bencher, (path, offsets, content): &(&Path, &[u64], &[u8])) { + let runtime = compio::runtime::Runtime::new().unwrap(); + let content = content.to_vec(); + b.to_async(&runtime).iter(|| async { + let file = compio::fs::OpenOptions::new() + .write(true) + .open(path) + .await + .unwrap(); + offsets + .iter() + .map(|offset| { + let mut file = &file; + let content = content.clone(); + async move { file.write_all_at(content, *offset).await.unwrap() } + }) + .collect::>() + .collect::>() + .await + }) +} + +fn write_all_std(b: &mut Bencher, (path, content): &(&Path, &[u8])) { + b.iter(|| { + let mut file = std::fs::File::create(path).unwrap(); + for buffer in content.windows(BUFFER_SIZE) { + file.write_all(buffer).unwrap(); + } + }) +} + +fn write_all_compio(b: &mut Bencher, (path, content): &(&Path, &[u8])) { + let runtime = compio::runtime::Runtime::new().unwrap(); + let content = content.to_vec(); + b.to_async(&runtime).iter(|| { + let mut content = content.clone(); + async { + let mut file = compio::fs::File::create(path).await.unwrap(); + let mut write_len = 0; + while write_len < content.len() as u64 { + let (_, slice) = file + .write_all_at( + content.slice(write_len as usize..write_len as usize + BUFFER_SIZE), + write_len, + ) + .await + .unwrap(); + write_len += BUFFER_SIZE as u64; + content = slice.into_inner(); + } + } + }) +} fn write(c: &mut Criterion) { - let mut group = c.benchmark_group("write"); + const FILE_SIZE: u64 = 1024; + const WRITE_FILE_SIZE: u64 = 16; - group.bench_function("std", |b| { - let temp_file = NamedTempFile::new().unwrap(); - b.iter(|| { - use std::io::Write; + let mut rng = thread_rng(); - let mut file = std::fs::File::create(temp_file.path()).unwrap(); - file.write_all(CONTENT).unwrap(); - }) - }); + let mut file = NamedTempFile::new().unwrap(); + for _i in 0..FILE_SIZE { + let mut buffer = [0u8; BUFFER_SIZE]; + rng.fill_bytes(&mut buffer); + file.write_all(&buffer).unwrap(); + } + file.flush().unwrap(); + let path = file.into_temp_path(); - group.bench_function("tokio", |b| { - let runtime = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .unwrap(); - let temp_file = NamedTempFile::new().unwrap(); - b.to_async(&runtime).iter(|| async { - use tokio::io::AsyncWriteExt; - - let mut file = tokio::fs::File::create(temp_file.path()).await.unwrap(); - file.write_all(CONTENT).await.unwrap(); - }) - }); - - group.bench_function("compio", |b| { - let runtime = compio::runtime::Runtime::new().unwrap(); - let temp_file = NamedTempFile::new().unwrap(); - b.to_async(&runtime).iter(|| async { - use compio::io::AsyncWriteAtExt; - - let mut file = compio::fs::File::create(temp_file.path()).await.unwrap(); - file.write_all_at(CONTENT, 0).await.unwrap(); - }) - }); + let mut single_content = [0u8; BUFFER_SIZE]; + rng.fill_bytes(&mut single_content); + + let mut offsets = vec![]; + for _i in 0..64 { + let offset = rng.gen_range(0u64..FILE_SIZE) * BUFFER_SIZE as u64; + offsets.push(offset); + } + + let mut content = vec![]; + for _i in 0..WRITE_FILE_SIZE { + let mut buffer = [0u8; BUFFER_SIZE]; + rng.fill_bytes(&mut buffer); + content.extend_from_slice(&buffer); + } + + let mut group = c.benchmark_group("write"); + + group.bench_with_input::<_, _, (&Path, &[u64], &[u8])>( + "std-random", + &(&path, &offsets, &single_content), + write_std, + ); + group.bench_with_input::<_, _, (&Path, &[u64], &[u8])>( + "tokio-random", + &(&path, &offsets, &single_content), + write_tokio, + ); + group.bench_with_input::<_, _, (&Path, &[u64], &[u8])>( + "compio-random", + &(&path, &offsets, &single_content), + write_compio, + ); + group.bench_with_input::<_, _, (&Path, &[u64], &[u8])>( + "compio-random-join", + &(&path, &offsets, &single_content), + write_compio_join, + ); + + group.bench_with_input::<_, _, (&Path, &[u8])>("std-all", &(&path, &content), write_all_std); + group.bench_with_input::<_, _, (&Path, &[u8])>( + "compio-all", + &(&path, &content), + write_all_compio, + ); group.finish() } From 1fe9b6f79f6468dcb3495986868ea4982a876dab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Mon, 11 Mar 2024 23:35:36 +0800 Subject: [PATCH 2/9] fix(bench): reduce warnings --- compio/benches/fs.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compio/benches/fs.rs b/compio/benches/fs.rs index 735b3c41..2e0b305a 100644 --- a/compio/benches/fs.rs +++ b/compio/benches/fs.rs @@ -1,5 +1,7 @@ +#[cfg(windows)] +use std::io::Seek; use std::{ - io::{Read, Seek, SeekFrom, Write}, + io::{Read, SeekFrom, Write}, path::Path, }; @@ -199,6 +201,7 @@ fn read(c: &mut Criterion) { fn write_std(b: &mut Bencher, (path, offsets, content): &(&Path, &[u64], &[u8])) { b.iter(|| { + #[allow(unused_mut)] let mut file = std::fs::OpenOptions::new().write(true).open(path).unwrap(); for &offset in *offsets { #[cfg(windows)] From 98f9dfeb8857bc6068de488c86bddb98754212aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Tue, 12 Mar 2024 00:47:49 +0800 Subject: [PATCH 3/9] feat(bench): add monoio fs bench --- compio/Cargo.toml | 3 + compio/benches/fs.rs | 177 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) diff --git a/compio/Cargo.toml b/compio/Cargo.toml index d8704910..eda1b2dd 100644 --- a/compio/Cargo.toml +++ b/compio/Cargo.toml @@ -70,6 +70,9 @@ windows-sys = { workspace = true, features = ["Win32_Storage_FileSystem"] } nix = { workspace = true, features = ["fs"] } libc = { workspace = true } +[target.'cfg(target_os = "linux")'.dev-dependencies] +monoio = { version = "0.2.2", default-features = false, features = ["iouring"] } + [features] default = ["runtime", "io-uring"] io-uring = ["compio-driver/io-uring"] diff --git a/compio/benches/fs.rs b/compio/benches/fs.rs index 2e0b305a..d7d9fe6e 100644 --- a/compio/benches/fs.rs +++ b/compio/benches/fs.rs @@ -13,6 +13,23 @@ use rand::{thread_rng, Rng, RngCore}; use tempfile::NamedTempFile; use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt}; +#[cfg(target_os = "linux")] +struct MonoioRuntime(std::cell::RefCell>); + +#[cfg(target_os = "linux")] +impl criterion::async_executor::AsyncExecutor for MonoioRuntime { + fn block_on(&self, future: impl futures_util::Future) -> T { + self.0.borrow_mut().block_on(future) + } +} + +#[cfg(target_os = "linux")] +impl criterion::async_executor::AsyncExecutor for &MonoioRuntime { + fn block_on(&self, future: impl futures_util::Future) -> T { + self.0.borrow_mut().block_on(future) + } +} + criterion_group!(fs, read, write); criterion_main!(fs); @@ -84,6 +101,25 @@ fn read_compio_join(b: &mut Bencher, (path, offsets): &(&Path, &[u64])) { }) } +#[cfg(target_os = "linux")] +fn read_monoio(b: &mut Bencher, (path, offsets): &(&Path, &[u64])) { + let runtime = MonoioRuntime(std::cell::RefCell::new( + monoio::RuntimeBuilder::::new() + .build() + .unwrap(), + )); + b.to_async(&runtime).iter(|| async { + let file = monoio::fs::File::open(path).await.unwrap(); + let mut buffer = Box::new([0u8; BUFFER_SIZE]); + for &offset in *offsets { + let res; + (res, buffer) = file.read_exact_at(buffer, offset).await; + res.unwrap(); + } + buffer + }) +} + fn read_all_std(b: &mut Bencher, (path, len): &(&Path, u64)) { b.iter(|| { let mut file = std::fs::File::open(path).unwrap(); @@ -148,6 +184,27 @@ fn read_all_compio_join(b: &mut Bencher, (path, len): &(&Path, u64)) { }) } +#[cfg(target_os = "linux")] +fn read_all_monoio(b: &mut Bencher, (path, len): &(&Path, u64)) { + let runtime = MonoioRuntime(std::cell::RefCell::new( + monoio::RuntimeBuilder::::new() + .build() + .unwrap(), + )); + b.to_async(&runtime).iter(|| async { + let file = monoio::fs::File::open(path).await.unwrap(); + let mut buffer = Box::new([0u8; BUFFER_SIZE]); + let mut read_len = 0; + while read_len < *len { + let res; + (res, buffer) = file.read_exact_at(buffer, read_len).await; + res.unwrap(); + read_len += BUFFER_SIZE as u64; + } + buffer + }) +} + fn read(c: &mut Criterion) { const FILE_SIZE: u64 = 1024; @@ -182,6 +239,12 @@ fn read(c: &mut Criterion) { &(&path, &offsets), read_compio_join, ); + #[cfg(target_os = "linux")] + group.bench_with_input::<_, _, (&Path, &[u64])>( + "monoio-random", + &(&path, &offsets), + read_monoio, + ); group.bench_with_input::<_, _, (&Path, u64)>("std-all", &(&path, FILE_SIZE), read_all_std); group.bench_with_input::<_, _, (&Path, u64)>("tokio-all", &(&path, FILE_SIZE), read_all_tokio); @@ -195,6 +258,12 @@ fn read(c: &mut Criterion) { &(&path, FILE_SIZE), read_all_compio_join, ); + #[cfg(target_os = "linux")] + group.bench_with_input::<_, _, (&Path, u64)>( + "monoio-all", + &(&path, FILE_SIZE), + read_all_monoio, + ); group.finish(); } @@ -276,6 +345,65 @@ fn write_compio_join(b: &mut Bencher, (path, offsets, content): &(&Path, &[u64], }) } +#[cfg(target_os = "linux")] +fn write_monoio(b: &mut Bencher, (path, offsets, content): &(&Path, &[u64], &[u8])) { + let runtime = MonoioRuntime(std::cell::RefCell::new( + monoio::RuntimeBuilder::::new() + .build() + .unwrap(), + )); + let content = content.to_vec(); + b.to_async(&runtime).iter(|| { + let mut content = content.clone(); + async { + let file = monoio::fs::OpenOptions::new() + .write(true) + .open(path) + .await + .unwrap(); + for &offset in *offsets { + let res; + (res, content) = file.write_all_at(content, offset).await; + res.unwrap(); + } + } + }) +} + +#[cfg(target_os = "linux")] +fn write_monoio_join(b: &mut Bencher, (path, offsets, content): &(&Path, &[u64], &[u8])) { + let runtime = MonoioRuntime(std::cell::RefCell::new( + monoio::RuntimeBuilder::::new() + .build() + .unwrap(), + )); + let content = content.to_vec(); + b.to_async(&runtime).iter(|| { + let content = content.clone(); + async move { + let file = monoio::fs::OpenOptions::new() + .write(true) + .open(path) + .await + .unwrap(); + offsets + .iter() + .map(|offset| { + let file = &file; + let content = content.clone(); + async move { + let (res, content) = file.write_all_at(content, *offset).await; + res.unwrap(); + content + } + }) + .collect::>() + .collect::>() + .await + } + }) +} + fn write_all_std(b: &mut Bencher, (path, content): &(&Path, &[u8])) { b.iter(|| { let mut file = std::fs::File::create(path).unwrap(); @@ -308,6 +436,37 @@ fn write_all_compio(b: &mut Bencher, (path, content): &(&Path, &[u8])) { }) } +#[cfg(target_os = "linux")] +fn write_all_monoio(b: &mut Bencher, (path, content): &(&Path, &[u8])) { + let runtime = MonoioRuntime(std::cell::RefCell::new( + monoio::RuntimeBuilder::::new() + .build() + .unwrap(), + )); + let content = content.to_vec(); + b.to_async(&runtime).iter(|| { + let mut content = content.clone(); + async { + let file = monoio::fs::File::create(path).await.unwrap(); + let mut write_len = 0; + while write_len < content.len() as u64 { + let (res, slice) = file + .write_all_at( + monoio::buf::IoBuf::slice( + content, + write_len as usize..write_len as usize + BUFFER_SIZE, + ), + write_len, + ) + .await; + res.unwrap(); + write_len += BUFFER_SIZE as u64; + content = slice.into_inner(); + } + } + }) +} + fn write(c: &mut Criterion) { const FILE_SIZE: u64 = 1024; const WRITE_FILE_SIZE: u64 = 16; @@ -361,6 +520,18 @@ fn write(c: &mut Criterion) { &(&path, &offsets, &single_content), write_compio_join, ); + #[cfg(target_os = "linux")] + group.bench_with_input::<_, _, (&Path, &[u64], &[u8])>( + "monoio-random", + &(&path, &offsets, &single_content), + write_monoio, + ); + #[cfg(target_os = "linux")] + group.bench_with_input::<_, _, (&Path, &[u64], &[u8])>( + "monoio-random-join", + &(&path, &offsets, &single_content), + write_monoio_join, + ); group.bench_with_input::<_, _, (&Path, &[u8])>("std-all", &(&path, &content), write_all_std); group.bench_with_input::<_, _, (&Path, &[u8])>( @@ -368,6 +539,12 @@ fn write(c: &mut Criterion) { &(&path, &content), write_all_compio, ); + #[cfg(target_os = "linux")] + group.bench_with_input::<_, _, (&Path, &[u8])>( + "monoio-all", + &(&path, &content), + write_all_monoio, + ); group.finish() } From 3e502797c8dce853bb72e47d5cb0567125f3aa45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Tue, 12 Mar 2024 01:55:34 +0800 Subject: [PATCH 4/9] fix(bench): move file open out of bench --- compio/benches/fs.rs | 388 ++++++++++++++++++++++++------------------- 1 file changed, 220 insertions(+), 168 deletions(-) diff --git a/compio/benches/fs.rs b/compio/benches/fs.rs index d7d9fe6e..aad4f7e3 100644 --- a/compio/benches/fs.rs +++ b/compio/benches/fs.rs @@ -1,12 +1,12 @@ -#[cfg(windows)] -use std::io::Seek; use std::{ - io::{Read, SeekFrom, Write}, + hint::black_box, + io::{Read, Seek, SeekFrom, Write}, path::Path, + time::Instant, }; use compio_buf::{IntoInner, IoBuf}; -use compio_io::{AsyncReadAtExt, AsyncWriteAtExt}; +use compio_io::{AsyncReadAt, AsyncWriteAt}; use criterion::{criterion_group, criterion_main, Bencher, Criterion}; use futures_util::{stream::FuturesUnordered, StreamExt}; use rand::{thread_rng, Rng, RngCore}; @@ -36,20 +36,19 @@ criterion_main!(fs); const BUFFER_SIZE: usize = 4096; fn read_std(b: &mut Bencher, (path, offsets): &(&Path, &[u64])) { + let file = std::fs::File::open(path).unwrap(); b.iter(|| { - #[allow(unused_mut)] - let mut file = std::fs::File::open(path).unwrap(); let mut buffer = [0u8; BUFFER_SIZE]; for &offset in *offsets { #[cfg(windows)] { - file.seek(SeekFrom::Start(offset)).unwrap(); - file.read_exact(&mut buffer).unwrap(); + use std::os::windows::fs::FileExt; + file.seek_read(&mut buffer, offset).unwrap(); } #[cfg(unix)] { use std::os::unix::fs::FileExt; - file.read_exact_at(&mut buffer, offset).unwrap(); + file.read_at(&mut buffer, offset).unwrap(); } } buffer @@ -61,43 +60,59 @@ fn read_tokio(b: &mut Bencher, (path, offsets): &(&Path, &[u64])) { .enable_all() .build() .unwrap(); - b.to_async(&runtime).iter(|| async { + b.to_async(&runtime).iter_custom(|iter| async move { let mut file = tokio::fs::File::open(path).await.unwrap(); - let mut buffer = [0u8; BUFFER_SIZE]; - for &offset in *offsets { - file.seek(SeekFrom::Start(offset)).await.unwrap(); - file.read_exact(&mut buffer).await.unwrap(); + + let start = Instant::now(); + for _i in 0..iter { + let mut buffer = [0u8; BUFFER_SIZE]; + for &offset in *offsets { + file.seek(SeekFrom::Start(offset)).await.unwrap(); + _ = file.read(&mut buffer).await.unwrap(); + } + black_box(buffer); } - buffer + start.elapsed() }) } fn read_compio(b: &mut Bencher, (path, offsets): &(&Path, &[u64])) { let runtime = compio::runtime::Runtime::new().unwrap(); - b.to_async(&runtime).iter(|| async { + b.to_async(&runtime).iter_custom(|iter| async move { let file = compio::fs::File::open(path).await.unwrap(); - let mut buffer = [0u8; BUFFER_SIZE]; - for &offset in *offsets { - (_, buffer) = file.read_exact_at(buffer, offset).await.unwrap(); + + let start = Instant::now(); + for _i in 0..iter { + let mut buffer = [0u8; BUFFER_SIZE]; + for &offset in *offsets { + (_, buffer) = file.read_at(buffer, offset).await.unwrap(); + } + black_box(buffer); } - buffer + start.elapsed() }) } fn read_compio_join(b: &mut Bencher, (path, offsets): &(&Path, &[u64])) { let runtime = compio::runtime::Runtime::new().unwrap(); - b.to_async(&runtime).iter(|| async { + b.to_async(&runtime).iter_custom(|iter| async move { let file = compio::fs::File::open(path).await.unwrap(); - offsets - .iter() - .map(|offset| async { - let buffer = [0u8; BUFFER_SIZE]; - let (_, buffer) = file.read_exact_at(buffer, *offset).await.unwrap(); - buffer - }) - .collect::>() - .collect::>() - .await + + let start = Instant::now(); + for _i in 0..iter { + let res = offsets + .iter() + .map(|offset| async { + let buffer = [0u8; BUFFER_SIZE]; + let (_, buffer) = file.read_at(buffer, *offset).await.unwrap(); + buffer + }) + .collect::>() + .collect::>() + .await; + black_box(res); + } + start.elapsed() }) } @@ -108,26 +123,32 @@ fn read_monoio(b: &mut Bencher, (path, offsets): &(&Path, &[u64])) { .build() .unwrap(), )); - b.to_async(&runtime).iter(|| async { + b.to_async(&runtime).iter_custom(|iter| async move { let file = monoio::fs::File::open(path).await.unwrap(); - let mut buffer = Box::new([0u8; BUFFER_SIZE]); - for &offset in *offsets { - let res; - (res, buffer) = file.read_exact_at(buffer, offset).await; - res.unwrap(); + + let start = Instant::now(); + for _i in 0..iter { + let mut buffer = Box::new([0u8; BUFFER_SIZE]); + for &offset in *offsets { + let res; + (res, buffer) = file.read_at(buffer, offset).await; + res.unwrap(); + } + black_box(buffer); } - buffer + start.elapsed() }) } fn read_all_std(b: &mut Bencher, (path, len): &(&Path, u64)) { + let mut file = std::fs::File::open(path).unwrap(); b.iter(|| { - let mut file = std::fs::File::open(path).unwrap(); let mut buffer = [0u8; BUFFER_SIZE]; let mut read_len = 0; + file.seek(SeekFrom::Start(0)).unwrap(); while read_len < *len { - file.read_exact(&mut buffer).unwrap(); - read_len += BUFFER_SIZE as u64; + let read = file.read(&mut buffer).unwrap(); + read_len += read as u64; } buffer }) @@ -138,49 +159,39 @@ fn read_all_tokio(b: &mut Bencher, (path, len): &(&Path, u64)) { .enable_all() .build() .unwrap(); - b.to_async(&runtime).iter(|| async { + b.to_async(&runtime).iter_custom(|iter| async move { let mut file = tokio::fs::File::open(path).await.unwrap(); let mut buffer = [0u8; BUFFER_SIZE]; - let mut read_len = 0; - while read_len < *len { - file.read_exact(&mut buffer).await.unwrap(); - read_len += BUFFER_SIZE as u64; + + let start = Instant::now(); + for _i in 0..iter { + let mut read_len = 0; + file.seek(SeekFrom::Start(0)).await.unwrap(); + while read_len < *len { + let read = file.read(&mut buffer).await.unwrap(); + read_len += read as u64; + } } - buffer + start.elapsed() }) } fn read_all_compio(b: &mut Bencher, (path, len): &(&Path, u64)) { let runtime = compio::runtime::Runtime::new().unwrap(); - b.to_async(&runtime).iter(|| async { + b.to_async(&runtime).iter_custom(|iter| async move { let file = compio::fs::File::open(path).await.unwrap(); let mut buffer = [0u8; BUFFER_SIZE]; - let mut read_len = 0; - while read_len < *len { - (_, buffer) = file.read_exact_at(buffer, read_len).await.unwrap(); - read_len += BUFFER_SIZE as u64; - } - buffer - }) -} -fn read_all_compio_join(b: &mut Bencher, (path, len): &(&Path, u64)) { - let runtime = compio::runtime::Runtime::new().unwrap(); - b.to_async(&runtime).iter(|| async { - let file = compio::fs::File::open(path).await.unwrap(); - let tasks = len / BUFFER_SIZE as u64; - (0..tasks) - .map(|offset| { - let file = &file; - async move { - let buffer = [0u8; BUFFER_SIZE]; - let (_, buffer) = file.read_exact_at(buffer, offset).await.unwrap(); - buffer - } - }) - .collect::>() - .collect::>() - .await + let start = Instant::now(); + for _i in 0..iter { + let mut read_len = 0; + while read_len < *len { + let read; + (read, buffer) = file.read_at(buffer, read_len).await.unwrap(); + read_len += read as u64; + } + } + start.elapsed() }) } @@ -191,17 +202,20 @@ fn read_all_monoio(b: &mut Bencher, (path, len): &(&Path, u64)) { .build() .unwrap(), )); - b.to_async(&runtime).iter(|| async { + b.to_async(&runtime).iter_custom(|iter| async move { let file = monoio::fs::File::open(path).await.unwrap(); let mut buffer = Box::new([0u8; BUFFER_SIZE]); - let mut read_len = 0; - while read_len < *len { - let res; - (res, buffer) = file.read_exact_at(buffer, read_len).await; - res.unwrap(); - read_len += BUFFER_SIZE as u64; + + let start = Instant::now(); + for _i in 0..iter { + let mut read_len = 0; + while read_len < *len { + let read; + (read, buffer) = file.read_at(buffer, read_len).await; + read_len += read.unwrap() as u64; + } } - buffer + start.elapsed() }) } @@ -253,11 +267,6 @@ fn read(c: &mut Criterion) { &(&path, FILE_SIZE), read_all_compio, ); - group.bench_with_input::<_, _, (&Path, u64)>( - "compio-all-join", - &(&path, FILE_SIZE), - read_all_compio_join, - ); #[cfg(target_os = "linux")] group.bench_with_input::<_, _, (&Path, u64)>( "monoio-all", @@ -269,19 +278,18 @@ fn read(c: &mut Criterion) { } fn write_std(b: &mut Bencher, (path, offsets, content): &(&Path, &[u64], &[u8])) { + let file = std::fs::OpenOptions::new().write(true).open(path).unwrap(); b.iter(|| { - #[allow(unused_mut)] - let mut file = std::fs::OpenOptions::new().write(true).open(path).unwrap(); for &offset in *offsets { #[cfg(windows)] { - file.seek(SeekFrom::Start(offset)).unwrap(); - file.write_all(content).unwrap(); + use std::os::windows::fs::FileExt; + file.seek_write(content, offset).unwrap(); } #[cfg(unix)] { use std::os::unix::fs::FileExt; - file.write_all_at(content, offset).unwrap(); + file.write_at(content, offset).unwrap(); } } }) @@ -292,33 +300,43 @@ fn write_tokio(b: &mut Bencher, (path, offsets, content): &(&Path, &[u64], &[u8] .enable_all() .build() .unwrap(); - b.to_async(&runtime).iter(|| async { + b.to_async(&runtime).iter_custom(|iter| async move { let mut file = tokio::fs::OpenOptions::new() .write(true) .open(path) .await .unwrap(); - for &offset in *offsets { - file.seek(SeekFrom::Start(offset)).await.unwrap(); - file.write_all(content).await.unwrap(); + + let start = Instant::now(); + for _i in 0..iter { + for &offset in *offsets { + file.seek(SeekFrom::Start(offset)).await.unwrap(); + _ = file.write(content).await.unwrap(); + } } + start.elapsed() }) } fn write_compio(b: &mut Bencher, (path, offsets, content): &(&Path, &[u64], &[u8])) { let runtime = compio::runtime::Runtime::new().unwrap(); let content = content.to_vec(); - b.to_async(&runtime).iter(|| { + b.to_async(&runtime).iter_custom(|iter| { let mut content = content.clone(); - async { + async move { let mut file = compio::fs::OpenOptions::new() .write(true) .open(path) .await .unwrap(); - for &offset in *offsets { - (_, content) = file.write_all_at(content, offset).await.unwrap(); + + let start = Instant::now(); + for _i in 0..iter { + for &offset in *offsets { + (_, content) = file.write_at(content, offset).await.unwrap(); + } } + start.elapsed() } }) } @@ -326,22 +344,31 @@ fn write_compio(b: &mut Bencher, (path, offsets, content): &(&Path, &[u64], &[u8 fn write_compio_join(b: &mut Bencher, (path, offsets, content): &(&Path, &[u64], &[u8])) { let runtime = compio::runtime::Runtime::new().unwrap(); let content = content.to_vec(); - b.to_async(&runtime).iter(|| async { - let file = compio::fs::OpenOptions::new() - .write(true) - .open(path) - .await - .unwrap(); - offsets - .iter() - .map(|offset| { - let mut file = &file; - let content = content.clone(); - async move { file.write_all_at(content, *offset).await.unwrap() } - }) - .collect::>() - .collect::>() - .await + b.to_async(&runtime).iter_custom(|iter| { + let content = content.clone(); + async move { + let file = compio::fs::OpenOptions::new() + .write(true) + .open(path) + .await + .unwrap(); + + let start = Instant::now(); + for _i in 0..iter { + let res = offsets + .iter() + .map(|offset| { + let mut file = &file; + let content = content.clone(); + async move { file.write_at(content, *offset).await.unwrap() } + }) + .collect::>() + .collect::>() + .await; + black_box(res); + } + start.elapsed() + } }) } @@ -353,19 +380,24 @@ fn write_monoio(b: &mut Bencher, (path, offsets, content): &(&Path, &[u64], &[u8 .unwrap(), )); let content = content.to_vec(); - b.to_async(&runtime).iter(|| { + b.to_async(&runtime).iter_custom(|iter| { let mut content = content.clone(); - async { + async move { let file = monoio::fs::OpenOptions::new() .write(true) .open(path) .await .unwrap(); - for &offset in *offsets { - let res; - (res, content) = file.write_all_at(content, offset).await; - res.unwrap(); + + let start = Instant::now(); + for _i in 0..iter { + for &offset in *offsets { + let res; + (res, content) = file.write_at(content, offset).await; + res.unwrap(); + } } + start.elapsed() } }) } @@ -378,7 +410,7 @@ fn write_monoio_join(b: &mut Bencher, (path, offsets, content): &(&Path, &[u64], .unwrap(), )); let content = content.to_vec(); - b.to_async(&runtime).iter(|| { + b.to_async(&runtime).iter_custom(|iter| { let content = content.clone(); async move { let file = monoio::fs::OpenOptions::new() @@ -386,29 +418,40 @@ fn write_monoio_join(b: &mut Bencher, (path, offsets, content): &(&Path, &[u64], .open(path) .await .unwrap(); - offsets - .iter() - .map(|offset| { - let file = &file; - let content = content.clone(); - async move { - let (res, content) = file.write_all_at(content, *offset).await; - res.unwrap(); - content - } - }) - .collect::>() - .collect::>() - .await + + let start = Instant::now(); + for _i in 0..iter { + let res = offsets + .iter() + .map(|offset| { + let file = &file; + let content = content.clone(); + async move { + let (res, content) = file.write_at(content, *offset).await; + res.unwrap(); + content + } + }) + .collect::>() + .collect::>() + .await; + black_box(res); + } + start.elapsed() } }) } fn write_all_std(b: &mut Bencher, (path, content): &(&Path, &[u8])) { + let mut file = std::fs::File::create(path).unwrap(); b.iter(|| { - let mut file = std::fs::File::create(path).unwrap(); - for buffer in content.windows(BUFFER_SIZE) { - file.write_all(buffer).unwrap(); + file.seek(SeekFrom::Start(0)).unwrap(); + let mut write_len = 0; + while write_len < content.len() { + let write = file + .write(&content[write_len..write_len + BUFFER_SIZE]) + .unwrap(); + write_len += write; } }) } @@ -416,22 +459,27 @@ fn write_all_std(b: &mut Bencher, (path, content): &(&Path, &[u8])) { fn write_all_compio(b: &mut Bencher, (path, content): &(&Path, &[u8])) { let runtime = compio::runtime::Runtime::new().unwrap(); let content = content.to_vec(); - b.to_async(&runtime).iter(|| { + b.to_async(&runtime).iter_custom(|iter| { let mut content = content.clone(); - async { + async move { let mut file = compio::fs::File::create(path).await.unwrap(); - let mut write_len = 0; - while write_len < content.len() as u64 { - let (_, slice) = file - .write_all_at( - content.slice(write_len as usize..write_len as usize + BUFFER_SIZE), - write_len, - ) - .await - .unwrap(); - write_len += BUFFER_SIZE as u64; - content = slice.into_inner(); + + let start = Instant::now(); + for _i in 0..iter { + let mut write_len = 0; + while write_len < content.len() as u64 { + let (write, slice) = file + .write_at( + content.slice(write_len as usize..write_len as usize + BUFFER_SIZE), + write_len, + ) + .await + .unwrap(); + write_len += write as u64; + content = slice.into_inner(); + } } + start.elapsed() } }) } @@ -444,25 +492,29 @@ fn write_all_monoio(b: &mut Bencher, (path, content): &(&Path, &[u8])) { .unwrap(), )); let content = content.to_vec(); - b.to_async(&runtime).iter(|| { + b.to_async(&runtime).iter_custom(|iter| { let mut content = content.clone(); - async { + async move { let file = monoio::fs::File::create(path).await.unwrap(); - let mut write_len = 0; - while write_len < content.len() as u64 { - let (res, slice) = file - .write_all_at( - monoio::buf::IoBuf::slice( - content, - write_len as usize..write_len as usize + BUFFER_SIZE, - ), - write_len, - ) - .await; - res.unwrap(); - write_len += BUFFER_SIZE as u64; - content = slice.into_inner(); + + let start = Instant::now(); + for _i in 0..iter { + let mut write_len = 0; + while write_len < content.len() as u64 { + let (write, slice) = file + .write_at( + monoio::buf::IoBuf::slice( + content, + write_len as usize..write_len as usize + BUFFER_SIZE, + ), + write_len, + ) + .await; + write_len += write.unwrap() as u64; + content = slice.into_inner(); + } } + start.elapsed() } }) } From bf2e4353dfd6b6c28ce9a6bd8ff46db701bdd5a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Tue, 12 Mar 2024 02:03:56 +0800 Subject: [PATCH 5/9] fix(bench): correct write_all --- compio/benches/fs.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/compio/benches/fs.rs b/compio/benches/fs.rs index aad4f7e3..dd4b6e80 100644 --- a/compio/benches/fs.rs +++ b/compio/benches/fs.rs @@ -447,9 +447,10 @@ fn write_all_std(b: &mut Bencher, (path, content): &(&Path, &[u8])) { b.iter(|| { file.seek(SeekFrom::Start(0)).unwrap(); let mut write_len = 0; - while write_len < content.len() { + let total_len = content.len(); + while write_len < total_len { let write = file - .write(&content[write_len..write_len + BUFFER_SIZE]) + .write(&content[write_len..(write_len + BUFFER_SIZE).min(total_len)]) .unwrap(); write_len += write; } @@ -467,10 +468,14 @@ fn write_all_compio(b: &mut Bencher, (path, content): &(&Path, &[u8])) { let start = Instant::now(); for _i in 0..iter { let mut write_len = 0; - while write_len < content.len() as u64 { + let total_len = content.len(); + while write_len < total_len as u64 { let (write, slice) = file .write_at( - content.slice(write_len as usize..write_len as usize + BUFFER_SIZE), + content.slice( + write_len as usize + ..(write_len as usize + BUFFER_SIZE).min(total_len), + ), write_len, ) .await @@ -500,12 +505,14 @@ fn write_all_monoio(b: &mut Bencher, (path, content): &(&Path, &[u8])) { let start = Instant::now(); for _i in 0..iter { let mut write_len = 0; - while write_len < content.len() as u64 { + let total_len = content.len(); + while write_len < total_len as u64 { let (write, slice) = file .write_at( monoio::buf::IoBuf::slice( content, - write_len as usize..write_len as usize + BUFFER_SIZE, + write_len as usize + ..(write_len as usize + BUFFER_SIZE).min(total_len), ), write_len, ) From 3986e273907cf2a25c2384bb849db8730dd7a21a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Tue, 12 Mar 2024 17:15:45 +0800 Subject: [PATCH 6/9] feat(bench): add throughput for read-all & write-all --- compio/benches/fs.rs | 76 ++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 45 deletions(-) diff --git a/compio/benches/fs.rs b/compio/benches/fs.rs index dd4b6e80..b4ed046b 100644 --- a/compio/benches/fs.rs +++ b/compio/benches/fs.rs @@ -7,7 +7,7 @@ use std::{ use compio_buf::{IntoInner, IoBuf}; use compio_io::{AsyncReadAt, AsyncWriteAt}; -use criterion::{criterion_group, criterion_main, Bencher, Criterion}; +use criterion::{criterion_group, criterion_main, Bencher, Criterion, Throughput}; use futures_util::{stream::FuturesUnordered, StreamExt}; use rand::{thread_rng, Rng, RngCore}; use tempfile::NamedTempFile; @@ -239,40 +239,29 @@ fn read(c: &mut Criterion) { offsets.push(offset); } - let mut group = c.benchmark_group("read"); + let mut group = c.benchmark_group("read-random"); - group.bench_with_input::<_, _, (&Path, &[u64])>("std-random", &(&path, &offsets), read_std); - group.bench_with_input::<_, _, (&Path, &[u64])>("tokio-random", &(&path, &offsets), read_tokio); + group.bench_with_input::<_, _, (&Path, &[u64])>("std", &(&path, &offsets), read_std); + group.bench_with_input::<_, _, (&Path, &[u64])>("tokio", &(&path, &offsets), read_tokio); + group.bench_with_input::<_, _, (&Path, &[u64])>("compio", &(&path, &offsets), read_compio); group.bench_with_input::<_, _, (&Path, &[u64])>( - "compio-random", - &(&path, &offsets), - read_compio, - ); - group.bench_with_input::<_, _, (&Path, &[u64])>( - "compio-random-join", + "compio-join", &(&path, &offsets), read_compio_join, ); #[cfg(target_os = "linux")] - group.bench_with_input::<_, _, (&Path, &[u64])>( - "monoio-random", - &(&path, &offsets), - read_monoio, - ); + group.bench_with_input::<_, _, (&Path, &[u64])>("monoio", &(&path, &offsets), read_monoio); - group.bench_with_input::<_, _, (&Path, u64)>("std-all", &(&path, FILE_SIZE), read_all_std); - group.bench_with_input::<_, _, (&Path, u64)>("tokio-all", &(&path, FILE_SIZE), read_all_tokio); - group.bench_with_input::<_, _, (&Path, u64)>( - "compio-all", - &(&path, FILE_SIZE), - read_all_compio, - ); + group.finish(); + + let mut group = c.benchmark_group("read-all"); + group.throughput(Throughput::Bytes(FILE_SIZE * BUFFER_SIZE as u64)); + + group.bench_with_input::<_, _, (&Path, u64)>("std", &(&path, FILE_SIZE), read_all_std); + group.bench_with_input::<_, _, (&Path, u64)>("tokio", &(&path, FILE_SIZE), read_all_tokio); + group.bench_with_input::<_, _, (&Path, u64)>("compio", &(&path, FILE_SIZE), read_all_compio); #[cfg(target_os = "linux")] - group.bench_with_input::<_, _, (&Path, u64)>( - "monoio-all", - &(&path, FILE_SIZE), - read_all_monoio, - ); + group.bench_with_input::<_, _, (&Path, u64)>("monoio", &(&path, FILE_SIZE), read_all_monoio); group.finish(); } @@ -557,53 +546,50 @@ fn write(c: &mut Criterion) { content.extend_from_slice(&buffer); } - let mut group = c.benchmark_group("write"); + let mut group = c.benchmark_group("write-random"); group.bench_with_input::<_, _, (&Path, &[u64], &[u8])>( - "std-random", + "std", &(&path, &offsets, &single_content), write_std, ); group.bench_with_input::<_, _, (&Path, &[u64], &[u8])>( - "tokio-random", + "tokio", &(&path, &offsets, &single_content), write_tokio, ); group.bench_with_input::<_, _, (&Path, &[u64], &[u8])>( - "compio-random", + "compio", &(&path, &offsets, &single_content), write_compio, ); group.bench_with_input::<_, _, (&Path, &[u64], &[u8])>( - "compio-random-join", + "compio-join", &(&path, &offsets, &single_content), write_compio_join, ); #[cfg(target_os = "linux")] group.bench_with_input::<_, _, (&Path, &[u64], &[u8])>( - "monoio-random", + "monoio", &(&path, &offsets, &single_content), write_monoio, ); #[cfg(target_os = "linux")] group.bench_with_input::<_, _, (&Path, &[u64], &[u8])>( - "monoio-random-join", + "monoio-join", &(&path, &offsets, &single_content), write_monoio_join, ); - group.bench_with_input::<_, _, (&Path, &[u8])>("std-all", &(&path, &content), write_all_std); - group.bench_with_input::<_, _, (&Path, &[u8])>( - "compio-all", - &(&path, &content), - write_all_compio, - ); + group.finish(); + + let mut group = c.benchmark_group("write-all"); + group.throughput(Throughput::Bytes(content.len() as _)); + + group.bench_with_input::<_, _, (&Path, &[u8])>("std", &(&path, &content), write_all_std); + group.bench_with_input::<_, _, (&Path, &[u8])>("compio", &(&path, &content), write_all_compio); #[cfg(target_os = "linux")] - group.bench_with_input::<_, _, (&Path, &[u8])>( - "monoio-all", - &(&path, &content), - write_all_monoio, - ); + group.bench_with_input::<_, _, (&Path, &[u8])>("monoio", &(&path, &content), write_all_monoio); group.finish() } From 74cad2d6a2e09a9a27c4fe2a1392128e1203e30b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Tue, 12 Mar 2024 17:20:04 +0800 Subject: [PATCH 7/9] feat(bench): readd write-all/tokio --- compio/benches/fs.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/compio/benches/fs.rs b/compio/benches/fs.rs index b4ed046b..0c2be682 100644 --- a/compio/benches/fs.rs +++ b/compio/benches/fs.rs @@ -446,6 +446,31 @@ fn write_all_std(b: &mut Bencher, (path, content): &(&Path, &[u8])) { }) } +fn write_all_tokio(b: &mut Bencher, (path, content): &(&Path, &[u8])) { + let runtime = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + b.to_async(&runtime).iter_custom(|iter| async move { + let mut file = tokio::fs::File::create(path).await.unwrap(); + + let start = Instant::now(); + for _i in 0..iter { + file.seek(SeekFrom::Start(0)).await.unwrap(); + let mut write_len = 0; + let total_len = content.len(); + while write_len < total_len { + let write = file + .write(&content[write_len..(write_len + BUFFER_SIZE).min(total_len)]) + .await + .unwrap(); + write_len += write; + } + } + start.elapsed() + }) +} + fn write_all_compio(b: &mut Bencher, (path, content): &(&Path, &[u8])) { let runtime = compio::runtime::Runtime::new().unwrap(); let content = content.to_vec(); @@ -587,6 +612,7 @@ fn write(c: &mut Criterion) { group.throughput(Throughput::Bytes(content.len() as _)); group.bench_with_input::<_, _, (&Path, &[u8])>("std", &(&path, &content), write_all_std); + group.bench_with_input::<_, _, (&Path, &[u8])>("tokio", &(&path, &content), write_all_tokio); group.bench_with_input::<_, _, (&Path, &[u8])>("compio", &(&path, &content), write_all_compio); #[cfg(target_os = "linux")] group.bench_with_input::<_, _, (&Path, &[u8])>("monoio", &(&path, &content), write_all_monoio); From 68e1c93245d64c98a354116fb0825c41245bc0ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Tue, 12 Mar 2024 17:27:17 +0800 Subject: [PATCH 8/9] feat(bench): use real_blackbox --- compio/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compio/Cargo.toml b/compio/Cargo.toml index eda1b2dd..5b3d9683 100644 --- a/compio/Cargo.toml +++ b/compio/Cargo.toml @@ -48,7 +48,7 @@ compio-buf = { workspace = true, features = ["bumpalo"] } compio-runtime = { workspace = true, features = ["criterion"] } compio-macros = { workspace = true } -criterion = { workspace = true, features = ["async_tokio"] } +criterion = { workspace = true, features = ["async_tokio", "real_blackbox"] } futures-channel = { workspace = true } futures-util = { workspace = true } rand = "0.8.5" From 2f2898ccee185d58e003f383d7eab294098ed02b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Tue, 12 Mar 2024 17:46:22 +0800 Subject: [PATCH 9/9] fix(bench): don't enable read_blackbox by default --- compio/Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compio/Cargo.toml b/compio/Cargo.toml index 5b3d9683..5d8c7753 100644 --- a/compio/Cargo.toml +++ b/compio/Cargo.toml @@ -48,7 +48,7 @@ compio-buf = { workspace = true, features = ["bumpalo"] } compio-runtime = { workspace = true, features = ["criterion"] } compio-macros = { workspace = true } -criterion = { workspace = true, features = ["async_tokio", "real_blackbox"] } +criterion = { workspace = true, features = ["async_tokio"] } futures-channel = { workspace = true } futures-util = { workspace = true } rand = "0.8.5" @@ -120,6 +120,8 @@ nightly = [ "try_trait_v2", ] +real_blackbox = ["criterion/real_blackbox"] + [[example]] name = "basic" required-features = ["macros"]