summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenry Gressmann <mail@henrygressmann.de>2024-01-30 01:12:38 +0100
committerHenry Gressmann <mail@henrygressmann.de>2024-01-30 01:12:38 +0100
commit893396aa3ce270280a2a1a87007a4b84edc8b898 (patch)
tree59690b8bee97a158a01dd49f4b6e611bdf284546
parent4919d8c2f86f69f669a1afba2a28d5c344fe7197 (diff)
perf: add more benchmarks
Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
-rw-r--r--Cargo.lock52
-rw-r--r--Cargo.toml6
-rw-r--r--README.md2
-rw-r--r--benches/argon2id.rs60
-rw-r--r--benches/fibonacci.rs42
-rw-r--r--benches/selfhosted.rs30
-rw-r--r--benches/util/mod.rs10
-rw-r--r--examples/rust/Cargo.toml5
-rwxr-xr-xexamples/rust/build.sh4
-rw-r--r--examples/rust/src/argon2id.rs14
-rw-r--r--examples/rust/src/fibonacci.rs8
-rw-r--r--examples/rust/src/print.rs7
12 files changed, 218 insertions, 22 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 8f97f2b..396573a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -120,6 +120,18 @@ dependencies = [
]
[[package]]
+name = "argon2"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072"
+dependencies = [
+ "base64ct",
+ "blake2",
+ "cpufeatures",
+ "password-hash",
+]
+
+[[package]]
name = "arrayvec"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -164,6 +176,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
+name = "base64ct"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
+
+[[package]]
name = "bincode"
version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -197,6 +215,15 @@ dependencies = [
]
[[package]]
+name = "blake2"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
+dependencies = [
+ "digest",
+]
+
+[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -855,6 +882,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
+ "subtle",
]
[[package]]
@@ -1653,6 +1681,17 @@ dependencies = [
]
[[package]]
+name = "password-hash"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
+dependencies = [
+ "base64ct",
+ "rand_core",
+ "subtle",
+]
+
+[[package]]
name = "paste"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1842,6 +1881,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+
+[[package]]
name = "rayon"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2209,6 +2254,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
+name = "subtle"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
+
+[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2349,6 +2400,7 @@ dependencies = [
name = "tinywasm-root"
version = "0.0.0"
dependencies = [
+ "argon2",
"color-eyre",
"criterion",
"tinywasm",
diff --git a/Cargo.toml b/Cargo.toml
index fae5388..104c809 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -33,6 +33,11 @@ harness=false
name="fibonacci"
harness=false
+
+[[bench]]
+name="argon2id"
+harness=false
+
[profile.bench]
opt-level=3
lto="thin"
@@ -48,3 +53,4 @@ wat={version="1.0"}
wasmi={version="0.31", features=["std"]}
wasmer={version="4.2", features=["cranelift", "singlepass"]}
wasmtime={version="17.0", features=["cranelift"]}
+argon2={version="0.5"}
diff --git a/README.md b/README.md
index 17e966f..ec1648b 100644
--- a/README.md
+++ b/README.md
@@ -22,7 +22,7 @@ TinyWasm, starting from version `0.3.0`, passes all the WebAssembly 1.0 tests in
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.
-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.
+TinyWasm is not (yet) designed for performance, but rather for simplicity, size and portability. See [Performance](#performance) for more details.
## Supported Proposals
diff --git a/benches/argon2id.rs b/benches/argon2id.rs
new file mode 100644
index 0000000..4504812
--- /dev/null
+++ b/benches/argon2id.rs
@@ -0,0 +1,60 @@
+mod util;
+use criterion::{black_box, criterion_group, criterion_main, Criterion};
+use util::wasm_to_twasm;
+
+fn run_tinywasm(twasm: &[u8], params: (i32, i32, i32), name: &str) {
+ let (mut store, instance) = util::tinywasm(twasm);
+ let argon2 = instance.exported_func::<(i32, i32, i32), i32>(&store, name).expect("exported_func");
+ argon2.call(&mut store, params).expect("call");
+}
+
+fn run_wasmi(wasm: &[u8], params: (i32, i32, i32), name: &str) {
+ let (module, mut store, linker) = util::wasmi(wasm);
+ let instance = linker.instantiate(&mut store, &module).expect("instantiate").start(&mut store).expect("start");
+ let argon2 = instance.get_typed_func::<(i32, i32, i32), i32>(&mut store, name).expect("get_typed_func");
+ argon2.call(&mut store, params).expect("call");
+}
+
+fn run_wasmer(wasm: &[u8], params: (i32, i32, i32), name: &str) {
+ use wasmer::Value;
+ let (mut store, instance) = util::wasmer(wasm);
+ let argon2 = instance.exports.get_function(name).expect("get_function");
+ argon2.call(&mut store, &[Value::I32(params.0), Value::I32(params.1), Value::I32(params.2)]).expect("call");
+}
+
+fn run_native(params: (i32, i32, i32)) {
+ fn run_native(m_cost: i32, t_cost: i32, p_cost: i32) {
+ let password = b"password";
+ let salt = b"some random salt";
+
+ let params = argon2::Params::new(m_cost as u32, t_cost as u32, p_cost as u32, None).unwrap();
+ let argon = argon2::Argon2::new(argon2::Algorithm::Argon2id, argon2::Version::V0x13, params);
+
+ let mut hash = [0u8; 32];
+ argon.hash_password_into(password, salt, &mut hash).unwrap();
+ }
+ run_native(params.0, params.1, params.2)
+}
+
+const ARGON2ID: &[u8] = include_bytes!("../examples/rust/out/argon2id.wasm");
+fn criterion_benchmark(c: &mut Criterion) {
+ let twasm = wasm_to_twasm(ARGON2ID);
+ let params = (1000, 2, 1);
+
+ let mut group = c.benchmark_group("argon2id");
+ group.measurement_time(std::time::Duration::from_secs(7));
+ group.sample_size(10);
+
+ group.bench_function("native", |b| b.iter(|| run_native(black_box(params))));
+ group.bench_function("tinywasm", |b| b.iter(|| run_tinywasm(&twasm, black_box(params), "argon2id")));
+ group.bench_function("wasmi", |b| b.iter(|| run_wasmi(&ARGON2ID, black_box(params), "argon2id")));
+ group.bench_function("wasmer", |b| b.iter(|| run_wasmer(&ARGON2ID, black_box(params), "argon2id")));
+}
+
+criterion_group!(
+ name = benches;
+ config = Criterion::default().significance_level(0.1);
+ targets = criterion_benchmark
+);
+
+criterion_main!(benches);
diff --git a/benches/fibonacci.rs b/benches/fibonacci.rs
index ca83869..1d1134a 100644
--- a/benches/fibonacci.rs
+++ b/benches/fibonacci.rs
@@ -4,15 +4,45 @@ use util::wasm_to_twasm;
fn run_tinywasm(twasm: &[u8], iterations: i32, name: &str) {
let (mut store, instance) = util::tinywasm(twasm);
- let hello = instance.exported_func::<i32, i32>(&store, name).expect("exported_func");
- hello.call(&mut store, iterations).expect("call");
+ let fib = instance.exported_func::<i32, i32>(&store, name).expect("exported_func");
+ fib.call(&mut store, iterations).expect("call");
}
fn run_wasmi(wasm: &[u8], iterations: i32, name: &str) {
let (module, mut store, linker) = util::wasmi(wasm);
let instance = linker.instantiate(&mut store, &module).expect("instantiate").start(&mut store).expect("start");
- let hello = instance.get_typed_func::<i32, i32>(&mut store, name).expect("get_typed_func");
- hello.call(&mut store, iterations).expect("call");
+ let fib = instance.get_typed_func::<i32, i32>(&mut store, name).expect("get_typed_func");
+ fib.call(&mut store, iterations).expect("call");
+}
+
+fn run_wasmer(wasm: &[u8], iterations: i32, name: &str) {
+ use wasmer::*;
+ let engine: Engine = wasmer::Singlepass::default().into();
+ let mut store = Store::default();
+ let import_object = imports! {};
+ let module = wasmer::Module::from_binary(&engine, &wasm).expect("wasmer::Module::from_binary");
+ let instance = Instance::new(&mut store, &module, &import_object).expect("Instance::new");
+ let fib = instance.exports.get_typed_function::<i32, i32>(&mut store, name).expect("get_function");
+ fib.call(&mut store, iterations).expect("call");
+}
+
+fn run_native(n: i32) -> i32 {
+ let mut sum = 0;
+ let mut last = 0;
+ let mut curr = 1;
+ for _i in 1..n {
+ sum = last + curr;
+ last = curr;
+ curr = sum;
+ }
+ sum
+}
+
+fn run_native_recursive(n: i32) -> i32 {
+ if n <= 1 {
+ return n;
+ }
+ run_native_recursive(n - 1) + run_native_recursive(n - 2)
}
const FIBONACCI: &[u8] = include_bytes!("../examples/rust/out/fibonacci.wasm");
@@ -21,15 +51,19 @@ fn criterion_benchmark(c: &mut Criterion) {
{
let mut group = c.benchmark_group("fibonacci");
+ group.bench_function("native", |b| b.iter(|| run_native(black_box(60))));
group.bench_function("tinywasm", |b| b.iter(|| run_tinywasm(&twasm, black_box(60), "fibonacci")));
group.bench_function("wasmi", |b| b.iter(|| run_wasmi(&FIBONACCI, black_box(60), "fibonacci")));
+ group.bench_function("wasmer", |b| b.iter(|| run_wasmer(&FIBONACCI, black_box(60), "fibonacci")));
}
{
let mut group = c.benchmark_group("fibonacci-recursive");
group.measurement_time(std::time::Duration::from_secs(5));
+ group.bench_function("native", |b| b.iter(|| run_native_recursive(black_box(26))));
group.bench_function("tinywasm", |b| b.iter(|| run_tinywasm(&twasm, black_box(26), "fibonacci_recursive")));
group.bench_function("wasmi", |b| b.iter(|| run_wasmi(&FIBONACCI, black_box(26), "fibonacci_recursive")));
+ group.bench_function("wasmer", |b| b.iter(|| run_wasmer(&FIBONACCI, black_box(26), "fibonacci_recursive")));
}
}
diff --git a/benches/selfhosted.rs b/benches/selfhosted.rs
index 4464579..57146e7 100644
--- a/benches/selfhosted.rs
+++ b/benches/selfhosted.rs
@@ -3,6 +3,17 @@ use criterion::{criterion_group, criterion_main, Criterion};
use crate::util::twasm_to_module;
+fn run_native() {
+ use tinywasm::*;
+ let module = tinywasm::Module::parse_bytes(include_bytes!("../examples/rust/out/print.wasm")).expect("parse");
+ let mut store = Store::default();
+ let mut imports = Imports::default();
+ imports.define("env", "printi32", Extern::typed_func(|_: FuncContext<'_>, _: i32| Ok(()))).expect("define");
+ let instance = ModuleInstance::instantiate(&mut store, module, Some(imports)).expect("instantiate");
+ let hello = instance.exported_func::<(i32, i32), ()>(&store, "add_and_print").expect("exported_func");
+ hello.call(&mut store, (2, 3)).expect("call");
+}
+
fn run_tinywasm(twasm: &[u8]) {
use tinywasm::*;
let module = twasm_to_module(twasm);
@@ -26,18 +37,35 @@ fn run_wasmi(wasm: &[u8]) {
hello.call(&mut store, ()).expect("call");
}
+fn run_wasmer(wasm: &[u8]) {
+ use wasmer::*;
+ let engine = wasmer::Engine::default();
+ let mut store = Store::default();
+ let import_object = imports! {
+ "env" => {
+ "printi32" => Function::new_typed(&mut store, |_: i32| {}),
+ },
+ };
+ let module = wasmer::Module::from_binary(&engine, &wasm).expect("wasmer::Module::from_binary");
+ let instance = Instance::new(&mut store, &module, &import_object).expect("Instance::new");
+ let hello = instance.exports.get_function("hello").expect("get_function");
+ hello.call(&mut store, &[]).expect("call");
+}
+
const TINYWASM: &[u8] = include_bytes!("../examples/rust/out/tinywasm.wasm");
fn criterion_benchmark(c: &mut Criterion) {
let twasm = util::wasm_to_twasm(TINYWASM);
let mut group = c.benchmark_group("selfhosted");
+ group.bench_function("native", |b| b.iter(|| run_native()));
group.bench_function("tinywasm", |b| b.iter(|| run_tinywasm(&twasm)));
group.bench_function("wasmi", |b| b.iter(|| run_wasmi(TINYWASM)));
+ group.bench_function("wasmer", |b| b.iter(|| run_wasmer(TINYWASM)));
}
criterion_group!(
name = benches;
- config = Criterion::default().sample_size(500).measurement_time(std::time::Duration::from_secs(5)).significance_level(0.1);
+ config = Criterion::default().sample_size(100).measurement_time(std::time::Duration::from_secs(5)).significance_level(0.1);
targets = criterion_benchmark
);
diff --git a/benches/util/mod.rs b/benches/util/mod.rs
index 69510a5..aa7b418 100644
--- a/benches/util/mod.rs
+++ b/benches/util/mod.rs
@@ -30,3 +30,13 @@ pub fn wasmi(wasm: &[u8]) -> (wasmi::Module, wasmi::Store<()>, wasmi::Linker<()>
let linker = <Linker<()>>::new(&engine);
(module, store, linker)
}
+
+pub fn wasmer(wasm: &[u8]) -> (wasmer::Store, wasmer::Instance) {
+ use wasmer::*;
+ let engine: Engine = wasmer::Singlepass::default().into();
+ let mut store = Store::default();
+ let import_object = imports! {};
+ let module = wasmer::Module::from_binary(&engine, &wasm).expect("wasmer::Module::from_binary");
+ let instance = Instance::new(&mut store, &module, &import_object).expect("Instance::new");
+ (store, instance)
+}
diff --git a/examples/rust/Cargo.toml b/examples/rust/Cargo.toml
index 2d06488..f3f475e 100644
--- a/examples/rust/Cargo.toml
+++ b/examples/rust/Cargo.toml
@@ -11,6 +11,7 @@ edition="2021"
[dependencies]
tinywasm={path="../../crates/tinywasm", features=["parser", "std", "unsafe"]}
+argon2={version="0.5"}
[[bin]]
name="hello"
@@ -28,6 +29,10 @@ path="src/tinywasm.rs"
name="fibonacci"
path="src/fibonacci.rs"
+[[bin]]
+name="argon2id"
+path="src/argon2id.rs"
+
[profile.wasm]
opt-level=3
lto="thin"
diff --git a/examples/rust/build.sh b/examples/rust/build.sh
index cabf00e..e6d3b0d 100755
--- a/examples/rust/build.sh
+++ b/examples/rust/build.sh
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
cd "$(dirname "$0")"
-bins=("hello" "fibonacci" "print" "tinywasm")
+bins=("hello" "fibonacci" "print" "tinywasm" "argon2id")
exclude_wat=("tinywasm")
out_dir="./target/wasm32-unknown-unknown/wasm"
dest_dir="out"
@@ -15,7 +15,7 @@ for bin in "${bins[@]}"; do
RUSTFLAGS="-C target-feature=$features -C panic=abort" cargo build --target wasm32-unknown-unknown --package rust-wasm-examples --profile=wasm --bin "$bin"
cp "$out_dir/$bin.wasm" "$dest_dir/"
- wasm-opt "$dest_dir/$bin.wasm" -o "$dest_dir/$bin.wasm" -O --intrinsic-lowering -O
+ wasm-opt "$dest_dir/$bin.wasm" -o "$dest_dir/$bin.wasm" -Oz --enable-bulk-memory --enable-multivalue --enable-reference-types --enable-mutable-globals
if [[ ! " ${exclude_wat[@]} " =~ " $bin " ]]; then
wasm2wat "$dest_dir/$bin.wasm" -o "$dest_dir/$bin.wat"
diff --git a/examples/rust/src/argon2id.rs b/examples/rust/src/argon2id.rs
new file mode 100644
index 0000000..01ea7ca
--- /dev/null
+++ b/examples/rust/src/argon2id.rs
@@ -0,0 +1,14 @@
+#![no_main]
+
+#[no_mangle]
+pub extern "C" fn argon2id(m_cost: i32, t_cost: i32, p_cost: i32) -> i32 {
+ let password = b"password";
+ let salt = b"some random salt";
+
+ let params = argon2::Params::new(m_cost as u32, t_cost as u32, p_cost as u32, None).unwrap();
+ let argon = argon2::Argon2::new(argon2::Algorithm::Argon2id, argon2::Version::V0x13, params);
+
+ let mut hash = [0u8; 32];
+ argon.hash_password_into(password, salt, &mut hash).unwrap();
+ hash[0] as i32
+}
diff --git a/examples/rust/src/fibonacci.rs b/examples/rust/src/fibonacci.rs
index 7924aef..8de496d 100644
--- a/examples/rust/src/fibonacci.rs
+++ b/examples/rust/src/fibonacci.rs
@@ -1,11 +1,5 @@
-#![no_std]
#![no_main]
-
-#[cfg(not(test))]
-#[panic_handler]
-fn panic(_info: &core::panic::PanicInfo) -> ! {
- core::arch::wasm32::unreachable()
-}
+#![allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn fibonacci(n: i32) -> i32 {
diff --git a/examples/rust/src/print.rs b/examples/rust/src/print.rs
index 34f3c7f..d04daa3 100644
--- a/examples/rust/src/print.rs
+++ b/examples/rust/src/print.rs
@@ -1,12 +1,5 @@
-#![no_std]
#![no_main]
-#[cfg(not(test))]
-#[panic_handler]
-fn panic(_info: &core::panic::PanicInfo) -> ! {
- core::arch::wasm32::unreachable()
-}
-
#[link(wasm_import_module = "env")]
extern "C" {
fn printi32(x: i32);