Skip to content

Commit

Permalink
Refactor and clean up benchmark code (#299)
Browse files Browse the repository at this point in the history
* move benches into workspace

* move build.rs into crate root

* adjust build.rs file

* fix warnings in benchmarks

* apply rustfmt in benchmarks

* move benchmark .wat files into their own files

* reduce code dupe

* fix warning in regex_redux.rs benchmark file

* move build.rs back to benches/

* adjust after move

* convert comments into docs

* add docs for #Panics

* apply rustfmt

* make wasm-kernel use Rust edition 2021

* fix clippy warnings in wasm-kernel
  • Loading branch information
Robbepop authored Jan 4, 2022
1 parent 759bd19 commit 26bb799
Show file tree
Hide file tree
Showing 10 changed files with 212 additions and 218 deletions.
175 changes: 38 additions & 137 deletions benches/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ extern crate wasmi;
extern crate assert_matches;
extern crate wabt;

use std::{error, fs::File};
use std::fs::File;
use test::Bencher;
use wasmi::{
Error,
Error,
Externals,
FuncInstance,
FuncRef,
Expand All @@ -30,28 +30,42 @@ use wasmi::{
Trap,
};

// Load a module from a file.
fn load_from_file(filename: &str) -> Result<Module, Box<dyn error::Error>> {
/// Parses the Wasm binary at the given file name into a `wasmi` module.
///
/// # Note
///
/// This includes validation and compilation to `wasmi` bytecode.
///
/// # Panics
///
/// - If the benchmark Wasm file could not be opened, read or parsed.
fn load_from_file(file_name: &str) -> Module {
use std::io::prelude::*;
let mut file = File::open(filename)?;
let mut buf = Vec::new();
file.read_to_end(&mut buf)?;
Ok(Module::from_buffer(buf)?)
let mut file = File::open(file_name)
.unwrap_or_else(|error| panic!("could not open benchmark file {}: {}", file_name, error));
let mut buffer = Vec::new();
file.read_to_end(&mut buffer).unwrap_or_else(|error| {
panic!("could not read file at {} to buffer: {}", file_name, error)
});
let module = Module::from_buffer(buffer).unwrap_or_else(|error| {
panic!(
"could not parse Wasm module from file {}: {}",
file_name, error
)
});
module
}

const WASM_KERNEL: &str = "wasm-kernel/target/wasm32-unknown-unknown/release/wasm_kernel.wasm";
const REVCOMP_INPUT: &'static [u8] = include_bytes!("./revcomp-input.txt");
const REVCOMP_OUTPUT: &'static [u8] = include_bytes!("./revcomp-output.txt");

#[bench]
fn bench_tiny_keccak(b: &mut Bencher) {
let wasm_kernel =
load_from_file("./wasm-kernel/target/wasm32-unknown-unknown/release/wasm_kernel.wasm")
.expect("failed to load wasm_kernel. Is `build.rs` broken?");

let wasm_kernel = load_from_file(WASM_KERNEL);
let instance = ModuleInstance::new(&wasm_kernel, &ImportsBuilder::default())
.expect("failed to instantiate wasm module")
.assert_no_start();

let test_data_ptr = assert_matches!(
instance.invoke_export("prepare_tiny_keccak", &[], &mut NopExternals),
Ok(Some(v @ RuntimeValue::I32(_))) => v
Expand All @@ -66,10 +80,7 @@ fn bench_tiny_keccak(b: &mut Bencher) {

#[bench]
fn bench_rev_comp(b: &mut Bencher) {
let wasm_kernel =
load_from_file("./wasm-kernel/target/wasm32-unknown-unknown/release/wasm_kernel.wasm")
.expect("failed to load wasm_kernel. Is `build.rs` broken?");

let wasm_kernel = load_from_file(WASM_KERNEL);
let instance = ModuleInstance::new(&wasm_kernel, &ImportsBuilder::default())
.expect("failed to instantiate wasm module")
.assert_no_start();
Expand Down Expand Up @@ -114,18 +125,16 @@ fn bench_rev_comp(b: &mut Bencher) {
Ok(Some(RuntimeValue::I32(v))) => v as u32,
"",
);
let result = memory
.get(output_data_mem_offset, REVCOMP_OUTPUT.len())
let mut result = vec![0x00_u8; REVCOMP_OUTPUT.len()];
memory
.get_into(output_data_mem_offset, &mut result)
.expect("can't get result data from a wasm memory");
assert_eq!(&*result, REVCOMP_OUTPUT);
}

#[bench]
fn bench_regex_redux(b: &mut Bencher) {
let wasm_kernel =
load_from_file("./wasm-kernel/target/wasm32-unknown-unknown/release/wasm_kernel.wasm")
.expect("failed to load wasm_kernel. Is `build.rs` broken?");

let wasm_kernel = load_from_file(WASM_KERNEL);
let instance = ModuleInstance::new(&wasm_kernel, &ImportsBuilder::default())
.expect("failed to instantiate wasm module")
.assert_no_start();
Expand Down Expand Up @@ -167,23 +176,8 @@ fn bench_regex_redux(b: &mut Bencher) {

#[bench]
fn fac_recursive(b: &mut Bencher) {
let wasm = wabt::wat2wasm(
r#"
;; Recursive factorial
(func (export "fac-rec") (param i64) (result i64)
(if (result i64) (i64.eq (get_local 0) (i64.const 0))
(then (i64.const 1))
(else
(i64.mul (get_local 0) (call 0 (i64.sub (get_local 0) (i64.const 1))))
)
)
)
"#,
)
.unwrap();

let wasm = wabt::wat2wasm(include_bytes!("../wat/recursive_factorial.wat")).unwrap();
let module = Module::from_buffer(&wasm).unwrap();

let instance = ModuleInstance::new(&module, &ImportsBuilder::default())
.expect("failed to instantiate wasm module")
.assert_no_start();
Expand All @@ -196,28 +190,8 @@ fn fac_recursive(b: &mut Bencher) {

#[bench]
fn fac_opt(b: &mut Bencher) {
let wasm = wabt::wat2wasm(
r#"
;; Optimized factorial.
(func (export "fac-opt") (param i64) (result i64)
(local i64)
(set_local 1 (i64.const 1))
(block
(br_if 0 (i64.lt_s (get_local 0) (i64.const 2)))
(loop
(set_local 1 (i64.mul (get_local 1) (get_local 0)))
(set_local 0 (i64.add (get_local 0) (i64.const -1)))
(br_if 0 (i64.gt_s (get_local 0) (i64.const 1)))
)
)
(get_local 1)
)
"#,
)
.unwrap();

let wasm = wabt::wat2wasm(include_bytes!("../wat/optimized_factorial.wat")).unwrap();
let module = Module::from_buffer(&wasm).unwrap();

let instance = ModuleInstance::new(&module, &ImportsBuilder::default())
.expect("failed to instantiate wasm module")
.assert_no_start();
Expand All @@ -228,31 +202,10 @@ fn fac_opt(b: &mut Bencher) {
});
}

// This is used for testing overhead of a function call
// is not too large.
#[bench]
fn recursive_ok(b: &mut Bencher) {
let wasm = wabt::wat2wasm(
r#"
(module
(func $call (export "call") (param i32) (result i32)
block (result i32)
get_local 0
get_local 0
i32.eqz
br_if 0
i32.const 1
i32.sub
call $call
end
)
)
"#,
)
.unwrap();
let wasm = wabt::wat2wasm(include_bytes!("../wat/recursive_ok.wat")).unwrap();
let module = Module::from_buffer(&wasm).unwrap();

let instance = ModuleInstance::new(&module, &ImportsBuilder::default())
.expect("failed to instantiate wasm module")
.assert_no_start();
Expand All @@ -265,28 +218,8 @@ fn recursive_ok(b: &mut Bencher) {

#[bench]
fn recursive_trap(b: &mut Bencher) {
let wasm = wabt::wat2wasm(
r#"
(module
(func $call (export "call") (param i32) (result i32)
block (result i32)
get_local 0
get_local 0
i32.eqz
br_if 0
i32.const 1
i32.sub
call $call
end
unreachable
)
)
"#,
)
.unwrap();
let wasm = wabt::wat2wasm(include_bytes!("../wat/recursive_trap.wat")).unwrap();
let module = Module::from_buffer(&wasm).unwrap();

let instance = ModuleInstance::new(&module, &ImportsBuilder::default())
.expect("failed to instantiate wasm module")
.assert_no_start();
Expand All @@ -299,40 +232,8 @@ fn recursive_trap(b: &mut Bencher) {

#[bench]
fn host_calls(b: &mut Bencher) {
// The below `.wat` file exports a function `call` that takes a `n` of type `i64`.
// It will iterate `n` times and call the imported function `host_call` every time.
//
// This benchmarks tests the performance of host calls.
//
// After successful execution the `call` function will return `0`.
let wasm = wabt::wat2wasm(
r#"
(module
(import "benchmark" "host_call" (func $host_call (param i64) (result i64)))
(func $call (export "call") (param i64) (result i64)
(block
(loop
(br_if
1
(i64.eq (get_local 0) (i64.const 0))
)
(set_local 0
(i64.sub
(call $host_call (get_local 0))
(i64.const 1)
)
)
(br 0)
)
)
(get_local 0)
)
)
"#,
)
.unwrap();
let wasm = wabt::wat2wasm(include_bytes!("../wat/host_calls.wat")).unwrap();
let module = Module::from_buffer(&wasm).unwrap();

let instance = ModuleInstance::new(&module, &BenchExternals)
.expect("failed to instantiate wasm module")
.assert_no_start();
Expand All @@ -354,7 +255,7 @@ fn host_calls(b: &mut Bencher) {
) -> Result<Option<RuntimeValue>, Trap> {
match index {
HOST_CALL_INDEX => {
let arg = args.nth_value_checked(0)?;
let arg = args.nth_value_checked(0)?;
Ok(Some(arg))
}
_ => panic!("BenchExternals do not provide function at index {}", index),
Expand Down
1 change: 1 addition & 0 deletions benches/wasm-kernel/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
name = "wasm-kernel"
version = "0.1.0"
authors = ["Sergey Pepyakin <[email protected]>"]
edition = "2021"

[lib]
crate-type = ["cdylib"]
Expand Down
Loading

0 comments on commit 26bb799

Please sign in to comment.