From cf5d6a408fef914a5a55ac0b2107cb8bda8ad292 Mon Sep 17 00:00:00 2001 From: zavakid Date: Mon, 10 Feb 2025 01:01:07 +0800 Subject: [PATCH] chore: new bencher crate --- Cargo.toml | 8 +++ crates/bencher/Cargo.toml | 32 +++++++++ crates/bencher/benches/decoder.rs | 37 ++++++++++ .../bencher/resources/request/get_header.txt | 17 +++++ crates/bencher/src/lib.rs | 67 +++++++++++++++++++ crates/http/Cargo.toml | 2 +- 6 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 crates/bencher/Cargo.toml create mode 100644 crates/bencher/benches/decoder.rs create mode 100644 crates/bencher/resources/request/get_header.txt create mode 100644 crates/bencher/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index e5c954e..6c57b1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ members = [ "crates/http", "crates/web", + "crates/bencher", ] resolver = "2" @@ -27,6 +28,7 @@ tracing = "0.1.40" tracing-subscriber = "0.3.18" tokio = {version = "1", features = ["full", "tracing"] } +tokio-util = { version = "0.7.13", features = ["codec", "io", "tracing"] } async-trait = "0.1.83" futures = "0.3.31" bytes = "1.10.0" @@ -58,6 +60,12 @@ matchit = "0.8.5" mockall = "0.13.1" criterion ="0.5" +codspeed-criterion-compat = { version = "2.6.0", default-features = false } + + +micro-web = { path = "crates/web" } +micro-http = { path = "crates/http" } + [patch.crates-io] micro-http = { path = "crates/http" } diff --git a/crates/bencher/Cargo.toml b/crates/bencher/Cargo.toml new file mode 100644 index 0000000..6734886 --- /dev/null +++ b/crates/bencher/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "bencher" +version = "0.0.0" +edition = "2021" +description = "micro-http benchmarks" +authors.workspace = true +homepage.workspace = true +license.workspace = true +readme.workspace = true +repository.workspace = true + +[lib] +bench = false +test = false +doctest = false + +[[bench]] +name = "decoder" +harness = false + +[dependencies] +codspeed-criterion-compat = { workspace = true, default-features = false, optional = true } +criterion = { workspace = true, default-features = false } + + +[dev-dependencies] +micro-http.workspace = true +micro-web.workspace = true +tokio-util.workspace = true + +[features] +codspeed = ["codspeed-criterion-compat"] \ No newline at end of file diff --git a/crates/bencher/benches/decoder.rs b/crates/bencher/benches/decoder.rs new file mode 100644 index 0000000..7f53405 --- /dev/null +++ b/crates/bencher/benches/decoder.rs @@ -0,0 +1,37 @@ +use bencher::{TestCase, TestFile}; +use criterion::{black_box, criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion, Throughput}; +use micro_http::codec::RequestDecoder; +use tokio_util::bytes::BytesMut; +use tokio_util::codec::Decoder; + +static SMALL_HEADER: TestFile = TestFile::new("get_header.txt", include_str!("../resources/request/get_header.txt")); + +fn create_test_cases() -> Vec { + vec![TestCase::normal("get_header.txt", SMALL_HEADER.clone())] +} + +fn benchmark_request_decoder(criterion: &mut Criterion) { + let test_cases = create_test_cases(); + let mut group = criterion.benchmark_group("request_decoder"); + + for case in test_cases { + group.throughput(Throughput::Bytes(case.file().content().len() as u64)); + group.bench_with_input(BenchmarkId::from_parameter(case.name()), &case, |b, case| { + b.iter_batched_ref( + || (RequestDecoder::new(), BytesMut::from(case.file().content())), + |(decoder, bytes_mut)| { + let header = decoder.decode(bytes_mut).expect("input should be valide http request header").unwrap(); + black_box(header); + let body = decoder.decode(bytes_mut).expect("input should be valide http request body").unwrap(); + black_box(body); + }, + BatchSize::SmallInput, + ); + }); + } + + group.finish(); +} + +criterion_group!(decoder, benchmark_request_decoder); +criterion_main!(decoder); diff --git a/crates/bencher/resources/request/get_header.txt b/crates/bencher/resources/request/get_header.txt new file mode 100644 index 0000000..0e2aa59 --- /dev/null +++ b/crates/bencher/resources/request/get_header.txt @@ -0,0 +1,17 @@ +GET /user/123 HTTP/1.1 +Host: 127.0.0.1:3000 +Sec-Fetch-Dest: document +Sec-Fetch-Mode: navigate +Sec-Fetch-Site: none +Sec-Fetch-User: ?1 +sec-ch-ua: "Not A(Brand";v="8", "Chromium";v="132", "Microsoft Edge";v="132" +sec-ch-ua-mobile: ?0 +sec-ch-ua-platform: "macOS" +Cache-Control: max-age=0 +Connection: keep-alive +Upgrade-Insecure-Requests: 1 +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Edg/132.0.0.0 +Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7 +Accept-Encoding: gzip, deflate, br, zstd +Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 + diff --git a/crates/bencher/src/lib.rs b/crates/bencher/src/lib.rs new file mode 100644 index 0000000..206f430 --- /dev/null +++ b/crates/bencher/src/lib.rs @@ -0,0 +1,67 @@ +#[derive(Debug, Copy, Clone)] +pub struct TestCase { + name: &'static str, + group: TestGroup, + file: TestFile, +} + +impl TestCase { + pub fn new(name: &'static str, group: TestGroup, file: TestFile) -> Self { + Self { name, group, file } + } + + pub fn small(name: &'static str, file: TestFile) -> Self { + Self::new(name, TestGroup::Small, file) + } + + pub fn normal(name: &'static str, file: TestFile) -> Self { + Self::new(name, TestGroup::Normal, file) + } + + pub fn large(name: &'static str, file: TestFile) -> Self { + Self::new(name, TestGroup::Large, file) + } + + pub fn name(&self) -> &'static str { + self.name + } + + pub fn group(&self) -> TestGroup { + self.group + } + + pub fn file(&self) -> &TestFile { + &self.file + } + + pub fn file_name(&self) -> &'static str { + self.file().file_name + } +} + +#[derive(Debug, Copy, Clone)] +pub struct TestFile { + file_name: &'static str, + content: &'static str, +} + +impl TestFile { + pub const fn new(file_name: &'static str, content: &'static str) -> Self { + Self { file_name, content } + } + + pub fn content(&self) -> &'static str { + self.content + } + + pub fn file_name(&self) -> &'static str { + self.file_name + } +} + +#[derive(Clone, Copy, Debug)] +pub enum TestGroup { + Small, + Normal, + Large, +} diff --git a/crates/http/Cargo.toml b/crates/http/Cargo.toml index 655fd76..4347127 100644 --- a/crates/http/Cargo.toml +++ b/crates/http/Cargo.toml @@ -25,7 +25,7 @@ tracing-subscriber.workspace = true bytes.workspace = true tokio.workspace = true -tokio-util = { version = "0.7.13", features = ["codec", "io", "tracing"] } +tokio-util.workspace = true futures.workspace = true trait-variant.workspace = true