feat: create Pool::acquire() benchmark

This commit is contained in:
Austin Bonander 2025-10-29 03:43:48 -07:00
parent a2a219f175
commit 54564bead6
3 changed files with 152 additions and 42 deletions

54
Cargo.lock generated
View File

@ -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",

View File

@ -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

127
benches/any/pool.rs Normal file
View File

@ -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);