Skip to main content

aver/
runtime_bench_cases.rs

1pub struct CoreBenchCase {
2    pub slug: &'static str,
3    pub name: &'static str,
4    pub source: &'static str,
5}
6
7impl CoreBenchCase {
8    pub fn module_root(&self) -> Option<&'static str> {
9        match self.slug {
10            "json_roundtrip_1k" => Some("examples"),
11            _ => None,
12        }
13    }
14
15    pub fn source_is_module(&self) -> bool {
16        self.source.trim_start().starts_with("module ")
17    }
18}
19
20const FIBONACCI: &str = "\
21fn fib(n: Int) -> Int
22    match n < 2
23        true -> n
24        false -> fib(n - 1) + fib(n - 2)
25
26fn main() -> Int
27    fib(25)
28";
29
30const SUM_TCO: &str = "\
31fn sum(n: Int, acc: Int) -> Int
32    match n == 0
33        true -> acc
34        false -> sum(n - 1, acc + n)
35
36fn main() -> Int
37    sum(10000000, 0)
38";
39
40const COUNTDOWN: &str = "\
41fn countdown(n: Int) -> Int
42    match n == 0
43        true -> 0
44        false -> countdown(n - 1)
45
46fn main() -> Int
47    countdown(10000000)
48";
49
50const FACTORIAL_TCO: &str = "\
51fn fact(n: Int, acc: Int) -> Int
52    match n == 0
53        true -> acc
54        false -> fact(n - 1, acc * n)
55
56fn repeat(n: Int, acc: Int) -> Int
57    match n == 0
58        true -> acc
59        false -> repeat(n - 1, acc + Result.withDefault(Int.mod(fact(20, 1), 1000000), 0))
60
61fn main() -> Int
62    repeat(50000, 0)
63";
64
65const NESTED_MATCH: &str = "\
66fn 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";
67
68const RESULT_CHAIN: &str = "\
69fn 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";
70
71const LIST_WALK: &str = "\
72fn 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";
73
74const SHAPES: &str = "\
75type 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";
76
77const RECORD_HEAVY: &str = "\
78record 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";
79
80const STRING_BUILD: &str = "\
81fn 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";
82
83const ERROR_PIPELINE: &str = "\
84fn 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";
85
86const LIST_BUILTINS: &str = "\
87fn 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";
88
89const LIST_APPEND_SCAN: &str = "\
90fn 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";
91
92const MIXED_REAL: &str = "\
93record 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";
94
95const LIST_GET_OR: &str = "\
96fn 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";
97
98const JSON_ROUNDTRIP: &str = r#"module Bench
99    intent =
100        "Runtime benchmark case for the pure JSON module."
101        "Parses and re-serializes a nested object repeatedly."
102    depends [Data.Json]
103    effects [Console]
104
105fn sampleJson() -> String
106    "{{\"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}}}}}}"
107
108fn roundtripLen(raw: String) -> Int
109    match Data.Json.fromString(raw)
110        Result.Err(_) -> 0
111        Result.Ok(value) -> String.len(Data.Json.toString(value))
112
113fn loop(n: Int, raw: String, acc: Int) -> Int
114    match n == 0
115        true -> acc
116        false -> loop(n - 1, raw, acc + roundtripLen(raw))
117
118fn benchMain() -> Int
119    loop(1000, sampleJson(), 0)
120
121fn main() -> Unit
122    ! [Console.print]
123    Console.print("{benchMain()}")
124"#;
125
126pub const CORE_BENCH_CASES: &[CoreBenchCase] = &[
127    CoreBenchCase {
128        slug: "fib_25",
129        name: "fib(25)",
130        source: FIBONACCI,
131    },
132    CoreBenchCase {
133        slug: "sum_tco_10m",
134        name: "sum_tco(10M)",
135        source: SUM_TCO,
136    },
137    CoreBenchCase {
138        slug: "countdown_10m",
139        name: "countdown(10M)",
140        source: COUNTDOWN,
141    },
142    CoreBenchCase {
143        slug: "factorial_20",
144        name: "factorial(20) x 50K",
145        source: FACTORIAL_TCO,
146    },
147    CoreBenchCase {
148        slug: "nested_match_360k",
149        name: "nested_match(360K)",
150        source: NESTED_MATCH,
151    },
152    CoreBenchCase {
153        slug: "result_chain_400k",
154        name: "result_chain(400K)",
155        source: RESULT_CHAIN,
156    },
157    CoreBenchCase {
158        slug: "list_walk_100k",
159        name: "list_walk(100K x5)",
160        source: LIST_WALK,
161    },
162    CoreBenchCase {
163        slug: "shapes_300k",
164        name: "shapes(300K)",
165        source: SHAPES,
166    },
167    CoreBenchCase {
168        slug: "record_heavy_400k",
169        name: "record_heavy(400K)",
170        source: RECORD_HEAVY,
171    },
172    CoreBenchCase {
173        slug: "string_build_20k",
174        name: "string_build(20K)",
175        source: STRING_BUILD,
176    },
177    CoreBenchCase {
178        slug: "error_pipeline_200k",
179        name: "error_pipeline(200K)",
180        source: ERROR_PIPELINE,
181    },
182    CoreBenchCase {
183        slug: "list_builtins_400k",
184        name: "list_builtins(400K)",
185        source: LIST_BUILTINS,
186    },
187    CoreBenchCase {
188        slug: "list_append_scan_1k",
189        name: "list_append_scan(12K)",
190        source: LIST_APPEND_SCAN,
191    },
192    CoreBenchCase {
193        slug: "mixed_real_200k",
194        name: "mixed_real(200K)",
195        source: MIXED_REAL,
196    },
197    CoreBenchCase {
198        slug: "list_get_or_30k",
199        name: "list_get_or(30K)",
200        source: LIST_GET_OR,
201    },
202    CoreBenchCase {
203        slug: "json_roundtrip_1k",
204        name: "json_roundtrip(1K)",
205        source: JSON_ROUNDTRIP,
206    },
207];