From 5b796ba6d18e2a53ebff9a3d961124fb65ada61d Mon Sep 17 00:00:00 2001 From: Thomas Tanon Date: Mon, 9 Dec 2024 21:16:15 +0100 Subject: [PATCH] Adds some basic benchmarks --- .github/workflows/build.yml | 15 +++++- Cargo.toml | 9 +++- benches/lib.rs | 98 +++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 benches/lib.rs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3fe9ffe..98abb42 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -65,7 +65,7 @@ jobs: - uses: actions/checkout@v4 with: submodules: true - - run: rustup toolchain install nightly && rustup default 1.70.0 + - run: rustup toolchain install nightly && rustup default 1.74.0 - uses: Swatinem/rust-cache@v2 - run: cargo +nightly update -Z direct-minimal-versions - run: cargo test @@ -132,3 +132,16 @@ jobs: flags: rust fail_ci_if_error: true token: ${{ secrets.CODECOV_TOKEN }} + + codspeed: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: Swatinem/rust-cache@v2 + - uses: taiki-e/install-action@v2 + with: { tool: cargo-codspeed } + - run: cargo codspeed build + - uses: CodSpeedHQ/action@v3 + with: + run: cargo codspeed run + token: ${{ secrets.CODSPEED_TOKEN }} diff --git a/Cargo.toml b/Cargo.toml index 8c7a0a5..ac93cad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ description = """ Very simple implementation of HTTP 1.1 (both client and server) """ edition = "2021" -rust-version = "1.70" +rust-version = "1.74" [dependencies] flate2 = { version = "1", optional = true } @@ -24,6 +24,9 @@ rustls-platform-verifier = { version = "0.4", optional = true } webpki-roots = { version = "0.26", optional = true } url = "2.4" +[dev-dependencies] +codspeed-criterion-compat = "2" + [features] default = ["client", "server"] rustls-ring-platform-verifier = ["rustls/ring", "rustls-pki-types", "rustls-platform-verifier"] @@ -35,6 +38,10 @@ rustls-aws-lc-webpki = ["rustls/aws_lc_rs", "rustls-pki-types", "webpki-roots"] client = [] server = [] +[[bench]] +name = "lib" +harness = false + [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] diff --git a/benches/lib.rs b/benches/lib.rs new file mode 100644 index 0000000..1be9624 --- /dev/null +++ b/benches/lib.rs @@ -0,0 +1,98 @@ +use codspeed_criterion_compat::{criterion_group, criterion_main, Criterion}; +use oxhttp::model::{Body, Method, Request, Response, Status}; +use oxhttp::{Client, Server}; +use std::io; +use std::io::Read; +use std::net::{Ipv4Addr, SocketAddrV4}; +use url::Url; + +fn client_server_no_body(c: &mut Criterion) { + Server::new(|_| Response::builder(Status::OK).build()) + .bind(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 3456)) + .spawn() + .unwrap(); + + let client = Client::new(); + let url = Url::parse("http://localhost:3456").unwrap(); + + c.bench_function("client_server_no_body", |b| { + b.iter(|| { + client + .request(Request::builder(Method::GET, url.clone()).build()) + .unwrap(); + }) + }); +} + +fn client_server_fixed_body(c: &mut Criterion) { + Server::new(|request| { + let mut body = Vec::new(); + request.body_mut().read_to_end(&mut body).unwrap(); + Response::builder(Status::OK).with_body(body) + }) + .bind(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 3457)) + .spawn() + .unwrap(); + + let client = Client::new(); + let url = Url::parse("http://localhost:3456").unwrap(); + let body = vec![16u8; 1024]; + + c.bench_function("client_server_fixed_body", |b| { + b.iter(|| { + client + .request(Request::builder(Method::GET, url.clone()).with_body(body.clone())) + .unwrap(); + }) + }); +} + +fn client_server_chunked_body(c: &mut Criterion) { + Server::new(|request| { + let mut body = Vec::new(); + request.body_mut().read_to_end(&mut body).unwrap(); + Response::builder(Status::OK).build() + }) + .bind(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 3458)) + .spawn() + .unwrap(); + + let client = Client::new(); + let url = Url::parse("http://localhost:3456").unwrap(); + + c.bench_function("client_server_chunked_body", |b| { + b.iter(|| { + client + .request( + Request::builder(Method::GET, url.clone()) + .with_body(Body::from_read(ChunkedReader::default())), + ) + .unwrap(); + }) + }); +} + +criterion_group!( + client_server, + client_server_no_body, + client_server_fixed_body, + client_server_chunked_body +); + +criterion_main!(client_server); + +#[derive(Default)] +struct ChunkedReader { + counter: usize, +} + +impl Read for ChunkedReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + if self.counter >= 10 { + return Ok(0); + } + self.counter += 1; + buf.fill(12); + Ok(buf.len()) + } +}