From 7fef7eba854bcea6c45650e00afb5f3546e6be3a Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Tue, 17 May 2022 23:34:46 -0400 Subject: [PATCH] Add cfold benchmark - can't go over 5 (though Koka uses 20) because wasm runs out of stack. Not entirely sure how to handle that - I imagine we're emitting far to much on the stack frame, but also I would hope wasmtime would optimize it, and I additionally can't find a way to raise wasmtime's limit from the cli... It is worth noting that Koka notes that cfold is a benchmark that can exhaust the stack --- koka_bench/cfold_table.md | 5 + koka_bench/cpp/CMakeLists.txt | 2 +- koka_bench/cpp/cfold.cpp | 172 +++++++++++++++++++++++++++++++++ koka_bench/koka/CMakeLists.txt | 2 +- koka_bench/koka/cfold.kk | 70 ++++++++++++++ koka_bench/test.sh | 1 + 6 files changed, 250 insertions(+), 2 deletions(-) create mode 100644 koka_bench/cfold_table.md create mode 100644 koka_bench/cpp/cfold.cpp create mode 100644 koka_bench/koka/cfold.kk diff --git a/koka_bench/cfold_table.md b/koka_bench/cfold_table.md new file mode 100644 index 0000000..8073a14 --- /dev/null +++ b/koka_bench/cfold_table.md @@ -0,0 +1,5 @@ +| Command | Mean [ms] | Min [ms] | Max [ms] | Relative | +|:---|---:|---:|---:|---:| +| `build/kraken/out/bench/kraken-cfold 5` | 24.6 ± 1.0 | 22.9 | 27.5 | 52.26 ± 36.33 | +| `build/cpp/cpp-cfold 5` | 0.8 ± 0.4 | 0.5 | 2.6 | 1.78 ± 1.45 | +| `build/koka/out/bench/kk-cfold 5` | 0.5 ± 0.3 | 0.2 | 2.9 | 1.00 | diff --git a/koka_bench/cpp/CMakeLists.txt b/koka_bench/cpp/CMakeLists.txt index b4421ef..6bafe8e 100644 --- a/koka_bench/cpp/CMakeLists.txt +++ b/koka_bench/cpp/CMakeLists.txt @@ -2,7 +2,7 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED YES) set(CMAKE_CXX_EXTENSIONS NO) -foreach (source IN ITEMS rbtree.cpp nqueens.cpp) +foreach (source IN ITEMS rbtree.cpp nqueens.cpp cfold.cpp) get_filename_component(name "${source}" NAME_WE) set(name "cpp-${name}") diff --git a/koka_bench/cpp/cfold.cpp b/koka_bench/cpp/cfold.cpp new file mode 100644 index 0000000..55ac8e7 --- /dev/null +++ b/koka_bench/cpp/cfold.cpp @@ -0,0 +1,172 @@ +#include +#include +#include + +enum Kind { + Val, + Var, + Add, + Mul, +}; + +class Expr { +public: + Kind kind; + Expr(Kind k) { + this->kind = k; + } +}; + +class ValExpr : public Expr { +public: + long value; + ValExpr(long i) : Expr(Val) { + this->value = i; + } +}; + +class VarExpr : public Expr { +public: + long name; + VarExpr( long n ) : Expr(Var) { + this->name = n; + } +}; + +class AddExpr : public Expr { +public: + const Expr* left; + const Expr* right; + AddExpr( const Expr* e1, const Expr* e2 ) : Expr(Add) { + this->left = e1; + this->right = e2; + } +}; + +class MulExpr : public Expr { +public: + const Expr* left; + const Expr* right; + MulExpr( const Expr* e1, const Expr* e2 ) : Expr(Mul) { + this->left = e1; + this->right = e2; + } +}; + + +static const Expr* mk_expr( long n, long v ) { + if (n==0) { + if (v==0) return new VarExpr(1); + else return new ValExpr(v); + } + else { + return new AddExpr(mk_expr(n-1,v+1),mk_expr(n-1,v == 0 ? 0 : v - 1)); + } +} + +static const Expr* append_add( const Expr* e1, const Expr* e2 ) { + if (e1->kind == Add) { + const AddExpr* x = (AddExpr*)e1; + return new AddExpr( x->left, append_add(x->right, e2)); + } + else { + return new AddExpr(e1,e2); + } +} + +static const Expr* append_mul( const Expr* e1, const Expr* e2 ) { + if (e1->kind == Mul) { + const MulExpr* x = (MulExpr*)e1; + return new MulExpr( x->left, append_mul(x->right, e2)); + } + else { + return new MulExpr(e1,e2); + } +} + +static const Expr* reassoc( const Expr* e ) { + if (e->kind == Add) { + const AddExpr* x = (AddExpr*)e; + return append_add( reassoc(x->left), reassoc(x->right) ); + } + else if (e->kind == Mul) { + const MulExpr* x = (MulExpr*)e; + return append_mul( reassoc(x->left), reassoc(x->right) ); + } + else return e; +} + +static const Expr* const_folding( const Expr* e ) { + if (e->kind == Add) { + const Expr* e1 = ((AddExpr*)e)->left; + const Expr* e2 = ((AddExpr*)e)->right; + if (e1->kind == Val && e2->kind==Val) { + return new ValExpr( ((ValExpr*)e1)->value + ((ValExpr*)e2)->value ); + } + else if (e1->kind == Val && e2->kind==Add && ((AddExpr*)e2)->right->kind == Val) { + AddExpr* b = (AddExpr*)e2; + ValExpr* v = (ValExpr*)(b->right); + return new AddExpr( new ValExpr(((ValExpr*)e1)->value + v->value ), b->left ); + } + else if (e1->kind == Val && e2->kind==Add && ((AddExpr*)e2)->left->kind == Val) { + AddExpr* b = (AddExpr*)e2; + ValExpr* v = (ValExpr*)(b->left); + return new AddExpr( new ValExpr(((ValExpr*)e1)->value + v->value ), b->right ); + } + else { + return new AddExpr(e1,e2); + } + } + else if (e->kind == Mul) { + const Expr* e1 = ((MulExpr*)e)->left; + const Expr* e2 = ((MulExpr*)e)->right; + if (e1->kind == Val && e2->kind==Val) { + return new ValExpr( ((ValExpr*)e1)->value * ((ValExpr*)e2)->value ); + } + else if (e1->kind == Val && e2->kind==Mul && ((MulExpr*)e2)->right->kind == Val) { + MulExpr* b = (MulExpr*)e2; + ValExpr* v = (ValExpr*)(b->right); + return new MulExpr( new ValExpr(((ValExpr*)e1)->value * v->value ), b->left ); + } + else if (e1->kind == Val && e2->kind==Mul && ((MulExpr*)e2)->left->kind == Val) { + MulExpr* b = (MulExpr*)e2; + ValExpr* v = (ValExpr*)(b->left); + return new MulExpr( new ValExpr(((ValExpr*)e1)->value * v->value ), b->right ); + } + else { + return new MulExpr(e1,e2); + } + } + else return e; +} + +static long eval( const Expr* e ) { + if (e->kind == Var) { + return 0; + } + else if (e->kind == Val) { + return ((ValExpr*)e)->value; + } + else if (e->kind == Add) { + return eval(((AddExpr*)e)->left) + eval(((AddExpr*)e)->right); + } + else if (e->kind == Mul) { + return eval(((MulExpr*)e)->left) * eval(((MulExpr*)e)->right); + } + else { + return 0; + } +} + + +int main(int argc, char ** argv) { + int n = 20; + if (argc == 2) { + n = atoi(argv[1]); + } + const Expr* e = mk_expr(n,1); + long v1 = eval(e); + long v2 = eval(const_folding(reassoc(e))); + std::cout << v1 << ", " << v2 << "\n"; + return 0; +} diff --git a/koka_bench/koka/CMakeLists.txt b/koka_bench/koka/CMakeLists.txt index e06719f..2743a71 100644 --- a/koka_bench/koka/CMakeLists.txt +++ b/koka_bench/koka/CMakeLists.txt @@ -1,4 +1,4 @@ -set(sources rbtree.kk nqueens.kk nqueens-int.kk) +set(sources rbtree.kk nqueens.kk nqueens-int.kk cfold.kk) set(koka koka) diff --git a/koka_bench/koka/cfold.kk b/koka_bench/koka/cfold.kk new file mode 100644 index 0000000..1f9e516 --- /dev/null +++ b/koka_bench/koka/cfold.kk @@ -0,0 +1,70 @@ +// Adapted from https://github.com/leanprover/lean4/blob/IFL19/tests/bench/const_fold.hs +import std/os/env +type expr + Var( : int ) + Val( : int ) + Add( l : expr, r : expr ) + Mul( l : expr, r : expr ) + +fun mk_expr( n : int, v : int ) : div expr + if n==0 + then (if v==0 then Var(1) else Val(v)) + else Add( mk_expr(n - 1, v+1), mk_expr(n - 1, max(v - 1,0)) ) + +fun append_add( e0 : expr, e3 : expr ) : expr + match e0 + Add(e1,e2) -> Add(e1, append_add(e2,e3)) + _ -> Add(e0,e3) + +fun append_mul( e0 : expr, e3 : expr ) : expr + match e0 + Mul(e1,e2) -> Mul(e1, append_mul(e2,e3)) + _ -> Mul(e0,e3) + +fun reassoc( e : expr ) : expr + match e + Add(e1,e2) -> append_add(reassoc(e1), reassoc(e2)) + Mul(e1,e2) -> append_mul(reassoc(e1), reassoc(e2)) + _ -> e + +fun cfold( e : expr ) : expr + match e + Add(e1,e2) -> + val e1' = cfold(e1) + val e2' = cfold(e2) + match e1' + Val(a) -> match e2' + Val(b) -> Val(a+b) + Add(f,Val(b)) -> Add(Val(a+b),f) + Add(Val(b),f) -> Add(Val(a+b),f) + _ -> Add(e1',e2') + _ -> Add(e1',e2') + Mul(e1,e2) -> + val e1' = cfold(e1) + val e2' = cfold(e2) + match e1' + Val(a) -> match e2' + Val(b) -> Val(a*b) + Mul(f,Val(b)) -> Mul(Val(a*b),f) + Mul(Val(b),f) -> Mul(Val(a*b),f) + _ -> Mul(e1',e2') + _ -> Mul(e1',e2') + _ -> e + + +fun eval(e : expr) : int + match e + Var -> 0 + Val(v) -> v + Add(l,r) -> eval(l) + eval(r) + Mul(l,r) -> eval(l) * eval(r) + + +pub fun main() + val n = get-args().head("").parse-int.default(20) + val e = mk_expr(n,1) + val v1 = eval(e) + val v2 = e.reassoc.cfold.eval + println( v1.show ) + println( v2.show ) + diff --git a/koka_bench/test.sh b/koka_bench/test.sh index aa1e55f..75d7d5c 100755 --- a/koka_bench/test.sh +++ b/koka_bench/test.sh @@ -14,3 +14,4 @@ popd nix develop -i -c bash -c 'ulimit -s unlimited && find build -type f -executable -name \*nqueens\* -printf "\"%p 10\"\n" | xargs hyperfine --ignore-failure --warmup 2 --export-markdown rbnqueens_table.md' nix develop -i -c bash -c 'ulimit -s unlimited && find build -type f -executable -name \*rbtree\* -printf "\"%p 42000\"\n" | xargs hyperfine --ignore-failure --warmup 2 --export-markdown rbtree_table.md' +nix develop -i -c bash -c 'ulimit -s unlimited && find build -type f -executable -name \*cfold\* -printf "\"%p 5\"\n" | xargs hyperfine --ignore-failure --warmup 2 --export-markdown cfold_table.md'