Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4919d8c

Browse files
perf: improve benchmarks
Signed-off-by: Henry Gressmann <[email protected]>
1 parent 963ddd2 commit 4919d8c

File tree

7 files changed

+75
-65
lines changed

7 files changed

+75
-65
lines changed

benches/README.md renamed to BENCHMARKS.md

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,23 @@ All runtimes are compiled with the following settings:
2020
- `unsafe` features are enabled
2121
- `opt-level` is set to 3, `lto` is set to `thin`, `codegen-units` is set to 1.
2222

23-
## Benchmarking
23+
# Running benchmarks
2424

25-
Benchmarks are run using [Criterion.rs](https://github.com/bheisler/criterion.rs) and can be found in the `benches` directory.
26-
27-
## Running benchmarks
25+
Benchmarks are run using [Criterion.rs](https://github.com/bheisler/criterion.rs). To run a benchmark, use the following command:
2826

2927
```sh
3028
$ cargo bench --bench <name>
3129
```
30+
31+
## Profiling
32+
33+
To profile a benchmark, use the following command:
34+
35+
```sh
36+
$ cargo flamegraph --bench <name> -- --bench
37+
```
38+
39+
This will generate a flamegraph in `flamegraph.svg` and a `perf.data` file.
40+
You can use [hotspot](https://github.com/KDAB/hotspot) to analyze the `perf.data` file.
41+
Since a lot of functions are inlined, you probably want to remove the `#[inline]` attribute from the functions you care about.
42+
Note that this will make the benchmark considerably slower, 2-10x slower in some cases.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ debug=true
4343
color-eyre="0.6"
4444
criterion={version="0.5", features=["html_reports"]}
4545

46-
tinywasm={path="crates/tinywasm"}
46+
tinywasm={path="crates/tinywasm", features=["unsafe"]}
4747
wat={version="1.0"}
4848
wasmi={version="0.31", features=["std"]}
4949
wasmer={version="4.2", features=["cranelift", "singlepass"]}

README.md

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
## Why TinyWasm?
1414

1515
- **Tiny** - Designed to be as small as possible without sacrificing too much performance or functionality.
16-
- **Fast enough** - TinyWasm is reasonably fast, especially when compared to other interpreters. See [Performance](#performance) for more details.
16+
- **Fast enough** - TinyWasm is reasonably fast, especially when compared to other interpreters. See [Benchmarks](./BENCHMARKS.md) for more details.
1717
- **Portable** - Runs on any platform llvm supports, including WebAssembly. Minimal external dependencies.
1818

1919
## Status
@@ -69,10 +69,6 @@ $ tinywasm-cli --help
6969
With all these features disabled, TinyWasm only depends on `core`, `alloc` and `libm` and can be used in `no_std` environments.
7070
Since `libm` is not as performant as the compiler's math intrinsics, it is recommended to use the `std` feature if possible (at least [for now](https://github.com/rust-lang/rfcs/issues/2505)), especially on wasm32 targets.
7171

72-
## Performance
73-
74-
> Benchmarks are coming soon.
75-
7672
## License
7773

7874
Licensed under either of [Apache License, Version 2.0](./LICENSE-APACHE) or [MIT license](./LICENSE-MIT) at your option.

benches/fibonacci.rs

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,41 @@
11
mod util;
22
use criterion::{black_box, criterion_group, criterion_main, Criterion};
3-
use tinywasm::types::TinyWasmModule;
4-
use util::tinywasm_module;
3+
use util::wasm_to_twasm;
54

6-
fn run_tinywasm(module: TinyWasmModule, iterations: i32) {
7-
use tinywasm::*;
8-
let module = Module::from(module);
9-
let mut store = Store::default();
10-
let imports = Imports::default();
11-
let instance = ModuleInstance::instantiate(&mut store, module, Some(imports)).expect("instantiate");
12-
let hello = instance.exported_func::<i32, i32>(&store, "fibonacci").expect("exported_func");
5+
fn run_tinywasm(twasm: &[u8], iterations: i32, name: &str) {
6+
let (mut store, instance) = util::tinywasm(twasm);
7+
let hello = instance.exported_func::<i32, i32>(&store, name).expect("exported_func");
138
hello.call(&mut store, iterations).expect("call");
149
}
1510

16-
fn run_wasmi(iterations: i32) {
17-
use wasmi::*;
18-
let engine = Engine::default();
19-
let module = wasmi::Module::new(&engine, FIBONACCI).expect("wasmi::Module::new");
20-
let mut store = Store::new(&engine, ());
21-
let linker = <Linker<()>>::new(&engine);
11+
fn run_wasmi(wasm: &[u8], iterations: i32, name: &str) {
12+
let (module, mut store, linker) = util::wasmi(wasm);
2213
let instance = linker.instantiate(&mut store, &module).expect("instantiate").start(&mut store).expect("start");
23-
let hello = instance.get_typed_func::<i32, i32>(&mut store, "fibonacci").expect("get_typed_func");
14+
let hello = instance.get_typed_func::<i32, i32>(&mut store, name).expect("get_typed_func");
2415
hello.call(&mut store, iterations).expect("call");
2516
}
2617

2718
const FIBONACCI: &[u8] = include_bytes!("../examples/rust/out/fibonacci.wasm");
2819
fn criterion_benchmark(c: &mut Criterion) {
29-
let module = tinywasm_module(FIBONACCI);
20+
let twasm = wasm_to_twasm(FIBONACCI);
3021

31-
let mut group = c.benchmark_group("fibonacci");
32-
group.bench_function("tinywasm", |b| b.iter(|| run_tinywasm(module.clone(), black_box(60))));
33-
group.bench_function("wasmi", |b| b.iter(|| run_wasmi(black_box(60))));
22+
{
23+
let mut group = c.benchmark_group("fibonacci");
24+
group.bench_function("tinywasm", |b| b.iter(|| run_tinywasm(&twasm, black_box(60), "fibonacci")));
25+
group.bench_function("wasmi", |b| b.iter(|| run_wasmi(&FIBONACCI, black_box(60), "fibonacci")));
26+
}
27+
28+
{
29+
let mut group = c.benchmark_group("fibonacci-recursive");
30+
group.measurement_time(std::time::Duration::from_secs(5));
31+
group.bench_function("tinywasm", |b| b.iter(|| run_tinywasm(&twasm, black_box(26), "fibonacci_recursive")));
32+
group.bench_function("wasmi", |b| b.iter(|| run_wasmi(&FIBONACCI, black_box(26), "fibonacci_recursive")));
33+
}
3434
}
3535

3636
criterion_group!(
3737
name = benches;
38-
config = Criterion::default().sample_size(50).measurement_time(std::time::Duration::from_secs(5)).significance_level(0.1);
38+
config = Criterion::default().significance_level(0.1);
3939
targets = criterion_benchmark
4040
);
4141

benches/selfhosted.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
mod util;
22
use criterion::{criterion_group, criterion_main, Criterion};
3-
use tinywasm::types::TinyWasmModule;
4-
use util::tinywasm_module;
53

6-
fn run_tinywasm(module: TinyWasmModule) {
4+
use crate::util::twasm_to_module;
5+
6+
fn run_tinywasm(twasm: &[u8]) {
77
use tinywasm::*;
8-
let module = Module::from(module);
8+
let module = twasm_to_module(twasm);
99
let mut store = Store::default();
1010
let mut imports = Imports::default();
1111
imports.define("env", "printi32", Extern::typed_func(|_: FuncContext<'_>, _: i32| Ok(()))).expect("define");
@@ -14,10 +14,10 @@ fn run_tinywasm(module: TinyWasmModule) {
1414
hello.call(&mut store, ()).expect("call");
1515
}
1616

17-
fn run_wasmi() {
17+
fn run_wasmi(wasm: &[u8]) {
1818
use wasmi::*;
1919
let engine = Engine::default();
20-
let module = wasmi::Module::new(&engine, TINYWASM).expect("wasmi::Module::new");
20+
let module = wasmi::Module::new(&engine, wasm).expect("wasmi::Module::new");
2121
let mut store = Store::new(&engine, ());
2222
let mut linker = <Linker<()>>::new(&engine);
2323
linker.define("env", "printi32", Func::wrap(&mut store, |_: Caller<'_, ()>, _: i32| {})).expect("define");
@@ -28,11 +28,11 @@ fn run_wasmi() {
2828

2929
const TINYWASM: &[u8] = include_bytes!("../examples/rust/out/tinywasm.wasm");
3030
fn criterion_benchmark(c: &mut Criterion) {
31-
let module = tinywasm_module(TINYWASM);
31+
let twasm = util::wasm_to_twasm(TINYWASM);
3232

3333
let mut group = c.benchmark_group("selfhosted");
34-
group.bench_function("tinywasm", |b| b.iter(|| run_tinywasm(module.clone())));
35-
group.bench_function("wasmi", |b| b.iter(run_wasmi));
34+
group.bench_function("tinywasm", |b| b.iter(|| run_tinywasm(&twasm)));
35+
group.bench_function("wasmi", |b| b.iter(|| run_wasmi(TINYWASM)));
3636
}
3737

3838
criterion_group!(

benches/util/mod.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,32 @@
1+
#![allow(dead_code)]
2+
13
use tinywasm::{self, parser::Parser, types::TinyWasmModule};
24

3-
pub fn tinywasm_module(wasm: &[u8]) -> TinyWasmModule {
5+
pub fn wasm_to_twasm(wasm: &[u8]) -> Vec<u8> {
46
let parser = Parser::new();
5-
parser.parse_module_bytes(wasm).expect("parse_module_bytes")
7+
let res = parser.parse_module_bytes(wasm).expect("parse_module_bytes");
8+
res.serialize_twasm().to_vec()
9+
}
10+
11+
#[inline]
12+
pub fn twasm_to_module(twasm: &[u8]) -> tinywasm::Module {
13+
unsafe { TinyWasmModule::from_twasm_unchecked(&twasm) }.into()
14+
}
15+
16+
pub fn tinywasm(twasm: &[u8]) -> (tinywasm::Store, tinywasm::ModuleInstance) {
17+
use tinywasm::*;
18+
let module = twasm_to_module(twasm);
19+
let mut store = Store::default();
20+
let imports = Imports::default();
21+
let instance = ModuleInstance::instantiate(&mut store, module, Some(imports)).expect("instantiate");
22+
(store, instance)
23+
}
24+
25+
pub fn wasmi(wasm: &[u8]) -> (wasmi::Module, wasmi::Store<()>, wasmi::Linker<()>) {
26+
use wasmi::*;
27+
let engine = Engine::default();
28+
let module = wasmi::Module::new(&engine, wasm).expect("wasmi::Module::new");
29+
let store = Store::new(&engine, ());
30+
let linker = <Linker<()>>::new(&engine);
31+
(module, store, linker)
632
}

examples/README.md

Lines changed: 0 additions & 23 deletions
This file was deleted.

0 commit comments

Comments
 (0)