use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
use mun_runtime::StructRef;
use wasmer::Store;
mod util;
pub fn fibonacci_benchmark(c: &mut Criterion) {
let runtime = util::runtime_from_file("fibonacci.mun");
let lua = util::lua_from_file("fibonacci.lua");
let mut wasm_store = Store::default();
let wasm = util::wasmer_from_file(&mut wasm_store, "fibonacci.wasm");
let wasm_func = wasm.exports.get_function("main").unwrap();
let mut group = c.benchmark_group("fibonacci");
for i in [100i64, 200i64, 500i64, 1000i64, 4000i64, 8000i64].iter() {
group.bench_with_input(BenchmarkId::new("mun", i), i, |b, i| {
b.iter(|| {
let _: i64 = runtime.invoke("main", (*i,)).unwrap();
})
});
group.bench_with_input(BenchmarkId::new("rust", i), i, |b, i| {
b.iter(|| fibonacci_main(*i))
});
group.bench_with_input(BenchmarkId::new("luajit", i), i, |b, i| {
b.iter(|| {
let f: mlua::Function = lua.globals().get("main").unwrap();
let _: i64 = f.call(*i).unwrap();
})
});
group.bench_with_input(BenchmarkId::new("wasm", i), i, |b, i| {
b.iter(|| {
wasm_func
.call(&mut wasm_store, &[(*i as i32).into()])
.unwrap();
})
});
}
group.finish();
fn fibonacci(n: i64) -> i64 {
let mut a = 0;
let mut b = 1;
let mut i = 1;
loop {
if i > n {
return a;
}
let sum = a.wrapping_add(b);
a = b;
b = sum;
i += 1;
}
}
fn fibonacci_main(n: i64) -> i64 {
fibonacci(n)
}
}
pub fn empty_benchmark(c: &mut Criterion) {
let runtime = util::runtime_from_file("empty.mun");
let lua = util::lua_from_file("empty.lua");
let mut wasm_store = Store::default();
let wasm = util::wasmer_from_file(&mut wasm_store, "empty.wasm");
let wasm_func = wasm.exports.get_function("empty").unwrap();
let mut group = c.benchmark_group("empty");
group.bench_function("mun", |b| {
b.iter(|| {
let _: i64 = runtime.invoke("empty", (black_box(20i64),)).unwrap();
})
});
group.bench_function("rust", |b| b.iter(|| empty(black_box(20))));
group.bench_function("luajit", |b| {
b.iter(|| {
let f: mlua::Function = lua.globals().get("empty").unwrap();
let _: i64 = f.call(black_box(20)).unwrap();
})
});
group.bench_function("wasm", |b| {
b.iter(|| wasm_func.call(&mut wasm_store, &[black_box(20i64).into()]))
});
group.finish();
pub fn empty(n: i64) -> i64 {
n
}
}
#[derive(Clone, Default)]
struct RustChild(f32, f32, f32, f32);
struct RustParent<'a> {
value: RustChild,
reference: &'a RustChild,
}
pub fn get_struct_field_benchmark(c: &mut Criterion) {
let runtime = util::runtime_from_file("struct.mun");
let mun_gc_parent: StructRef = runtime.invoke("make_gc_parent", ()).unwrap();
let mun_value_parent: StructRef = runtime.invoke("make_value_parent", ()).unwrap();
let rust_child = RustChild(-2.0, -1.0, 1.0, 2.0);
let rust_parent = RustParent {
value: rust_child.clone(),
reference: &rust_child,
};
let mut group = c.benchmark_group("get_struct_field");
for i in [100i64, 200i64, 500i64, 1000i64].iter() {
{
let child = mun_gc_parent.get::<StructRef>("child").unwrap();
group.bench_with_input(BenchmarkId::new("mun fundamental", i), i, |b, i| {
b.iter(|| {
for _ in 0..*i {
let _x = black_box(child.get::<f32>("0").unwrap());
}
})
});
}
group.bench_with_input(BenchmarkId::new("rust fundamental", i), i, |b, i| {
b.iter(|| {
for _ in 0..*i {
let _child = black_box(rust_child.0);
}
})
});
group.bench_with_input(BenchmarkId::new("mun struct(gc)", i), i, |b, i| {
b.iter(|| {
for _ in 0..*i {
let _child = black_box(mun_gc_parent.get::<StructRef>("child").unwrap());
}
})
});
group.bench_with_input(BenchmarkId::new("mun struct(value)", i), i, |b, i| {
b.iter(|| {
for _ in 0..*i {
let _child = black_box(mun_value_parent.get::<StructRef>("child").unwrap());
}
})
});
group.bench_with_input(BenchmarkId::new("rust struct", i), i, |b, i| {
b.iter(|| {
for _ in 0..*i {
let _child = black_box(rust_parent.value.clone());
}
})
});
group.bench_with_input(BenchmarkId::new("rust &struct", i), i, |b, i| {
b.iter(|| {
for _ in 0..*i {
let _child = black_box(rust_parent.reference);
}
})
});
}
group.finish();
}
pub fn set_struct_field_benchmark(c: &mut Criterion) {
let runtime = util::runtime_from_file("struct.mun");
let mut mun_gc_parent: StructRef = runtime.invoke("make_value_parent", ()).unwrap();
let mut mun_value_parent: StructRef = runtime.invoke("make_value_parent", ()).unwrap();
let rust_child = RustChild(-2.0, -1.0, 1.0, 2.0);
let mut rust_child2 = rust_child.clone();
let rust_child3 = RustChild {
0: std::f32::consts::PI,
..Default::default()
};
let mut rust_parent = RustParent {
value: rust_child.clone(),
reference: &rust_child,
};
let mut group = c.benchmark_group("set_struct_field");
for i in [100i64, 200i64, 500i64, 1000i64].iter() {
let mut gc_child = mun_gc_parent.get::<StructRef>("child").unwrap();
group.bench_with_input(BenchmarkId::new("mun fundamental", i), i, |b, i| {
b.iter(|| {
for _ in 0..*i {
gc_child.set("0", -std::f32::consts::PI).unwrap();
}
})
});
group.bench_with_input(BenchmarkId::new("rust fundamental", i), i, |b, i| {
b.iter(|| {
for _ in 0..*i {
rust_child2.0 = -std::f32::consts::PI;
black_box(&rust_child2);
}
})
});
group.bench_with_input(BenchmarkId::new("mun struct(gc)", i), i, |b, i| {
b.iter(|| {
for _ in 0..*i {
mun_gc_parent.set("child", gc_child.clone()).unwrap();
}
})
});
let value_child = mun_value_parent.get::<StructRef>("child").unwrap();
group.bench_with_input(BenchmarkId::new("mun struct(value)", i), i, |b, i| {
b.iter(|| {
for _ in 0..*i {
mun_value_parent.set("child", value_child.clone()).unwrap();
}
})
});
group.bench_with_input(BenchmarkId::new("rust struct", i), i, |b, i| {
b.iter(|| {
for _ in 0..*i {
rust_parent.value = rust_child.clone();
black_box(&rust_parent.value);
}
})
});
group.bench_with_input(BenchmarkId::new("rust &struct", i), i, |b, i| {
b.iter(|| {
for _ in 0..*i {
rust_parent.reference = &rust_child3;
black_box(rust_parent.reference);
}
})
});
}
group.finish();
}
criterion_group!(
benches,
fibonacci_benchmark,
empty_benchmark,
get_struct_field_benchmark,
set_struct_field_benchmark
);
criterion_main!(benches);