#![allow(clippy::disallowed_methods)]
#![allow(clippy::cast_precision_loss)]
use std::sync::Arc;
use std::time::Instant;
use agentplane::prelude::*;
use serde_json::{Value, json};
#[derive(Debug)]
struct Burst(usize);
#[async_trait::async_trait]
impl Skill for Burst {
fn descriptor(&self) -> SkillDescriptor {
SkillDescriptor::new("burst").provides("perf.burst")
}
async fn invoke(
&self,
cx: &mut StepCtx<'_>,
input: Tainted<Value>,
) -> Result<Outcome, SkillError> {
for _ in 0..self.0 {
let _ = cx.now().await?;
}
Ok(Outcome::done(input))
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let n: usize = std::env::var("N")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(2000);
let on_disk = std::env::var("DISK").is_ok();
let store: Arc<dyn JournalStore> = if on_disk {
let path =
std::env::temp_dir().join(format!("agentplane-bench-{}.redb", std::process::id()));
let _ = std::fs::remove_file(&path);
Arc::new(RedbStore::open(&path)?)
} else {
Arc::new(RedbStore::open_in_memory()?)
};
let runtime = Runtime::builder(Arc::clone(&store)).skill(Burst(n)).build();
let started = Instant::now();
let outcome = runtime
.run("perf.burst", Tainted::trusted(json!({})))
.await?;
let live = started.elapsed();
let started = Instant::now();
runtime.replay(outcome.run_id, Mode::Strict).await?;
let replay = started.elapsed();
let per = live.as_secs_f64() / n as f64 * 1000.0;
println!(
"{n} effects, redb {}\n \
live {live:>9.1?} {:>8.0} effects/sec {per:.2} ms/effect\n \
replay {replay:>9.1?} {:>8.0} effects/sec {:.0}x faster than live",
if on_disk { "on disk" } else { "in memory" },
n as f64 / live.as_secs_f64(),
n as f64 / replay.as_secs_f64(),
live.as_secs_f64() / replay.as_secs_f64(),
);
Ok(())
}