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
This commit is contained in:
5
koka_bench/cfold_table.md
Normal file
5
koka_bench/cfold_table.md
Normal file
@@ -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 |
|
||||
@@ -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}")
|
||||
|
||||
|
||||
172
koka_bench/cpp/cfold.cpp
Normal file
172
koka_bench/cpp/cfold.cpp
Normal file
@@ -0,0 +1,172 @@
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <iostream>
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
|
||||
70
koka_bench/koka/cfold.kk
Normal file
70
koka_bench/koka/cfold.kk
Normal file
@@ -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 )
|
||||
|
||||
@@ -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'
|
||||
|
||||
Reference in New Issue
Block a user