pub struct CoreBenchCase {
pub slug: &'static str,
pub name: &'static str,
pub source: &'static str,
}
impl CoreBenchCase {
pub fn module_root(&self) -> Option<&'static str> {
match self.slug {
"json_roundtrip_1k" => Some("examples"),
_ => None,
}
}
pub fn source_is_module(&self) -> bool {
self.source.trim_start().starts_with("module ")
}
}
const FIBONACCI: &str = "\
fn fib(n: Int) -> Int
match n < 2
true -> n
false -> fib(n - 1) + fib(n - 2)
fn main() -> Int
fib(25)
";
const SUM_TCO: &str = "\
fn sum(n: Int, acc: Int) -> Int
match n == 0
true -> acc
false -> sum(n - 1, acc + n)
fn main() -> Int
sum(10000000, 0)
";
const COUNTDOWN: &str = "\
fn countdown(n: Int) -> Int
match n == 0
true -> 0
false -> countdown(n - 1)
fn main() -> Int
countdown(10000000)
";
const FACTORIAL_TCO: &str = "\
fn fact(n: Int, acc: Int) -> Int
match n == 0
true -> acc
false -> fact(n - 1, acc * n)
fn repeat(n: Int, acc: Int) -> Int
match n == 0
true -> acc
false -> repeat(n - 1, acc + Result.withDefault(Int.mod(fact(20, 1), 1000000), 0))
fn main() -> Int
repeat(50000, 0)
";
const NESTED_MATCH: &str = "\
fn abs(n: Int) -> Int\n match n < 0\n true -> 0 - n\n false -> n\n\nfn classify(n: Int) -> Int\n match n == 0\n true -> 0\n false -> abs(n) * 2\n\nfn run(n: Int, acc: Int) -> Int\n match n == 0\n true -> acc\n false -> run(n - 1, acc + classify(n - 180000))\n\nfn main() -> Int\n run(360000, 0)\n";
const RESULT_CHAIN: &str = "\
fn safeDivide(a: Int, b: Int) -> Result<Int, Int>\n match b == 0\n true -> Result.Err(0)\n false -> Result.Ok(a / b)\n\nfn unwrapOr(r: Result<Int, Int>, d: Int) -> Int\n match r\n Result.Ok(v) -> v\n Result.Err(_) -> d\n\nfn chain(n: Int, acc: Int) -> Int\n match n == 0\n true -> acc\n false -> chain(n - 1, acc + unwrapOr(safeDivide(n * 10, n), 0))\n\nfn main() -> Int\n chain(400000, 0)\n";
const LIST_WALK: &str = "\
fn build(n: Int, acc: List<Int>) -> List<Int>\n match n == 0\n true -> acc\n false -> build(n - 1, List.prepend(n, acc))\n\nfn listLen(xs: List<Int>, acc: Int) -> Int\n match xs\n [] -> acc\n [h, ..t] -> listLen(t, acc + 1)\n\nfn walkFive(xs: List<Int>) -> Int\n listLen(xs, 0) + listLen(xs, 0) + listLen(xs, 0) + listLen(xs, 0) + listLen(xs, 0)\n\nfn main() -> Int\n walkFive(build(100000, []))\n";
const SHAPES: &str = "\
type Shape\n Circle(Float)\n Rect(Float, Float)\n Point\n\nfn area(s: Shape) -> Float\n match s\n Shape.Circle(r) -> r * r * 3.14159\n Shape.Rect(w, h) -> w * h\n Shape.Point -> 0.0\n\nfn sumAreas(n: Int, acc: Float) -> Float\n match n == 0\n true -> acc\n false -> sumAreas(n - 1, acc + area(Shape.Circle(1.0)) + area(Shape.Rect(3.0, 4.0)))\n\nfn main() -> Float\n sumAreas(300000, 0.0)\n";
const RECORD_HEAVY: &str = "\
record Point\n x: Int\n y: Int\n\nfn moveRight(p: Point) -> Point\n Point.update(p, x = p.x + 1)\n\nfn walk(n: Int, p: Point) -> Int\n match n == 0\n true -> p.x + p.y\n false -> walk(n - 1, moveRight(p))\n\nfn main() -> Int\n walk(400000, Point(x = 0, y = 0))\n";
const STRING_BUILD: &str = "\
fn repeat(n: Int, s: String, acc: String) -> String\n match n == 0\n true -> acc\n false -> repeat(n - 1, s, acc + s)\n\nfn main() -> Int\n r = repeat(20000, \"ab\", \"\")\n String.len(r)\n";
const ERROR_PIPELINE: &str = "\
fn validate(n: Int) -> Result<Int, String>\n match n < 0\n true -> Result.Err(\"negative\")\n false -> Result.Ok(n)\n\nfn transform(n: Int) -> Result<Int, String>\n match n > 1000\n true -> Result.Err(\"too large\")\n false -> Result.Ok(n * 2)\n\nfn pipeline(n: Int) -> Result<Int, String>\n v = validate(n)?\n transform(v)\n\nfn run(n: Int, acc: Int) -> Int\n match n == 0\n true -> acc\n false -> run(n - 1, acc + Result.withDefault(pipeline(n), 0))\n\nfn main() -> Int\n run(200000, 0)\n";
const LIST_BUILTINS: &str = "\
fn buildAndMeasure(n: Int, acc: List<Int>) -> Int\n match n == 0\n true -> List.len(acc)\n false -> buildAndMeasure(n - 1, List.prepend(n, acc))\n\nfn main() -> Int\n buildAndMeasure(400000, [])\n";
const LIST_APPEND_SCAN: &str = "\
fn build(n: Int, acc: List<Int>) -> List<Int>\n match n == 0\n true -> acc\n false -> build(n - 1, List.prepend(n, acc))\n\nfn sum(v: Vector<Int>, size: Int, i: Int, acc: Int) -> Int\n match i == size\n true -> acc\n false -> sum(v, size, i + 1, acc + Option.withDefault(Vector.get(v, i), 0))\n\nfn main() -> Int\n xs = List.reverse(build(12000, []))\n v = Vector.fromList(xs)\n sum(v, Vector.len(v), 0, 0)\n";
const MIXED_REAL: &str = "\
record Order\n id: Int\n amount: Int\n valid: Bool\n\nfn processOrder(o: Order) -> Result<Int, String>\n match o.valid\n true -> Result.Ok(o.amount * 2)\n false -> Result.Err(\"invalid\")\n\nfn processAll(n: Int, acc: Int) -> Int\n match n == 0\n true -> acc\n false -> processAll(n - 1, acc + Result.withDefault(processOrder(Order(id = n, amount = n * 10, valid = true)), 0))\n\nfn main() -> Int\n processAll(200000, 0)\n";
const LIST_GET_OR: &str = "\
fn build(n: Int, acc: List<Int>) -> List<Int>\n match n == 0\n true -> List.reverse(acc)\n false -> build(n - 1, List.prepend(n, acc))\n\nfn scan(v: Vector<Int>, size: Int, i: Int, acc: Int) -> Int\n match i == size\n true -> acc\n false -> scan(v, size, i + 1, acc + Option.withDefault(Vector.get(v, i), 0))\n\nfn main() -> Int\n xs = build(10000, [])\n v = Vector.fromList(xs)\n scan(v, 10000, 0, 0) + scan(v, 10000, 0, 0) + scan(v, 10000, 0, 0)\n";
const JSON_ROUNDTRIP: &str = r#"module Bench
intent =
"Runtime benchmark case for the pure JSON module."
"Parses and re-serializes a nested object repeatedly."
depends [Data.Json]
effects [Console]
fn sampleJson() -> String
"{{\"service\":\"aver\",\"version\":\"0.14\",\"score\":14,\"edge\":true,\"runtime\":{{\"target\":\"edge-wasm\",\"provider\":\"cloudflare\",\"packed\":true,\"preset\":\"cloudflare\"}},\"items\":[{{\"name\":\"json\",\"ok\":true,\"size\":136}},{{\"name\":\"wasm\",\"ok\":true,\"size\":4800}},{{\"name\":\"worker\",\"ok\":true,\"regions\":[\"waw\",\"iad\",\"nrt\"]}}],\"meta\":{{\"commit\":\"a9e6924\",\"notes\":[\"pure\",\"typed\",\"effects\"],\"limits\":{{\"cold_start\":0,\"external_fetch\":false}}}}}}"
fn roundtripLen(raw: String) -> Int
match Data.Json.fromString(raw)
Result.Err(_) -> 0
Result.Ok(value) -> String.len(Data.Json.toString(value))
fn loop(n: Int, raw: String, acc: Int) -> Int
match n == 0
true -> acc
false -> loop(n - 1, raw, acc + roundtripLen(raw))
fn benchMain() -> Int
loop(1000, sampleJson(), 0)
fn main() -> Unit
! [Console.print]
Console.print("{benchMain()}")
"#;
pub const CORE_BENCH_CASES: &[CoreBenchCase] = &[
CoreBenchCase {
slug: "fib_25",
name: "fib(25)",
source: FIBONACCI,
},
CoreBenchCase {
slug: "sum_tco_10m",
name: "sum_tco(10M)",
source: SUM_TCO,
},
CoreBenchCase {
slug: "countdown_10m",
name: "countdown(10M)",
source: COUNTDOWN,
},
CoreBenchCase {
slug: "factorial_20",
name: "factorial(20) x 50K",
source: FACTORIAL_TCO,
},
CoreBenchCase {
slug: "nested_match_360k",
name: "nested_match(360K)",
source: NESTED_MATCH,
},
CoreBenchCase {
slug: "result_chain_400k",
name: "result_chain(400K)",
source: RESULT_CHAIN,
},
CoreBenchCase {
slug: "list_walk_100k",
name: "list_walk(100K x5)",
source: LIST_WALK,
},
CoreBenchCase {
slug: "shapes_300k",
name: "shapes(300K)",
source: SHAPES,
},
CoreBenchCase {
slug: "record_heavy_400k",
name: "record_heavy(400K)",
source: RECORD_HEAVY,
},
CoreBenchCase {
slug: "string_build_20k",
name: "string_build(20K)",
source: STRING_BUILD,
},
CoreBenchCase {
slug: "error_pipeline_200k",
name: "error_pipeline(200K)",
source: ERROR_PIPELINE,
},
CoreBenchCase {
slug: "list_builtins_400k",
name: "list_builtins(400K)",
source: LIST_BUILTINS,
},
CoreBenchCase {
slug: "list_append_scan_1k",
name: "list_append_scan(12K)",
source: LIST_APPEND_SCAN,
},
CoreBenchCase {
slug: "mixed_real_200k",
name: "mixed_real(200K)",
source: MIXED_REAL,
},
CoreBenchCase {
slug: "list_get_or_30k",
name: "list_get_or(30K)",
source: LIST_GET_OR,
},
CoreBenchCase {
slug: "json_roundtrip_1k",
name: "json_roundtrip(1K)",
source: JSON_ROUNDTRIP,
},
];