Skip to content

Commit

Permalink
benchmark: add read & write benchmark and tokio fs unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
KKould committed Sep 27, 2024
1 parent 317b1b0 commit f566fa1
Show file tree
Hide file tree
Showing 9 changed files with 414 additions and 10 deletions.
30 changes: 30 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

version: 2
updates:
# Maintain dependencies for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"

# Maintain dependencies for rust
- package-ecosystem: "cargo"
directory: "/"
schedule:
interval: "monthly"
108 changes: 108 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
name: CI

on:
push:
pull_request:
workflow_dispatch:

env:
CARGO_TERM_COLOR: always
CARGO_REGISTRIES_MY_REGISTRY_INDEX: https://github.com/rust-lang/crates.io-index

jobs:
# 1
tokio_check:
name: Rust project check on tokio
runs-on: ${{ matrix.os }}
strategy:
matrix:
os:
- ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install latest
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
components: rustfmt, clippy

# `cargo check` command here will use installed `nightly`
# as it is set as an "override" for current directory

- name: Run cargo clippy on tokio
uses: actions-rs/cargo@v1
with:
command: check
args: --package fusio --features "tokio, futures"

- name: Run cargo build on tokio
uses: actions-rs/cargo@v1
with:
command: build
args: --package fusio --features "tokio, futures"

- name: Run cargo test on tokio
uses: actions-rs/cargo@v1
with:
command: test
args: --package fusio --features "tokio, futures"

monoio_check:
name: Rust project check on monoio
runs-on: ${{ matrix.os }}
strategy:
matrix:
os:
- ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install latest
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
components: rustfmt, clippy

# `cargo check` command here will use installed `nightly`
# as it is set as an "override" for current directory

- name: Run cargo clippy on monoio
uses: actions-rs/cargo@v1
with:
command: check
args: --package fusio --features "monoio, futures"

- name: Run cargo build on monoio
uses: actions-rs/cargo@v1
with:
command: build
args: --package fusio --features "monoio, futures"

- name: Run cargo test on monoio
uses: actions-rs/cargo@v1
with:
command: test
args: --package fusio --features "monoio, futures"

# 2
fmt:
name: Rust fmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install latest nightly
uses: actions-rs/toolchain@v1
with:
toolchain: nightly
override: true
components: rustfmt, clippy

# `cargo check` command here will use installed `nightly`
# as it is set as an "override" for current directory

- name: Run cargo fmt
uses: actions-rs/cargo@v1
with:
command: fmt
args: -- --check
9 changes: 8 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ repository = "https://github.com/tonbo-io/fusio"
[workspace.dependencies]
bytes = { version = "1.7" }

[profile.bench]
[target.'cfg(unix)'.dev-dependencies]
pprof = { version = "0.13", features = ["criterion", "flamegraph"] }

[profile.release]
codegen-units = 1
lto = "thin"

