// Benchmark Driver for moon-frequency-sketch
// ============================================
// Exercises all core data structures with realistic workloads.
// Run with: moon run bench
///|
fn main {
println("=== moon-frequency-sketch Benchmarks ===")
println("")
bench_cms()
bench_topk()
bench_bloom()
bench_countsketch()
bench_window()
bench_telemetry()
println("")
println("All benchmarks complete.")
}
///|
/// Simulate a Zipf-like distribution: rank k gets N/(k * H_distinct) events.
fn zipf_workload(n : Int, distinct : Int) -> Array[(String, Int64)] {
let result = Array::make(distinct, ("", 0L))
let mut i = 0
while i < distinct {
let rank = i + 1
let count = (n / rank).to_int64()
result[i] = ("key_" + rank.to_string(), if count < 1L { 1L } else { count })
i = i + 1
}
result
}
///|
/// Count-Min Sketch benchmark.
fn bench_cms() -> Unit {
println("[CMS] Building workload (100k insertions, 1k distinct keys)...")
let workload = zipf_workload(100000, 1000)
let cms = @cms.CountMinSketch::new(5, 2000)
let mut i = 0
while i < workload.length() {
let (key, count) = workload[i]
cms.add_str(key, count)
i = i + 1
}
println("[CMS] Querying top-10 keys...")
i = 0
while i < 10 {
let (key, true_count) = workload[i]
let est = cms.estimate_str(key)
let over = est - true_count
println(
" " +
key +
" true=" +
true_count.to_string() +
" est=" +
est.to_string() +
" over=" +
over.to_string(),
)
i = i + 1
}
println("[CMS] " + cms.summary())
println("")
}
///|
/// Top-K Heavy Hitters benchmark.
fn bench_topk() -> Unit {
println("[TopK] Space-Saving benchmark (500 events, 50 distinct)...")
let ss = @topk.SpaceSaving::new(100)
let mut i = 0
while i < 500 {
ss.add("event_" + (i % 50).to_string())
i = i + 1
}
let top = ss.top_k(5)
println(" Top-5 results:")
i = 0
while i < top.length() {
println(
" " +
(i + 1).to_string() +
". " +
top[i].key +
" count=" +
top[i].count.to_string(),
)
i = i + 1
}
println("")
println("[TopK] Misra-Gries benchmark (500 events, 30 distinct)...")
let mg = @topk.MisraGries::new(50)
i = 0
while i < 500 {
mg.add("item_" + (i % 30).to_string())
i = i + 1
}
let cands = mg.candidates()
println(" Active candidates: " + cands.length().to_string())
println("")
}
///|
/// Bloom Filter benchmark.
fn bench_bloom() -> Unit {
println("[Bloom] Standard Bloom Filter (10k insertions, ~1% FP rate)...")
let bf = @bloomfilter.BloomFilter::from_params(10000, 0.01)
let mut i = 0
while i < 10000 {
bf.add_str("item_" + i.to_string())
i = i + 1
}
let mut fp_count = 0
i = 10000
while i < 20000 {
if bf.contains_str("item_" + i.to_string()) {
fp_count = fp_count + 1
}
i = i + 1
}
let fp_rate = fp_count.to_double() / 10000.0
println(
" FP count: " + fp_count.to_string() + ", rate: " + fp_rate.to_string(),
)
println(" Memory: " + bf.memory_bytes().to_string() + " bytes")
println("")
println("[Bloom] Counting Bloom Filter (1k insertions + 500 removals)...")
let cb = @bloomfilter.CountingBloom::from_params(1000, 0.01)
i = 0
while i < 1000 {
cb.add_str("session_" + i.to_string())
i = i + 1
}
i = 0
while i < 500 {
let _ = cb.remove_str("session_" + i.to_string())
i = i + 1
}
println(
" After 500 removals, approx count: " + cb.approx_count().to_string(),
)
println("")
}
///|
/// Count Sketch benchmark.
fn bench_countsketch() -> Unit {
println("[CountSketch] 5k events, 100 distinct keys (50 each)...")
let cs = @countsketch.CountSketch::new(7, 1000)
let mut i = 0
while i < 5000 {
cs.add_str("key_" + (i % 100).to_string(), 1L)
i = i + 1
}
let e0 = cs.estimate_str("key_0")
let e1 = cs.estimate_str("key_1")
println(" key_0 estimate: " + e0.to_string() + " (expected ~50)")
println(" key_1 estimate: " + e1.to_string() + " (expected ~50)")
println("")
}
///|
/// Sliding Window benchmark.
fn bench_window() -> Unit {
println("[Window] 10-bucket sliding window, 100 ticks...")
let sw = @window.SlidingWindow::new(10, 4, 200)
let mut i = 0
while i < 100 {
sw.add_str("hot_key", 10L)
sw.add_str("cold_key", 1L)
if i % 10 == 9 {
sw.tick()
}
i = i + 1
}
println(
" hot_key window estimate: " + sw.estimate_str("hot_key").to_string(),
)
println(
" cold_key window estimate: " + sw.estimate_str("cold_key").to_string(),
)
println(" Total window count: " + sw.total_count().to_string())
println("")
}
///|
/// Deterministic end-to-end API telemetry benchmark with exact reference values.
fn bench_telemetry() -> Unit {
let event_count = 10000
let monitor = @telemetry.Monitor::new(20, 10, 5, 1000, 12, 100).unwrap()
let start = @env.now()
for i in 0.. value
None => 0.0
}
let p99 = match report.latency_p99 {
Some(value) => value
None => 0.0
}
println("[Telemetry] Deterministic API stream benchmark")
println(" events=" + event_count.to_string() + " distinct_entities=1000")
println(
" measured_ms=" +
measured_ms.to_string() +
" throughput_events_per_sec=" +
throughput.to_string(),
)
println(
" unique_estimate=" +
report.unique_entities.to_string() +
" relative_error=" +
unique_error.to_string(),
)
println(
" latency_p95_estimate=" +
p95.to_string() +
" exact=104.0 latency_p99_estimate=" +
p99.to_string() +
" exact=108.0",
)
println(
" error_events=" +
report.error_events.to_string() +
" error_rate=" +
report.error_rate.to_string(),
)
println("")
}