use criterion::{black_box, criterion_group, criterion_main, Criterion, BenchmarkId};
use std::time::Duration;
fn configure_criterion() -> Criterion {
Criterion::default()
.measurement_time(Duration::from_secs(10))
.warm_up_time(Duration::from_secs(3))
.sample_size(100)
}
fn bench_json_parsing(c: &mut Criterion) {
let json_data = r#"{
"database": "postgres",
"query": "SELECT * FROM users WHERE id = $1",
"params": [12345]
}"#;
c.bench_function("json_parsing_query_request", |b| {
b.iter(|| {
let _: serde_json::Value = serde_json::from_str(black_box(json_data)).unwrap();
});
});
}
fn bench_response_serialization(c: &mut Criterion) {
use serde::Serialize;
#[derive(Serialize)]
struct MockResponse {
success: bool,
data: MockData,
metadata: MockMetadata,
}
#[derive(Serialize)]
struct MockData {
rows: Vec<MockRow>,
row_count: u64,
}
#[derive(Serialize)]
struct MockRow {
id: i32,
name: String,
email: String,
}
#[derive(Serialize)]
struct MockMetadata {
request_id: String,
execution_time_ms: u64,
}
let response = MockResponse {
success: true,
data: MockData {
rows: vec![
MockRow { id: 1, name: "Alice".to_string(), email: "alice@example.com".to_string() },
MockRow { id: 2, name: "Bob".to_string(), email: "bob@example.com".to_string() },
MockRow { id: 3, name: "Charlie".to_string(), email: "charlie@example.com".to_string() },
],
row_count: 3,
},
metadata: MockMetadata {
request_id: "550e8400-e29b-41d4-a716-446655440000".to_string(),
execution_time_ms: 42,
},
};
c.bench_function("response_serialization", |b| {
b.iter(|| {
let _ = serde_json::to_string(black_box(&response)).unwrap();
});
});
}
fn bench_permission_validation(c: &mut Criterion) {
fn validate_query_simple(query: &str) -> &'static str {
let query_upper = query.to_uppercase();
if query_upper.starts_with("SELECT") {
"SELECT"
} else if query_upper.starts_with("INSERT") {
"INSERT"
} else if query_upper.starts_with("UPDATE") {
"UPDATE"
} else if query_upper.starts_with("DELETE") {
"DELETE"
} else {
"OTHER"
}
}
let queries = vec![
"SELECT * FROM users WHERE id = 1",
"INSERT INTO users (name) VALUES ('test')",
"UPDATE users SET name = 'test' WHERE id = 1",
"DELETE FROM users WHERE id = 1",
];
c.bench_function("permission_validation", |b| {
b.iter(|| {
for query in &queries {
let _ = validate_query_simple(black_box(query));
}
});
});
}
fn bench_api_key_extraction(c: &mut Criterion) {
use axum::http::HeaderMap;
use axum::http::header::HeaderValue;
fn extract_api_key(headers: &HeaderMap) -> Option<String> {
headers
.get("x-api-key")
.or_else(|| headers.get("authorization"))
.and_then(|h| h.to_str().ok())
.map(|h| {
if h.starts_with("Bearer ") {
h.strip_prefix("Bearer ").unwrap().to_string()
} else {
h.to_string()
}
})
}
let mut headers = HeaderMap::new();
headers.insert("x-api-key", HeaderValue::from_static("sk_test_123456789"));
c.bench_function("api_key_extraction", |b| {
b.iter(|| {
let _ = extract_api_key(black_box(&headers));
});
});
}
fn bench_param_substitution(c: &mut Criterion) {
fn substitute_params(query: &str, params: &[serde_json::Value]) -> String {
let mut result = query.to_string();
for (i, param) in params.iter().enumerate().rev() {
let placeholder = format!("${}", i + 1);
let value = match param {
serde_json::Value::Null => "NULL".to_string(),
serde_json::Value::Bool(b) => b.to_string(),
serde_json::Value::Number(n) => n.to_string(),
serde_json::Value::String(s) => format!("'{}'", s.replace("'", "''")),
_ => param.to_string(),
};
result = result.replace(&placeholder, &value);
}
result
}
let query = "SELECT * FROM users WHERE id = $1 AND name = $2 AND active = $3";
let params = vec![
serde_json::json!(12345),
serde_json::json!("John Doe"),
serde_json::json!(true),
];
c.bench_function("param_substitution", |b| {
b.iter(|| {
let _ = substitute_params(black_box(query), black_box(¶ms));
});
});
}
fn bench_config_parsing(c: &mut Criterion) {
use serde::Deserialize;
#[derive(Deserialize)]
struct TestConfig {
host: String,
port: u16,
log_level: String,
}
let config_json = r#"{
"host": "127.0.0.1",
"port": 8580,
"log_level": "info"
}"#;
c.bench_function("config_parsing", |b| {
b.iter(|| {
let _: TestConfig = serde_json::from_str(black_box(config_json)).unwrap();
});
});
}
fn bench_rate_limiter(c: &mut Criterion) {
use std::collections::HashMap;
use std::time::{SystemTime, UNIX_EPOCH};
struct RateLimiter {
requests: HashMap<String, Vec<u64>>,
window_size: u64,
max_requests: usize,
}
impl RateLimiter {
fn new(window_size: u64, max_requests: usize) -> Self {
Self {
requests: HashMap::new(),
window_size,
max_requests,
}
}
fn is_allowed(&mut self, key: &str) -> bool {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
let window_start = now - self.window_size;
let timestamps = self.requests.entry(key.to_string()).or_default();
timestamps.retain(|&t| t > window_start);
if timestamps.len() < self.max_requests {
timestamps.push(now);
true
} else {
false
}
}
}
let mut limiter = RateLimiter::new(60, 100);
c.bench_function("rate_limiter_check", |b| {
b.iter(|| {
let _ = limiter.is_allowed(black_box("test_key"));
});
});
}
fn bench_payload_sizes(c: &mut Criterion) {
let sizes = vec![10, 100, 1000];
let mut group = c.benchmark_group("payload_serialization");
for size in sizes {
let data: Vec<i32> = (0..size).collect();
group.bench_with_input(
BenchmarkId::from_parameter(size),
&data,
|b, data| {
b.iter(|| {
let _ = serde_json::to_string(black_box(data)).unwrap();
});
}
);
}
group.finish();
}
criterion_group! {
name = benches;
config = configure_criterion();
targets =
bench_json_parsing,
bench_response_serialization,
bench_permission_validation,
bench_api_key_extraction,
bench_param_substitution,
bench_config_parsing,
bench_rate_limiter,
bench_payload_sizes
}
criterion_main!(benches);