From a897e2355af8e693fb3b68f42ab06435a4d82498 Mon Sep 17 00:00:00 2001 From: Mika Cohen Date: Sat, 5 Sep 2026 15:06:01 -0600 Subject: [PATCH 1/3] bench: compare hybrid metadata and payload updates --- Cargo.toml | 4 + benches/cache_metadata_payload.rs | 117 ++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 benches/cache_metadata_payload.rs diff --git a/Cargo.toml b/Cargo.toml index c5c378f8..0c6b99e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -176,6 +176,10 @@ harness = false name = "cache_ingest" harness = false +[[bench]] +name = "cache_metadata_payload" +harness = false + [[bench]] name = "end_to_end_proxy" harness = false diff --git a/benches/cache_metadata_payload.rs b/benches/cache_metadata_payload.rs new file mode 100644 index 00000000..34b1f317 --- /dev/null +++ b/benches/cache_metadata_payload.rs @@ -0,0 +1,117 @@ +//! Mixed hybrid-cache workload for metadata and retained-payload updates. +//! +//! Run with: `cargo bench --bench cache_metadata_payload` + +use divan::{Bencher, black_box}; +use nntp_proxy::cache::{HybridCacheConfig, UnifiedCache}; +use nntp_proxy::protocol::StatusCode; +use nntp_proxy::types::{BackendId, MessageId}; +use std::sync::atomic::{AtomicU64, Ordering}; +use std::time::Duration; +use tempfile::{TempDir, tempdir}; + +const ARTICLE_BODY: &str = "x"; + +fn main() { + divan::main(); +} + +fn benchmark_cache() -> (tokio::runtime::Runtime, TempDir, UnifiedCache) { + let runtime = tokio::runtime::Runtime::new().expect("benchmark runtime"); + let directory = tempdir().expect("benchmark cache directory"); + let config = HybridCacheConfig { + memory_capacity: 4 * 1024 * 1024, + disk_capacity: 64 * 1024 * 1024, + disk_path: directory.path().to_path_buf(), + ttl: Duration::from_secs(300), + compression: nntp_proxy::config::CompressionCodec::None, + shards: 16, + }; + let cache = runtime + .block_on(UnifiedCache::hybrid(config)) + .expect("hybrid cache"); + (runtime, directory, cache) +} + +fn message_id(sequence: u64) -> MessageId<'static> { + MessageId::new(format!("")).expect("benchmark message ID") +} + +fn article_response(sequence: u64) -> Vec { + format!( + "220 42 \r\nSubject: Benchmark\r\n\r\n{ARTICLE_BODY}\r\n.\r\n" + ) + .into_bytes() +} + +#[divan::bench(sample_count = 20, sample_size = 1)] +fn metadata_only_updates(bencher: Bencher) { + let (runtime, _directory, cache) = benchmark_cache(); + let sequence = AtomicU64::new(0); + + bencher.bench(|| { + let id = message_id(sequence.fetch_add(1, Ordering::Relaxed)); + runtime.block_on(cache.record_backend_has_status( + id, + StatusCode::new(223), + BackendId::from_index(0), + 0.into(), + )); + }); + + runtime + .block_on(cache.close()) + .expect("close benchmark cache"); +} + +#[divan::bench(sample_count = 20, sample_size = 1)] +fn retained_payload_updates(bencher: Bencher) { + let (runtime, _directory, cache) = benchmark_cache(); + let sequence = AtomicU64::new(0); + + bencher.bench(|| { + let sequence = sequence.fetch_add(1, Ordering::Relaxed); + runtime.block_on(cache.upsert_ingest( + message_id(sequence), + black_box(article_response(sequence)), + BackendId::from_index(0), + 0.into(), + )); + }); + + runtime + .block_on(cache.close()) + .expect("close benchmark cache"); +} + +#[divan::bench(sample_count = 20, sample_size = 1)] +fn mixed_metadata_and_payload_updates(bencher: Bencher) { + let (runtime, _directory, cache) = benchmark_cache(); + let sequence = AtomicU64::new(0); + + bencher.bench(|| { + let sequence = sequence.fetch_add(2, Ordering::Relaxed); + runtime.block_on(async { + cache + .record_backend_has_status( + message_id(sequence), + StatusCode::new(223), + BackendId::from_index(0), + 0.into(), + ) + .await; + cache + .upsert_ingest( + message_id(sequence + 1), + black_box(article_response(sequence + 1)), + BackendId::from_index(0), + 0.into(), + ) + .await; + }); + }); + + runtime + .block_on(cache.close()) + .expect("close benchmark cache"); +} From 0881e7f5b20d3e674df01d0b215492a3a9cffaca Mon Sep 17 00:00:00 2001 From: Mika Cohen Date: Sat, 5 Sep 2026 17:17:19 -0600 Subject: [PATCH 2/3] bench: exclude input construction from cache timings --- benches/cache_metadata_payload.rs | 81 ++++++++++++++++--------------- 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/benches/cache_metadata_payload.rs b/benches/cache_metadata_payload.rs index 34b1f317..22826ac5 100644 --- a/benches/cache_metadata_payload.rs +++ b/benches/cache_metadata_payload.rs @@ -2,7 +2,7 @@ //! //! Run with: `cargo bench --bench cache_metadata_payload` -use divan::{Bencher, black_box}; +use divan::Bencher; use nntp_proxy::cache::{HybridCacheConfig, UnifiedCache}; use nntp_proxy::protocol::StatusCode; use nntp_proxy::types::{BackendId, MessageId}; @@ -49,15 +49,16 @@ fn metadata_only_updates(bencher: Bencher) { let (runtime, _directory, cache) = benchmark_cache(); let sequence = AtomicU64::new(0); - bencher.bench(|| { - let id = message_id(sequence.fetch_add(1, Ordering::Relaxed)); - runtime.block_on(cache.record_backend_has_status( - id, - StatusCode::new(223), - BackendId::from_index(0), - 0.into(), - )); - }); + bencher + .with_inputs(|| message_id(sequence.fetch_add(1, Ordering::Relaxed))) + .bench_values(|id| { + runtime.block_on(cache.record_backend_has_status( + id, + StatusCode::new(223), + BackendId::from_index(0), + 0.into(), + )); + }); runtime .block_on(cache.close()) @@ -69,15 +70,14 @@ fn retained_payload_updates(bencher: Bencher) { let (runtime, _directory, cache) = benchmark_cache(); let sequence = AtomicU64::new(0); - bencher.bench(|| { - let sequence = sequence.fetch_add(1, Ordering::Relaxed); - runtime.block_on(cache.upsert_ingest( - message_id(sequence), - black_box(article_response(sequence)), - BackendId::from_index(0), - 0.into(), - )); - }); + bencher + .with_inputs(|| { + let sequence = sequence.fetch_add(1, Ordering::Relaxed); + (message_id(sequence), article_response(sequence)) + }) + .bench_values(|(id, response)| { + runtime.block_on(cache.upsert_ingest(id, response, BackendId::from_index(0), 0.into())); + }); runtime .block_on(cache.close()) @@ -89,27 +89,30 @@ fn mixed_metadata_and_payload_updates(bencher: Bencher) { let (runtime, _directory, cache) = benchmark_cache(); let sequence = AtomicU64::new(0); - bencher.bench(|| { - let sequence = sequence.fetch_add(2, Ordering::Relaxed); - runtime.block_on(async { - cache - .record_backend_has_status( - message_id(sequence), - StatusCode::new(223), - BackendId::from_index(0), - 0.into(), - ) - .await; - cache - .upsert_ingest( - message_id(sequence + 1), - black_box(article_response(sequence + 1)), - BackendId::from_index(0), - 0.into(), - ) - .await; + bencher + .with_inputs(|| { + let sequence = sequence.fetch_add(2, Ordering::Relaxed); + ( + message_id(sequence), + message_id(sequence + 1), + article_response(sequence + 1), + ) + }) + .bench_values(|(metadata_id, payload_id, response)| { + runtime.block_on(async { + cache + .record_backend_has_status( + metadata_id, + StatusCode::new(223), + BackendId::from_index(0), + 0.into(), + ) + .await; + cache + .upsert_ingest(payload_id, response, BackendId::from_index(0), 0.into()) + .await; + }); }); - }); runtime .block_on(cache.close()) From da93f1d39e6d1a469daf4507a0df2c4ef497bb3e Mon Sep 17 00:00:00 2001 From: Mika Cohen Date: Fri, 11 Sep 2026 12:08:57 -0600 Subject: [PATCH 3/3] Compact ordinary development artifacts --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 0c6b99e7..a499cda6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -185,12 +185,15 @@ name = "end_to_end_proxy" harness = false [profile.dev] +debug = 0 # Use the profiling/bench profiles when symbols are needed +incremental = false # Avoid retaining a second full set of object files split-debuginfo = "unpacked" # Faster linking — don't bundle debuginfo into binary [profile.dev.package."*"] opt-level = 1 # Compile dependencies with optimizations in dev mode # Huge runtime speedup for rustls/ring/foyer/moka # Minimal compile-time cost (deps cached after first build) +debug = 0 # Keep dependency artifacts compact in the dev profile [profile.release] debug = false # No debug symbols for smaller binaries