[profile.bench]
debug = true
inherits = "release"
10 changes: 10 additions & 0 deletions fusio/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ bytes = ["dep:bytes"]
completion-based = []
default = ["dyn", "fs"]
dyn = []
futures = ["dep:futures-util"]
fs = ["tokio?/rt"]
h2 = ["dep:h2"]
http = [
Expand All @@ -38,6 +39,12 @@ tokio = ["async-stream", "dep:tokio"]
tokio-http = ["dep:reqwest", "http"]
tokio-uring = ["async-stream", "completion-based", "dep:tokio-uring", "no-send"]

[[bench]]
harness = false
name = "tokio"
path = "benches/tokio.rs"
required-features = ["tokio"]

[dependencies]
async-stream = { version = "0.3", optional = true }
bytes = { workspace = true, optional = true }
Expand Down Expand Up @@ -79,9 +86,12 @@ url = { version = "2" }
tokio-uring = { version = "0.5", default-features = false, optional = true }

[dev-dependencies]
criterion = { version = "0.5", features = ["async_tokio", "html_reports"] }
futures-executor = "0.3"
hyper = { version = "1", features = ["full"] }
hyper-util = { version = "0.1", features = ["full"] }
monoio = { version = "0.2" }
rand = "0.8"
tempfile = "3"
tokio = { version = "1", features = ["full"] }

Expand Down
133 changes: 133 additions & 0 deletions fusio/benches/tokio.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
use std::{cell::RefCell, io::SeekFrom, rc::Rc, sync::Arc};

use criterion::{criterion_group, criterion_main, Criterion};
use fusio::{
fs::{Fs, OpenOptions},
local::TokioFs,
path::Path,
IoBuf, IoBufMut, Write,
};
use rand::Rng;
use tempfile::NamedTempFile;

fn write(c: &mut Criterion) {
let runtime = tokio::runtime::Builder::new_multi_thread()
.worker_threads(8)
.enable_all()
.build()
.unwrap();

let mut group = c.benchmark_group("write");

let mut write_bytes = [0u8; 4096];
rand::thread_rng().fill(&mut write_bytes);
let write_bytes = Arc::new(write_bytes);

let temp_file = NamedTempFile::new().unwrap();
let path = Path::from_filesystem_path(temp_file.path()).unwrap();

let fs = TokioFs;
let file = Rc::new(RefCell::new(runtime.block_on(async {
fs.open_options(&path, OpenOptions::default().write(true).append(true))
.await
.unwrap()
})));

group.bench_function("fusio write 4K", |b| {
b.to_async(&runtime).iter(|| {
let bytes = write_bytes.clone();
let file = file.clone();

async move {
let (result, _) =
fusio::dynamic::DynWrite::write_all(&mut *(*file).borrow_mut(), unsafe {
(&bytes.as_ref()[..]).to_buf_nocopy()
})
.await;
result.unwrap();
}
})
});
group.bench_function("tokio write 4K", |b| {
b.to_async(&runtime).iter(|| {
let bytes = write_bytes.clone();
let file = file.clone();

async move {
tokio::io::AsyncWriteExt::write_all(
&mut *(*file).borrow_mut(),
&bytes.as_ref()[..],
)
.await
.unwrap();
}
})
});

group.finish();
}

fn read(c: &mut Criterion) {
let runtime = tokio::runtime::Builder::new_multi_thread()
.worker_threads(8)
.enable_all()
.build()
.unwrap();

let mut group = c.benchmark_group("read");

let mut write_bytes = [0u8; 4096];
rand::thread_rng().fill(&mut write_bytes);

let temp_file = NamedTempFile::new().unwrap();
let path = Path::from_filesystem_path(temp_file.path()).unwrap();

let fs = TokioFs;
let file = Rc::new(RefCell::new(runtime.block_on(async {
let mut file = fs
.open_options(&path, OpenOptions::default().write(true).append(true))
.await
.unwrap();
let (result, _) = file.write_all(&write_bytes[..]).await;
result.unwrap();
file
})));

group.bench_function("fusio read 4K", |b| {
b.to_async(&runtime).iter(|| {
let file = file.clone();

async move {
let _ = fusio::dynamic::DynSeek::seek(&mut *(*file).borrow_mut(), 0)
.await
.unwrap();
let _ = fusio::dynamic::DynRead::read_exact(&mut *(*file).borrow_mut(), unsafe {
vec![0u8; 4096].to_buf_mut_nocopy()
})
.await
.unwrap();
}
})
});

group.bench_function("tokio read 4K", |b| {
b.to_async(&runtime).iter(|| {
let file = file.clone();
let mut bytes = [0u8; 4096];

async move {
let _ =
tokio::io::AsyncSeekExt::seek(&mut *(*file).borrow_mut(), SeekFrom::Start(0))
.await
.unwrap();
let _ =
tokio::io::AsyncReadExt::read_exact(&mut *(*file).borrow_mut(), &mut bytes[..])
.await
.unwrap();
}
})
});
}

criterion_group!(benches, write, read);
criterion_main!(benches);
2 changes: 2 additions & 0 deletions fusio/src/buf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@ pub trait IoBufMut: IoBuf {
unsafe { std::slice::from_raw_parts_mut(self.as_mut_ptr(), self.bytes_init()) }
}

#[warn(clippy::missing_safety_doc)]
unsafe fn to_buf_mut_nocopy(self) -> BufMut;

#[warn(clippy::missing_safety_doc)]
unsafe fn recover_from_buf_mut(buf: BufMut) -> Self;
}

Expand Down
16 changes: 8 additions & 8 deletions fusio/src/fs/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,23 @@ impl Default for OpenOptions {
}

impl OpenOptions {
pub fn read(mut self) -> Self {
self.read = true;
pub fn read(mut self, read: bool) -> Self {
self.read = read;
self
}

pub fn write(mut self) -> Self {
self.write = Some(WriteMode::Overwrite);
pub fn write(mut self, write: bool) -> Self {
self.write = write.then_some(WriteMode::Overwrite);
self
}

pub fn create(mut self) -> Self {
self.create = true;
pub fn create(mut self, create: bool) -> Self {
self.create = create;
self
}

pub fn append(mut self) -> Self {
self.write = Some(WriteMode::Append);
pub fn append(mut self, append: bool) -> Self {
self.write = append.then_some(WriteMode::Append);
self
}
}
Loading

0 comments on commit f566fa1

Please sign in to comment.