From 54564bead6612b217b855be56d9d41455e90f667 Mon Sep 17 00:00:00 2001 From: Austin Bonander Date: Wed, 29 Oct 2025 03:43:48 -0700 Subject: [PATCH] feat: create `Pool::acquire()` benchmark --- Cargo.lock | 54 +++++-------------- Cargo.toml | 13 ++++- benches/any/pool.rs | 127 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+), 42 deletions(-) create mode 100644 benches/any/pool.rs diff --git a/Cargo.lock b/Cargo.lock index 7a2979fc..ebd8daba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1021,26 +1021,22 @@ checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "criterion" -version = "0.5.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +checksum = "e1c047a62b0cc3e145fa84415a3191f628e980b194c2755aa12300a4e6cbd928" dependencies = [ "anes", "cast", "ciborium", "clap", "criterion-plot", - "futures", - "is-terminal", - "itertools 0.10.5", + "itertools 0.13.0", "num-traits", - "once_cell", "oorandom", "plotters", "rayon", "regex", "serde", - "serde_derive", "serde_json", "tinytemplate", "tokio", @@ -1049,12 +1045,12 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +checksum = "9b1bcc0dc7dfae599d84ad0b1a55f80cde8af3725da8313b528da95ef783e338" dependencies = [ "cast", - "itertools 0.10.5", + "itertools 0.13.0", ] [[package]] @@ -1446,20 +1442,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" -[[package]] -name = "futures" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - [[package]] name = "futures-channel" version = "0.3.31" @@ -1990,17 +1972,6 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf370abdafd54d13e54a620e8c3e1145f28e46cc9d704bc6d94414559df41763" -[[package]] -name = "is-terminal" -version = "0.4.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys 0.59.0", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -3517,6 +3488,7 @@ dependencies = [ "tempfile", "time", "tokio", + "tracing", "trybuild", "url", ] @@ -4411,9 +4383,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "log", "pin-project-lite", @@ -4423,9 +4395,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", @@ -4434,9 +4406,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", "valuable", diff --git a/Cargo.toml b/Cargo.toml index 00d5d656..35ba6701 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -236,9 +236,11 @@ rand = "0.8.4" rand_xoshiro = "0.6.0" hex = "0.4.3" tempfile = "3.10.1" -criterion = { version = "0.5.1", features = ["async_tokio"] } +criterion = { version = "0.7.0", features = ["async_tokio"] } libsqlite3-sys = { version = "0.30.1" } +tracing = { version = "0.1.44", features = ["attributes"] } + # If this is an unconditional dev-dependency then Cargo will *always* try to build `libsqlite3-sys`, # even when SQLite isn't the intended test target, and fail if the build environment is not set up for compiling C code. [target.'cfg(sqlite_test_sqlcipher)'.dev-dependencies] @@ -454,3 +456,12 @@ required-features = ["postgres"] name = "postgres-rustsec" path = "tests/postgres/rustsec.rs" required-features = ["postgres", "macros", "migrate"] + +# +# Benches +# +[[bench]] +name = "any-pool" +path = "benches/any/pool.rs" +required-features = ["runtime-tokio", "any"] +harness = false diff --git a/benches/any/pool.rs b/benches/any/pool.rs new file mode 100644 index 00000000..a6890580 --- /dev/null +++ b/benches/any/pool.rs @@ -0,0 +1,127 @@ +use criterion::{criterion_group, criterion_main, Bencher, BenchmarkId, Criterion}; +use sqlx_core::any::AnyPoolOptions; +use std::fmt::{Display, Formatter}; +use std::thread; +use std::time::{Duration, Instant}; +use tracing::Instrument; + +#[derive(Debug)] +struct Input { + threads: usize, + tasks: usize, + pool_size: u32, +} + +impl Display for Input { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "threads: {}, tasks: {}, pool size: {}", + self.threads, self.tasks, self.pool_size + ) + } +} + +fn bench_pool(c: &mut Criterion) { + sqlx::any::install_default_drivers(); + + let database_url = dotenvy::var("DATABASE_URL").expect("DATABASE_URL must be set"); + + let inputs = [ + Input { + threads: 1, + tasks: 2, + pool_size: 20, + }, + Input { + threads: 2, + tasks: 4, + pool_size: 20, + }, + Input { + threads: 4, + tasks: 8, + pool_size: 20, + }, + Input { + threads: 8, + tasks: 16, + pool_size: 20, + }, + Input { + threads: 16, + tasks: 32, + pool_size: 64, + }, + Input { + threads: 16, + tasks: 128, + pool_size: 64, + }, + ]; + + let mut group = c.benchmark_group("Bench Pool"); + + for input in inputs { + group.bench_with_input(BenchmarkId::from_parameter(&input), &input, |b, i| { + bench_pool_with(b, i, &database_url) + }); + } + + group.finish(); +} + +fn bench_pool_with(b: &mut Bencher, input: &Input, database_url: &str) { + let runtime = tokio::runtime::Builder::new_multi_thread() + .enable_all() + .worker_threads(input.threads) + .build() + .unwrap(); + + let pool = runtime.block_on(async { + AnyPoolOptions::new() + .min_connections(input.pool_size) + .max_connections(input.pool_size) + .test_before_acquire(false) + .connect(database_url) + .await + .expect("error connecting to pool") + }); + + for _ in 1..=input.tasks { + let pool = pool.clone(); + + runtime.spawn(async move { while pool.acquire().await.is_ok() {} }); + } + + // Spawn the benchmark loop into the runtime so we're not accidentally including the main thread + b.to_async(&runtime).iter_custom(|iters| { + let pool = pool.clone(); + + async move { + tokio::spawn( + async move { + let start = Instant::now(); + + for _ in 0..iters { + if let Err(e) = pool.acquire().await { + panic!("failed to acquire connection: {e:?}"); + } + } + + start.elapsed() + } + .instrument(tracing::info_span!("iter")), + ) + .await + .expect("panic in task") + } + }); + + runtime.block_on(pool.close()); + // Give the server a second to clean up + thread::sleep(Duration::from_millis(50)); +} + +criterion_group!(benches, bench_pool,); +criterion_main!(benches);