Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -176,17 +176,24 @@ harness = false
name = "cache_ingest"
harness = false

[[bench]]
name = "cache_metadata_payload"
harness = false

[[bench]]
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
Expand Down
120 changes: 120 additions & 0 deletions benches/cache_metadata_payload.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
//! Mixed hybrid-cache workload for metadata and retained-payload updates.
//!
//! Run with: `cargo bench --bench cache_metadata_payload`

use divan::Bencher;
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!("<bench-{sequence}@example.com>")).expect("benchmark message ID")
}

fn article_response(sequence: u64) -> Vec<u8> {
format!(
"220 42 <bench-{sequence}@example.com>\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
.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())
.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
.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())
.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
.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())
.expect("close benchmark cache");
}
Loading