use criterion::{black_box, criterion_group, criterion_main, Criterion, BenchmarkId}; use hero_supervisor_openrpc_client::SupervisorClientBuilder; use hero_job::Job; use tokio::runtime::Runtime; use std::time::Duration; use std::collections::HashMap; use uuid::Uuid; use chrono::Utc; /// Benchmark configuration const SUPERVISOR_URL: &str = "http://127.0.0.1:3030"; const OSIRIS_URL: &str = "http://127.0.0.1:8081"; const ADMIN_SECRET: &str = "SECRET"; /// Helper to create a tokio runtime for benchmarks fn create_runtime() -> Runtime { Runtime::new().unwrap() } /// Helper to create a test job fn create_test_job(runner: &str, command: &str, args: Vec) -> Job { Job { id: Uuid::new_v4().to_string(), caller_id: "benchmark".to_string(), context_id: "test".to_string(), payload: serde_json::json!({ "command": command, "args": args }).to_string(), runner: runner.to_string(), timeout: 30, env_vars: HashMap::new(), created_at: Utc::now(), updated_at: Utc::now(), signatures: vec![], } } /// Benchmark: Supervisor discovery (OpenRPC metadata) fn bench_supervisor_discovery(c: &mut Criterion) { let rt = create_runtime(); let client = rt.block_on(async { SupervisorClientBuilder::new() .url(SUPERVISOR_URL) .secret(ADMIN_SECRET) .build() .expect("Failed to create supervisor client") }); c.bench_function("supervisor_discovery", |b| { b.to_async(&rt).iter(|| async { black_box(client.discover().await.expect("Discovery failed")) }); }); } /// Benchmark: Supervisor info retrieval fn bench_supervisor_info(c: &mut Criterion) { let rt = create_runtime(); let client = rt.block_on(async { SupervisorClientBuilder::new() .url(SUPERVISOR_URL) .secret(ADMIN_SECRET) .build() .expect("Failed to create supervisor client") }); c.bench_function("supervisor_get_info", |b| { b.to_async(&rt).iter(|| async { black_box(client.get_supervisor_info().await.expect("Get info failed")) }); }); } /// Benchmark: List runners fn bench_list_runners(c: &mut Criterion) { let rt = create_runtime(); let client = rt.block_on(async { SupervisorClientBuilder::new() .url(SUPERVISOR_URL) .secret(ADMIN_SECRET) .build() .expect("Failed to create supervisor client") }); c.bench_function("supervisor_list_runners", |b| { b.to_async(&rt).iter(|| async { black_box(client.runner_list().await.expect("List runners failed")) }); }); } /// Benchmark: Job creation (without execution) fn bench_job_create(c: &mut Criterion) { let rt = create_runtime(); let client = rt.block_on(async { SupervisorClientBuilder::new() .url(SUPERVISOR_URL) .secret(ADMIN_SECRET) .build() .expect("Failed to create supervisor client") }); // Ensure runner exists rt.block_on(async { let _ = client.runner_create("hero").await; }); c.bench_function("supervisor_job_create", |b| { b.to_async(&rt).iter(|| async { let job = create_test_job("hero", "echo", vec!["hello".to_string()]); black_box(client.job_create(job).await.expect("Job create failed")) }); }); } /// Benchmark: Job listing fn bench_job_list(c: &mut Criterion) { let rt = create_runtime(); let client = rt.block_on(async { SupervisorClientBuilder::new() .url(SUPERVISOR_URL) .secret(ADMIN_SECRET) .build() .expect("Failed to create supervisor client") }); c.bench_function("supervisor_job_list", |b| { b.to_async(&rt).iter(|| async { black_box(client.job_list().await.expect("Job list failed")) }); }); } /// Benchmark: Osiris health check fn bench_osiris_health(c: &mut Criterion) { let rt = create_runtime(); let client = reqwest::Client::new(); c.bench_function("osiris_health_check", |b| { b.to_async(&rt).iter(|| async { let url = format!("{}/health", OSIRIS_URL); black_box( client .get(&url) .send() .await .expect("Health check failed") .json::() .await .expect("JSON parse failed") ) }); }); } /// Benchmark: Full job lifecycle (create, start, wait for result) fn bench_job_lifecycle(c: &mut Criterion) { let rt = create_runtime(); let client = rt.block_on(async { SupervisorClientBuilder::new() .url(SUPERVISOR_URL) .secret(ADMIN_SECRET) .timeout(Duration::from_secs(60)) .build() .expect("Failed to create supervisor client") }); // First ensure we have a runner registered rt.block_on(async { let _ = client.runner_create("hero").await; }); c.bench_function("job_full_lifecycle", |b| { b.to_async(&rt).iter(|| async { let job = create_test_job("hero", "echo", vec!["benchmark_test".to_string()]); // Start job and wait for result black_box( client .job_run(job, Some(30)) .await .expect("Job run failed") ) }); }); } /// Benchmark: Concurrent job submissions fn bench_concurrent_jobs(c: &mut Criterion) { let rt = create_runtime(); let client = rt.block_on(async { SupervisorClientBuilder::new() .url(SUPERVISOR_URL) .secret(ADMIN_SECRET) .timeout(Duration::from_secs(60)) .build() .expect("Failed to create supervisor client") }); // Ensure runner is registered rt.block_on(async { let _ = client.runner_create("hero").await; }); let mut group = c.benchmark_group("concurrent_jobs"); for num_jobs in [1, 5, 10, 20].iter() { group.bench_with_input( BenchmarkId::from_parameter(num_jobs), num_jobs, |b, &num_jobs| { b.to_async(&rt).iter(|| async { let mut handles = vec![]; for i in 0..num_jobs { let client = client.clone(); let handle = tokio::spawn(async move { let job = create_test_job("hero", "echo", vec![format!("job_{}", i)]); client.job_create(job).await }); handles.push(handle); } // Wait for all jobs to be submitted for handle in handles { black_box(handle.await.expect("Task failed").expect("Job start failed")); } }); }, ); } group.finish(); } /// Benchmark: Runner status checks fn bench_runner_status(c: &mut Criterion) { let rt = create_runtime(); let client = rt.block_on(async { SupervisorClientBuilder::new() .url(SUPERVISOR_URL) .secret(ADMIN_SECRET) .build() .expect("Failed to create supervisor client") }); // Ensure we have runners rt.block_on(async { let _ = client.runner_create("hero").await; let _ = client.runner_create("osiris").await; }); c.bench_function("get_all_runner_status", |b| { b.to_async(&rt).iter(|| async { black_box( client .get_all_runner_status() .await .expect("Get status failed") ) }); }); } /// Benchmark: API response time under load fn bench_api_latency(c: &mut Criterion) { let rt = create_runtime(); let client = rt.block_on(async { SupervisorClientBuilder::new() .url(SUPERVISOR_URL) .secret(ADMIN_SECRET) .build() .expect("Failed to create supervisor client") }); let mut group = c.benchmark_group("api_latency"); group.measurement_time(Duration::from_secs(10)); group.bench_function("supervisor_info", |b| { b.to_async(&rt).iter(|| async { black_box(client.get_supervisor_info().await.expect("Failed")) }); }); group.bench_function("runner_list", |b| { b.to_async(&rt).iter(|| async { black_box(client.runner_list().await.expect("Failed")) }); }); group.bench_function("job_list", |b| { b.to_async(&rt).iter(|| async { black_box(client.job_list().await.expect("Failed")) }); }); group.finish(); } criterion_group!( benches, bench_supervisor_discovery, bench_supervisor_info, bench_list_runners, bench_job_create, bench_job_list, bench_osiris_health, bench_job_lifecycle, bench_concurrent_jobs, bench_runner_status, bench_api_latency, ); criterion_main!(benches);