///|
pub(all) struct ExperimentCase {
name : String
summary : ModelSummary
notes : String
}
///|
pub(all) struct ExperimentReport {
title : String
cases : Array[ExperimentCase]
}
///|
pub fn experiment_case(
name : String,
summary : ModelSummary,
notes? : String = "",
) -> ExperimentCase {
{ name, summary, notes }
}
///|
pub fn ExperimentReport::new(title : String) -> ExperimentReport {
{ title, cases: [] }
}
///|
pub fn ExperimentReport::add(
self : ExperimentReport,
item : ExperimentCase,
) -> ExperimentReport {
self.cases.push(item)
self
}
///|
pub fn ExperimentReport::case_count(self : ExperimentReport) -> Int {
self.cases.length()
}
///|
pub fn ExperimentReport::combined_digest(self : ExperimentReport) -> UInt64 {
let entries : Array[TraceEntry] = []
for i in 0.. Int {
let mut total = 0
for item in self.cases {
total += item.summary.events
}
total
}
///|
pub fn ExperimentReport::max_final_tick(self : ExperimentReport) -> Int {
let mut max = 0
for item in self.cases {
if item.summary.final_tick > max {
max = item.summary.final_tick
}
}
max
}
///|
pub fn ExperimentReport::render(self : ExperimentReport) -> String {
let buf = StringBuilder::new()
buf.write_string("# Experiment " + self.title + "\n")
buf.write_string("cases: " + self.case_count().to_string() + "\n")
buf.write_string("events: " + self.total_events().to_string() + "\n")
buf.write_string("max_tick: " + self.max_final_tick().to_string() + "\n")
buf.write_string("digest: " + self.combined_digest().to_string() + "\n")
for item in self.cases {
buf.write_string("- " + item.name + ": " + item.summary.line())
if item.notes != "" {
buf.write_string(" (" + item.notes + ")")
}
buf.write_string("\n")
}
buf.to_string()
}
///|
pub fn demo_experiment() -> ExperimentReport {
ExperimentReport::new("moonsim model demo")
.add(
experiment_case(
"queue",
queue_summary(run_queue_model(queue_config(customers=5))),
notes="arrival and service model",
),
)
.add(
experiment_case(
"retry",
retry_summary(run_retry_model(retry_config(fail_until=2))),
notes="deterministic backoff",
),
)
.add(
experiment_case(
"traffic",
traffic_summary(run_traffic_model(traffic_config(cars=12))),
notes="timer and sample metrics",
),
)
.add(
experiment_case(
"network",
network_summary(run_network_model(network_config(messages=6))),
notes="message delivery and retry",
),
)
.add(
experiment_case(
"load_balancer",
load_balancer_summary(
run_load_balancer_model(load_balancer_config(jobs=8)),
),
notes="worker scheduling model",
),
)
.add(
experiment_case(
"circuit_breaker",
run_circuit_breaker_model(calls=8).summary(),
notes="service protection model",
),
)
.add(
experiment_case(
"token_bucket",
run_token_bucket_model(requests=8).summary(),
notes="rate limiting model",
),
)
}
///|
pub fn compare_experiments(
left : ExperimentReport,
right : ExperimentReport,
) -> TraceComparison {
let left_entries : Array[TraceEntry] = []
let right_entries : Array[TraceEntry] = []
for i in 0..