Skip to content

Commit 893396a

Browse files
perf: add more benchmarks
Signed-off-by: Henry Gressmann <[email protected]>
1 parent 4919d8c commit 893396a

File tree

12 files changed

+218
-22
lines changed

12 files changed

+218
-22
lines changed

Cargo.lock

Lines changed: 52 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ harness=false
3333
name="fibonacci"
3434
harness=false
3535

36+
37+
[[bench]]
38+
name="argon2id"
39+
harness=false
40+
3641
[profile.bench]
3742
opt-level=3
3843
lto="thin"
@@ -48,3 +53,4 @@ wat={version="1.0"}
4853
wasmi={version="0.31", features=["std"]}
4954
wasmer={version="4.2", features=["cranelift", "singlepass"]}
5055
wasmtime={version="17.0", features=["cranelift"]}
56+
argon2={version="0.5"}

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ TinyWasm, starting from version `0.3.0`, passes all the WebAssembly 1.0 tests in
2222

2323
Some APIs to interact with the runtime are not yet exposed, and the existing ones are subject to change, but the core functionality is mostly complete.
2424

25-
TinyWasm is not designed for performance, but rather for simplicity, size and portability. However, it is still reasonably fast, especially when compared to other interpreters. See [Performance](#performance) for more details.
25+
TinyWasm is not (yet) designed for performance, but rather for simplicity, size and portability. See [Performance](#performance) for more details.
2626

2727
## Supported Proposals
2828

benches/argon2id.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
mod util;
2+
use criterion::{black_box, criterion_group, criterion_main, Criterion};
3+
use util::wasm_to_twasm;
4+
5+
fn run_tinywasm(twasm: &[u8], params: (i32, i32, i32), name: &str) {
6+
let (mut store, instance) = util::tinywasm(twasm);
7+
let argon2 = instance.exported_func::<(i32, i32, i32), i32>(&store, name).expect("exported_func");
8+
argon2.call(&mut store, params).expect("call");
9+
}
10+
11+
fn run_wasmi(wasm: &[u8], params: (i32, i32, i32), name: &str) {
12+
let (module, mut store, linker) = util::wasmi(wasm);
13+
let instance = linker.instantiate(&mut store, &module).expect("instantiate").start(&mut store).expect("start");
14+
let argon2 = instance.get_typed_func::<(i32, i32, i32), i32>(&mut store, name).expect("get_typed_func");
15+
argon2.call(&mut store, params).expect("call");
16+
}
17+
18+
fn run_wasmer(wasm: &[u8], params: (i32, i32, i32), name: &str) {
19+
use wasmer::Value;
20+
let (mut store, instance) = util::wasmer(wasm);
21+
let argon2 = instance.exports.get_function(name).expect("get_function");
22+
argon2.call(&mut store, &[Value::I32(params.0), Value::I32(params.1), Value::I32(params.2)]).expect("call");
23+
}
24+
25+
fn run_native(params: (i32, i32, i32)) {
26+
fn run_native(m_cost: i32, t_cost: i32, p_cost: i32) {
27+
let password = b"password";
28+
let salt = b"some random salt";
29+
30+
let params = argon2::Params::new(m_cost as u32, t_cost as u32, p_cost as u32, None).unwrap();
31+
let argon = argon2::Argon2::new(argon2::Algorithm::Argon2id, argon2::Version::V0x13, params);
32+
33+
let mut hash = [0u8; 32];
34+
argon.hash_password_into(password, salt, &mut hash).unwrap();
35+
}
36+
run_native(params.0, params.1, params.2)
37+
}
38+
39+
const ARGON2ID: &[u8] = include_bytes!("../examples/rust/out/argon2id.wasm");
40+
fn criterion_benchmark(c: &mut Criterion) {
41+
let twasm = wasm_to_twasm(ARGON2ID);
42+
let params = (1000, 2, 1);
43+
44+
let mut group = c.benchmark_group("argon2id");
45+
group.measurement_time(std::time::Duration::from_secs(7));
46+
group.sample_size(10);
47+
48+
group.bench_function("native", |b| b.iter(|| run_native(black_box(params))));
49+
group.bench_function("tinywasm", |b| b.iter(|| run_tinywasm(&twasm, black_box(params), "argon2id")));
50+
group.bench_function("wasmi", |b| b.iter(|| run_wasmi(&ARGON2ID, black_box(params), "argon2id")));
51+
group.bench_function("wasmer", |b| b.iter(|| run_wasmer(&ARGON2ID, black_box(params), "argon2id")));
52+
}
53+
54+
criterion_group!(
55+
name = benches;
56+
config = Criterion::default().significance_level(0.1);
57+
targets = criterion_benchmark
58+
);
59+
60+
criterion_main!(benches);

benches/fibonacci.rs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,45 @@ use util::wasm_to_twasm;
44

55
fn run_tinywasm(twasm: &[u8], iterations: i32, name: &str) {
66
let (mut store, instance) = util::tinywasm(twasm);
7-
let hello = instance.exported_func::<i32, i32>(&store, name).expect("exported_func");
8-
hello.call(&mut store, iterations).expect("call");
7+
let fib = instance.exported_func::<i32, i32>(&store, name).expect("exported_func");
8+
fib.call(&mut store, iterations).expect("call");
99
}
1010

1111
fn run_wasmi(wasm: &[u8], iterations: i32, name: &str) {
1212
let (module, mut store, linker) = util::wasmi(wasm);
1313
let instance = linker.instantiate(&mut store, &module).expect("instantiate").start(&mut store).expect("start");
14-
let hello = instance.get_typed_func::<i32, i32>(&mut store, name).expect("get_typed_func");
15-
hello.call(&mut store, iterations).expect("call");
14+
let fib = instance.get_typed_func::<i32, i32>(&mut store, name).expect("get_typed_func");
15+
fib.call(&mut store, iterations).expect("call");
16+
}
17+
18+
fn run_wasmer(wasm: &[u8], iterations: i32, name: &str) {
19+
use wasmer::*;
20+
let engine: Engine = wasmer::Singlepass::default().into();
21+
let mut store = Store::default();
22+
let import_object = imports! {};
23+
let module = wasmer::Module::from_binary(&engine, &wasm).expect("wasmer::Module::from_binary");
24+
let instance = Instance::new(&mut store, &module, &import_object).expect("Instance::new");
25+
let fib = instance.exports.get_typed_function::<i32, i32>(&mut store, name).expect("get_function");
26+
fib.call(&mut store, iterations).expect("call");
27+
}
28+
29+
fn run_native(n: i32) -> i32 {
30+
let mut sum = 0;
31+
let mut last = 0;
32+
let mut curr = 1;
33+
for _i in 1..n {
34+
sum = last + curr;
35+
last = curr;
36+
curr = sum;
37+
}
38+
sum
39+
}
40+
41+
fn run_native_recursive(n: i32) -> i32 {
42+
if n <= 1 {
43+
return n;
44+
}
45+
run_native_recursive(n - 1) + run_native_recursive(n - 2)
1646
}
1747

1848
const FIBONACCI: &[u8] = include_bytes!("../examples/rust/out/fibonacci.wasm");
@@ -21,15 +51,19 @@ fn criterion_benchmark(c: &mut Criterion) {
2151

2252
{
2353
let mut group = c.benchmark_group("fibonacci");
54+
group.bench_function("native", |b| b.iter(|| run_native(black_box(60))));
2455
group.bench_function("tinywasm", |b| b.iter(|| run_tinywasm(&twasm, black_box(60), "fibonacci")));
2556
group.bench_function("wasmi", |b| b.iter(|| run_wasmi(&FIBONACCI, black_box(60), "fibonacci")));
57+
group.bench_function("wasmer", |b| b.iter(|| run_wasmer(&FIBONACCI, black_box(60), "fibonacci")));
2658
}
2759

2860
{
2961
let mut group = c.benchmark_group("fibonacci-recursive");
3062
group.measurement_time(std::time::Duration::from_secs(5));
63+
group.bench_function("native", |b| b.iter(|| run_native_recursive(black_box(26))));
3164
group.bench_function("tinywasm", |b| b.iter(|| run_tinywasm(&twasm, black_box(26), "fibonacci_recursive")));
3265
group.bench_function("wasmi", |b| b.iter(|| run_wasmi(&FIBONACCI, black_box(26), "fibonacci_recursive")));
66+
group.bench_function("wasmer", |b| b.iter(|| run_wasmer(&FIBONACCI, black_box(26), "fibonacci_recursive")));
3367
}
3468
}
3569

benches/selfhosted.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,17 @@ use criterion::{criterion_group, criterion_main, Criterion};
33

44
use crate::util::twasm_to_module;
55

6+
fn run_native() {
7+
use tinywasm::*;
8+
let module = tinywasm::Module::parse_bytes(include_bytes!("../examples/rust/out/print.wasm")).expect("parse");
9+
let mut store = Store::default();
10+
let mut imports = Imports::default();
11+
imports.define("env", "printi32", Extern::typed_func(|_: FuncContext<'_>, _: i32| Ok(()))).expect("define");
12+
let instance = ModuleInstance::instantiate(&mut store, module, Some(imports)).expect("instantiate");
13+
let hello = instance.exported_func::<(i32, i32), ()>(&store, "add_and_print").expect("exported_func");
14+
hello.call(&mut store, (2, 3)).expect("call");
15+
}
16+
617
fn run_tinywasm(twasm: &[u8]) {
718
use tinywasm::*;
819
let module = twasm_to_module(twasm);
@@ -26,18 +37,35 @@ fn run_wasmi(wasm: &[u8]) {
2637
hello.call(&mut store, ()).expect("call");
2738
}
2839

40+
fn run_wasmer(wasm: &[u8]) {
41+
use wasmer::*;
42+
let engine = wasmer::Engine::default();
43+
let mut store = Store::default();
44+
let import_object = imports! {
45+
"env" => {
46+
"printi32" => Function::new_typed(&mut store, |_: i32| {}),
47+
},
48+
};
49+
let module = wasmer::Module::from_binary(&engine, &wasm).expect("wasmer::Module::from_binary");
50+
let instance = Instance::new(&mut store, &module, &import_object).expect("Instance::new");
51+
let hello = instance.exports.get_function("hello").expect("get_function");
52+
hello.call(&mut store, &[]).expect("call");
53+
}
54+
2955
const TINYWASM: &[u8] = include_bytes!("../examples/rust/out/tinywasm.wasm");
3056
fn criterion_benchmark(c: &mut Criterion) {
3157
let twasm = util::wasm_to_twasm(TINYWASM);
3258

3359
let mut group = c.benchmark_group("selfhosted");
60+
group.bench_function("native", |b| b.iter(|| run_native()));
3461
group.bench_function("tinywasm", |b| b.iter(|| run_tinywasm(&twasm)));
3562
group.bench_function("wasmi", |b| b.iter(|| run_wasmi(TINYWASM)));
63+
group.bench_function("wasmer", |b| b.iter(|| run_wasmer(TINYWASM)));
3664
}
3765

3866
criterion_group!(
3967
name = benches;
40-
config = Criterion::default().sample_size(500).measurement_time(std::time::Duration::from_secs(5)).significance_level(0.1);
68+
config = Criterion::default().sample_size(100).measurement_time(std::time::Duration::from_secs(5)).significance_level(0.1);
4169
targets = criterion_benchmark
4270
);
4371

benches/util/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,13 @@ pub fn wasmi(wasm: &[u8]) -> (wasmi::Module, wasmi::Store<()>, wasmi::Linker<()>
3030
let linker = <Linker<()>>::new(&engine);
3131
(module, store, linker)
3232
}
33+
34+
pub fn wasmer(wasm: &[u8]) -> (wasmer::Store, wasmer::Instance) {
35+
use wasmer::*;
36+
let engine: Engine = wasmer::Singlepass::default().into();
37+
let mut store = Store::default();
38+
let import_object = imports! {};
39+
let module = wasmer::Module::from_binary(&engine, &wasm).expect("wasmer::Module::from_binary");
40+
let instance = Instance::new(&mut store, &module, &import_object).expect("Instance::new");
41+
(store, instance)
42+
}

examples/rust/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ edition="2021"
1111

1212
[dependencies]
1313
tinywasm={path="../../crates/tinywasm", features=["parser", "std", "unsafe"]}
14+
argon2={version="0.5"}
1415

1516
[[bin]]
1617
name="hello"
@@ -28,6 +29,10 @@ path="src/tinywasm.rs"
2829
name="fibonacci"
2930
path="src/fibonacci.rs"
3031

32+
[[bin]]
33+
name="argon2id"
34+
path="src/argon2id.rs"
35+
3136
[profile.wasm]
3237
opt-level=3
3338
lto="thin"

examples/rust/build.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env bash
22
cd "$(dirname "$0")"
33

4-
bins=("hello" "fibonacci" "print" "tinywasm")
4+
bins=("hello" "fibonacci" "print" "tinywasm" "argon2id")
55
exclude_wat=("tinywasm")
66
out_dir="./target/wasm32-unknown-unknown/wasm"
77
dest_dir="out"
@@ -15,7 +15,7 @@ for bin in "${bins[@]}"; do
1515
RUSTFLAGS="-C target-feature=$features -C panic=abort" cargo build --target wasm32-unknown-unknown --package rust-wasm-examples --profile=wasm --bin "$bin"
1616

1717
cp "$out_dir/$bin.wasm" "$dest_dir/"
18-
wasm-opt "$dest_dir/$bin.wasm" -o "$dest_dir/$bin.wasm" -O --intrinsic-lowering -O
18+
wasm-opt "$dest_dir/$bin.wasm" -o "$dest_dir/$bin.wasm" -Oz --enable-bulk-memory --enable-multivalue --enable-reference-types --enable-mutable-globals
1919

2020
if [[ ! " ${exclude_wat[@]} " =~ " $bin " ]]; then
2121
wasm2wat "$dest_dir/$bin.wasm" -o "$dest_dir/$bin.wat"

examples/rust/src/argon2id.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#![no_main]
2+
3+
#[no_mangle]
4+
pub extern "C" fn argon2id(m_cost: i32, t_cost: i32, p_cost: i32) -> i32 {
5+
let password = b"password";
6+
let salt = b"some random salt";
7+
8+
let params = argon2::Params::new(m_cost as u32, t_cost as u32, p_cost as u32, None).unwrap();
9+
let argon = argon2::Argon2::new(argon2::Algorithm::Argon2id, argon2::Version::V0x13, params);
10+
11+
let mut hash = [0u8; 32];
12+
argon.hash_password_into(password, salt, &mut hash).unwrap();
13+
hash[0] as i32
14+
}

0 commit comments

Comments
 (0)