wifi-densepose/vendor/midstream/benches/quic_bench.rs

431 lines
14 KiB
Rust

//! QUIC Multi-Stream Benchmarks
//!
//! Comprehensive performance benchmarks for quic-multistream crate covering:
//! - Stream throughput (target: >100 MB/s)
//! - Connection establishment latency (target: <10ms)
//! - Multiplexing performance (target: >1000 concurrent streams)
//! - 0-RTT connection time
//! - Backpressure handling
//! - Error recovery time
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use std::sync::Arc;
use tokio::runtime::Runtime;
// Mock QUIC components for benchmarking (since we need a server for real tests)
mod mock {
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
pub struct MockConnection {
bytes_sent: Arc<AtomicU64>,
bytes_received: Arc<AtomicU64>,
rtt_us: u64,
}
impl MockConnection {
pub fn new(rtt_us: u64) -> Self {
Self {
bytes_sent: Arc::new(AtomicU64::new(0)),
bytes_received: Arc::new(AtomicU64::new(0)),
rtt_us,
}
}
pub async fn open_bi_stream(&self) -> MockStream {
MockStream::new(
self.bytes_sent.clone(),
self.bytes_received.clone(),
self.rtt_us,
)
}
pub fn stats(&self) -> ConnectionStats {
ConnectionStats {
bytes_sent: self.bytes_sent.load(Ordering::Relaxed),
bytes_received: self.bytes_received.load(Ordering::Relaxed),
rtt_ms: (self.rtt_us as f64) / 1000.0,
}
}
}
pub struct MockStream {
bytes_sent: Arc<AtomicU64>,
bytes_received: Arc<AtomicU64>,
rtt_us: u64,
}
impl MockStream {
fn new(
bytes_sent: Arc<AtomicU64>,
bytes_received: Arc<AtomicU64>,
rtt_us: u64,
) -> Self {
Self {
bytes_sent,
bytes_received,
rtt_us,
}
}
pub async fn send(&mut self, data: &[u8]) -> Result<usize, String> {
// Simulate network delay
tokio::time::sleep(tokio::time::Duration::from_micros(self.rtt_us / 2)).await;
self.bytes_sent.fetch_add(data.len() as u64, Ordering::Relaxed);
Ok(data.len())
}
pub async fn recv(&mut self, buf: &mut [u8]) -> Result<usize, String> {
// Simulate network delay
tokio::time::sleep(tokio::time::Duration::from_micros(self.rtt_us / 2)).await;
let len = buf.len().min(8192); // Simulate typical packet size
self.bytes_received
.fetch_add(len as u64, Ordering::Relaxed);
Ok(len)
}
pub async fn finish(&mut self) -> Result<(), String> {
Ok(())
}
}
pub struct ConnectionStats {
pub bytes_sent: u64,
pub bytes_received: u64,
pub rtt_ms: f64,
}
}
/// Benchmark stream throughput with various payload sizes
fn benchmark_stream_throughput(c: &mut Criterion) {
let rt = Runtime::new().unwrap();
let mut group = c.benchmark_group("stream_throughput");
// Test various payload sizes: 1KB, 10KB, 100KB, 1MB
for size in [1024, 10 * 1024, 100 * 1024, 1024 * 1024].iter() {
group.throughput(Throughput::Bytes(*size as u64));
group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, &size| {
b.to_async(&rt).iter(|| async {
let conn = mock::MockConnection::new(100); // 100μs RTT
let mut stream = conn.open_bi_stream().await;
let data = vec![0u8; size];
// Send data
black_box(stream.send(&data).await.unwrap());
stream.finish().await.unwrap();
});
});
}
group.finish();
}
/// Benchmark connection establishment latency
fn benchmark_connection_latency(c: &mut Criterion) {
let rt = Runtime::new().unwrap();
let mut group = c.benchmark_group("connection_latency");
// Test different RTT scenarios
for rtt_us in [100, 500, 1000, 5000].iter() {
group.bench_with_input(
BenchmarkId::new("establish", format!("{}us", rtt_us)),
rtt_us,
|b, &rtt_us| {
b.to_async(&rt).iter(|| async {
// Simulate connection establishment
let start = std::time::Instant::now();
let _conn = mock::MockConnection::new(rtt_us);
tokio::time::sleep(tokio::time::Duration::from_micros(rtt_us * 3)).await;
black_box(start.elapsed());
});
},
);
}
group.finish();
}
/// Benchmark multiplexing performance with concurrent streams
fn benchmark_multiplexing(c: &mut Criterion) {
let rt = Runtime::new().unwrap();
let mut group = c.benchmark_group("multiplexing");
// Test concurrent stream handling: 10, 100, 500, 1000 streams
for num_streams in [10, 100, 500, 1000].iter() {
group.bench_with_input(
BenchmarkId::from_parameter(num_streams),
num_streams,
|b, &num_streams| {
b.to_async(&rt).iter(|| async {
let conn = Arc::new(mock::MockConnection::new(100));
let mut handles = Vec::new();
// Open and use multiple concurrent streams
for _ in 0..num_streams {
let conn = conn.clone();
let handle = tokio::spawn(async move {
let mut stream = conn.open_bi_stream().await;
let data = vec![0u8; 1024];
stream.send(&data).await.unwrap();
stream.finish().await.unwrap();
});
handles.push(handle);
}
// Wait for all streams to complete
for handle in handles {
handle.await.unwrap();
}
});
},
);
}
group.finish();
}
/// Benchmark 0-RTT connection time
fn benchmark_zero_rtt(c: &mut Criterion) {
let rt = Runtime::new().unwrap();
let mut group = c.benchmark_group("zero_rtt");
group.bench_function("0rtt_connection", |b| {
b.to_async(&rt).iter(|| async {
// Simulate 0-RTT connection (no handshake delay)
let start = std::time::Instant::now();
let _conn = mock::MockConnection::new(0);
black_box(start.elapsed());
});
});
group.bench_function("1rtt_connection", |b| {
b.to_async(&rt).iter(|| async {
// Simulate 1-RTT connection (standard handshake)
let start = std::time::Instant::now();
let _conn = mock::MockConnection::new(100);
tokio::time::sleep(tokio::time::Duration::from_micros(100)).await;
black_box(start.elapsed());
});
});
group.finish();
}
/// Benchmark backpressure handling
fn benchmark_backpressure(c: &mut Criterion) {
let rt = Runtime::new().unwrap();
let mut group = c.benchmark_group("backpressure");
// Test backpressure with different buffer sizes
for buffer_size in [16, 64, 256, 1024].iter() {
group.bench_with_input(
BenchmarkId::new("buffer_kb", buffer_size),
buffer_size,
|b, &buffer_size| {
b.to_async(&rt).iter(|| async {
let conn = mock::MockConnection::new(100);
let mut stream = conn.open_bi_stream().await;
// Send data with simulated backpressure
for _ in 0..10 {
let data = vec![0u8; buffer_size * 1024];
stream.send(&data).await.unwrap();
}
stream.finish().await.unwrap();
});
},
);
}
group.finish();
}
/// Benchmark error recovery time
fn benchmark_error_recovery(c: &mut Criterion) {
let rt = Runtime::new().unwrap();
let mut group = c.benchmark_group("error_recovery");
group.bench_function("stream_reset", |b| {
b.to_async(&rt).iter(|| async {
let conn = mock::MockConnection::new(100);
let mut stream = conn.open_bi_stream().await;
// Simulate stream reset
let data = vec![0u8; 1024];
stream.send(&data).await.unwrap();
// Reset and create new stream
let mut new_stream = conn.open_bi_stream().await;
black_box(new_stream.send(&data).await.unwrap());
});
});
group.bench_function("connection_migration", |b| {
b.to_async(&rt).iter(|| async {
// Simulate connection migration
let _conn1 = mock::MockConnection::new(100);
tokio::time::sleep(tokio::time::Duration::from_micros(50)).await;
// Create new connection (simulating migration)
let _conn2 = mock::MockConnection::new(100);
tokio::time::sleep(tokio::time::Duration::from_micros(50)).await;
black_box(());
});
});
group.finish();
}
/// Benchmark bidirectional vs unidirectional streams
fn benchmark_stream_types(c: &mut Criterion) {
let rt = Runtime::new().unwrap();
let mut group = c.benchmark_group("stream_types");
group.bench_function("bidirectional", |b| {
b.to_async(&rt).iter(|| async {
let conn = mock::MockConnection::new(100);
let mut stream = conn.open_bi_stream().await;
let data = vec![0u8; 4096];
stream.send(&data).await.unwrap();
let mut buf = vec![0u8; 4096];
stream.recv(&mut buf).await.unwrap();
stream.finish().await.unwrap();
});
});
group.bench_function("unidirectional", |b| {
b.to_async(&rt).iter(|| async {
let conn = mock::MockConnection::new(100);
let mut stream = conn.open_bi_stream().await;
let data = vec![0u8; 4096];
stream.send(&data).await.unwrap();
stream.finish().await.unwrap();
});
});
group.finish();
}
/// Benchmark stream priority handling
fn benchmark_stream_priority(c: &mut Criterion) {
let rt = Runtime::new().unwrap();
let mut group = c.benchmark_group("stream_priority");
// Simulate different priority streams
group.bench_function("mixed_priority", |b| {
b.to_async(&rt).iter(|| async {
let conn = Arc::new(mock::MockConnection::new(100));
let mut handles = Vec::new();
// Create streams with different "priorities" (simulated by varying delays)
for priority in 0..4 {
let conn = conn.clone();
let handle = tokio::spawn(async move {
let mut stream = conn.open_bi_stream().await;
let data = vec![0u8; 1024];
// Higher priority = less delay
tokio::time::sleep(tokio::time::Duration::from_micros(priority * 10)).await;
stream.send(&data).await.unwrap();
stream.finish().await.unwrap();
});
handles.push(handle);
}
for handle in handles {
handle.await.unwrap();
}
});
});
group.finish();
}
/// Benchmark connection statistics collection
fn benchmark_stats_collection(c: &mut Criterion) {
let rt = Runtime::new().unwrap();
let mut group = c.benchmark_group("stats_collection");
group.bench_function("get_stats", |b| {
b.to_async(&rt).iter(|| async {
let conn = mock::MockConnection::new(100);
let mut stream = conn.open_bi_stream().await;
let data = vec![0u8; 1024];
stream.send(&data).await.unwrap();
// Get connection stats
let stats = conn.stats();
black_box(stats);
});
});
group.bench_function("high_frequency_stats", |b| {
b.to_async(&rt).iter(|| async {
let conn = mock::MockConnection::new(100);
// Simulate frequent stats polling
for _ in 0..100 {
let stats = conn.stats();
black_box(stats);
}
});
});
group.finish();
}
/// Benchmark concurrent connections
fn benchmark_concurrent_connections(c: &mut Criterion) {
let rt = Runtime::new().unwrap();
let mut group = c.benchmark_group("concurrent_connections");
for num_conns in [1, 10, 50, 100].iter() {
group.bench_with_input(
BenchmarkId::from_parameter(num_conns),
num_conns,
|b, &num_conns| {
b.to_async(&rt).iter(|| async {
let mut handles = Vec::new();
// Create multiple concurrent connections
for _ in 0..num_conns {
let handle = tokio::spawn(async move {
let conn = mock::MockConnection::new(100);
let mut stream = conn.open_bi_stream().await;
let data = vec![0u8; 1024];
stream.send(&data).await.unwrap();
stream.finish().await.unwrap();
});
handles.push(handle);
}
for handle in handles {
handle.await.unwrap();
}
});
},
);
}
group.finish();
}
criterion_group!(
benches,
benchmark_stream_throughput,
benchmark_connection_latency,
benchmark_multiplexing,
benchmark_zero_rtt,
benchmark_backpressure,
benchmark_error_recovery,
benchmark_stream_types,
benchmark_stream_priority,
benchmark_stats_collection,
benchmark_concurrent_connections,
);
criterion_main!(benches);