Skip to content
This repository has been archived by the owner on Jul 16, 2020. It is now read-only.

Commit

Permalink
Implement performance benchmarking for basic demo
Browse files Browse the repository at this point in the history
  • Loading branch information
mbestavros authored and npmccallum committed Sep 5, 2019
1 parent 33b893a commit 84fed85
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 10 deletions.
1 change: 1 addition & 0 deletions wasmtime-basic/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ default = ["rust"]

c = []
rust = []
benchmark = []
10 changes: 9 additions & 1 deletion wasmtime-basic/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,12 @@ Rust is compiled by default. If C is desired, the appropriate feature can be inv
cargo run --no-default-features --features c
```

Or, alternatively, by changing the `default` feature in `Cargo.toml` from `["rust"]` to `["c"]`.
## Running benchmarks

`main.rs` includes performance benchmarks useful for analyzing the startup cost and runtime of functions in Wasmtime.

These benchmarks use Rust's unstable built-in benchmarking tools, and must be run on Rust nightly. Additionally, the `benchmark` feature must be enabled to run them:

```
cargo +nightly bench --features benchmark
```
82 changes: 73 additions & 9 deletions wasmtime-basic/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@
//! Rust-powered JIT, to natively run programs from several different source
//! languages (Rust/C/C++) compiled to WASI-compliant WASM.
#![cfg_attr(feature = "benchmark", feature(test))]

#[cfg(test)]
extern crate test;

use cranelift_codegen::settings;
use cranelift_native;
use std::fs::File;
use std::io::Read;
use wasmtime_jit::{ActionOutcome, Context, RuntimeValue};
use wasmtime_jit::{ActionError, ActionOutcome, Context, RuntimeValue};

// The basic WASM demo itself.
fn main() {
// Before we begin, it'll be heplful to know which source language we're
// running, so let's print it out.
Expand All @@ -18,11 +24,22 @@ fn main() {
println!("WASM binary has been compiled from Rust.");
}

println!("Loading WASM binary...");
println!("Loading and running WASM binary...");
let result = wasm_add_full();
println!("Finished. Results:");
match result.unwrap() {
ActionOutcome::Returned { values } => println!("Output: {:#?}", values),
ActionOutcome::Trapped { message } => println!("Trap from within function: {}", message),
}
println!("Done.");
}

// A function to encapsulate the full setup and execution of a single iteration of the WASM demo.
pub fn wasm_add_full() -> Result<ActionOutcome, ActionError> {
// First, we need to load the WASM binary in.
let mut binary_file = File::open(concat!(env!("OUT_DIR"), "/add.wasm")).unwrap();
let mut binary: Vec<u8> = Vec::new();
binary_file.read_to_end(&mut binary).unwrap();
println!("WASM binary loaded.");

// In order to run this binary, we need to prepare a few inputs.

Expand All @@ -40,12 +57,59 @@ fn main() {

// And, finally, invoke our function and print the results.
// For this demo, all we're doing is adding 5 and 7 together.
println!("Invoking function.");
let args = [RuntimeValue::I32(5), RuntimeValue::I32(7)];
let result = context.invoke(&mut instance, "add", &args);
match result.unwrap() {
ActionOutcome::Returned { values } => println!("Output: {:#?}", values),
ActionOutcome::Trapped { message } => println!("Trap from within function: {}", message),
context.invoke(&mut instance, "add", &args)
}

// A Rust function that does the same thing as the WASM demo, for benchmarking use.
#[cfg(test)]
pub fn native_add(a: i32, b: i32) -> i32 {
a + b
}

// Performance benchmarking for the demo.
#[cfg(test)]
mod tests {
use super::*;
use test::Bencher;

// Baseline benchmark: Simple Rust adition.
#[bench]
fn bench_native_add(b: &mut Bencher) {
b.iter(|| native_add(5, 7));
}

// Benchmark: WASM addition from start to finish, including
// loading/instantiating WASM.
#[bench]
fn bench_wasm_add_unloaded(b: &mut Bencher) {
b.iter(|| wasm_add_full());
}

// Benchmark: WASM addition once everything is set up.
#[bench]
fn bench_wasm_add_loaded(b: &mut Bencher) {
let mut binary_file = File::open(concat!(env!("OUT_DIR"), "/add.wasm")).unwrap();
let mut binary: Vec<u8> = Vec::new();
binary_file.read_to_end(&mut binary).unwrap();

// In order to run this binary, we need to prepare a few inputs.

// First, we need a Wasmtime context. To build one, we need to get an ISA
// from `cranelift_native.
let isa_builder = cranelift_native::builder().unwrap();
let flag_builder = settings::builder();
let isa = isa_builder.finish(settings::Flags::new(flag_builder));

// Then, we use the ISA to build the context.
let mut context = Context::with_isa(isa);

// Now, we instantiate the WASM module loaded into memory.
let mut instance = context.instantiate_module(None, &binary).unwrap();

// And, finally, invoke our function and print the results.
// For this demo, all we're doing is adding 5 and 7 together.
let args = [RuntimeValue::I32(5), RuntimeValue::I32(7)];
b.iter(|| context.invoke(&mut instance, "add", &args));
}
println!("Done.");
}

0 comments on commit 84fed85

Please sign in to comment.