///|
/// moon-agent microbenchmarks.
///
/// Run with: moon run bench --target
///
/// Uses `moonbitlang/core/bench` (auto-sized batches, winsorized stats).
/// Each hot path must stay under a generous per-operation threshold
/// (1 ms), so the benchmark only fails on real performance regressions
/// (e.g. accidental quadratic loops), not on slow CI runners.
///
/// Results are printed both human-readably and as JSON (via
/// `dump_summaries`), giving an inspectable baseline.
///|
/// Print each summary and return whether all means stay under threshold.
fn print_and_check_summaries(json_str : String, threshold_us : Double) -> Bool {
let parsed = @json.parse(json_str) catch { _ => return false }
let mut ok = true
match parsed {
Json::Array(items) =>
for item in items {
match item {
Json::Object(map) => {
let name = match map.get("name") {
Some(Json::String(n)) => n
_ => "?"
}
let mean = match map.get("mean") {
Some(Json::Number(n, ..)) => n
_ => 0.0
}
println(name + ": " + mean.to_string() + " us/op")
if mean > threshold_us {
println(
" FAILED: exceeds threshold " +
threshold_us.to_string() +
" us",
)
ok = false
}
}
_ => ()
}
}
_ => ()
}
ok
}
///|
fn main {
// Sink keeps results alive so the optimizer cannot remove the work.
let sink : Array[Int] = [0]
let b = @core_bench.Bench()
// 1. Prompt template rendering
let prompt = @prompts.ChatPromptTemplate::new()
|> @prompts.ChatPromptTemplate::with_user(
"你是一个乐于助人的助手,请回答:{topic}",
)
let vars : Map[String, String] = Map([])
vars["topic"] = "MoonBit"
b.bench(name="PromptTemplate.render", fn() {
let messages = prompt.render(vars)
sink[0] = sink[0] + messages.length()
})
// 2. Calculator evaluation (public run path, includes JSON parsing)
let calc_input = @json.parse("{\"expression\":\"15*23+100\"}") catch {
_ => Json::null()
}
let calculator = @tools.CalculatorTool::new()
b.bench(name="CalculatorTool.run", fn() {
let out = calculator.run(calc_input)
sink[0] = sink[0] + out.length()
})
// 3. Response cache set/get
let cache = @cache.InMemoryCache::new(max_entries=100000)
b.bench(name="InMemoryCache.set_get", fn() {
cache.set("key", "value")
match cache.get("key") {
Some(v) => sink[0] = sink[0] + v.length()
None => ()
}
})
// 4. Tool registry dispatch
let registry = @llm_tools.ToolRegistry::new()
registry.register("echo", "Echo input", Json::null(), fn(
input : Json,
) -> String {
input.stringify()
})
b.bench(name="ToolRegistry.execute", fn() {
let (out, _is_error) = registry.execute("echo", calc_input)
sink[0] = sink[0] + out.length()
})
b.keep(sink[0])
let json_str = b.dump_summaries()
println("Benchmark summaries: " + json_str)
let ok = print_and_check_summaries(json_str, 1000.0)
if !ok {
panic()
}
println("All benchmarks passed.")
}