benchmark interpreter reuse
name without-reuse.trace ns/iter with-reuse.trace ns/iter diff ns/iter diff % speedup bench_regex_redux 3,214,008 3,162,089 -51,919 -1.62% x 1.02 bench_rev_comp 7,356,860 7,168,441 -188,419 -2.56% x 1.03 bench_tiny_keccak 3,943,358 3,910,487 -32,871 -0.83% x 1.01 fac_opt 10,959 2,096 -8,863 -80.87% x 5.23 fac_recursive 13,345 4,277 -9,068 -67.95% x 3.12 recursive_ok 1,190,562 1,141,940 -48,622 -4.08% x 1.04 recursive_trap 125,047 111,962 -13,085 -10.46% x 1.12
This commit is contained in:
parent
2f7f809fd6
commit
1913702a03
|
@ -8,9 +8,10 @@ extern crate wabt;
|
||||||
|
|
||||||
use std::error;
|
use std::error;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
use test::Bencher;
|
||||||
use wasmi::{ImportsBuilder, Module, ModuleInstance, NopExternals, RuntimeValue};
|
use wasmi::{ImportsBuilder, Module, ModuleInstance, NopExternals, RuntimeValue};
|
||||||
|
|
||||||
use test::Bencher;
|
mod reuse;
|
||||||
|
|
||||||
// Load a module from a file.
|
// Load a module from a file.
|
||||||
fn load_from_file(filename: &str) -> Result<Module, Box<error::Error>> {
|
fn load_from_file(filename: &str) -> Result<Module, Box<error::Error>> {
|
||||||
|
@ -26,9 +27,8 @@ const REVCOMP_OUTPUT: &'static [u8] = include_bytes!("./revcomp-output.txt");
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_tiny_keccak(b: &mut Bencher) {
|
fn bench_tiny_keccak(b: &mut Bencher) {
|
||||||
let wasm_kernel = load_from_file(
|
let wasm_kernel = load_from_file("./wasm-kernel/target/wasm32-unknown-unknown/release/wasm_kernel.wasm")
|
||||||
"./wasm-kernel/target/wasm32-unknown-unknown/release/wasm_kernel.wasm",
|
.expect("failed to load wasm_kernel. Is `build.rs` broken?");
|
||||||
).expect("failed to load wasm_kernel. Is `build.rs` broken?");
|
|
||||||
|
|
||||||
let instance = ModuleInstance::new(&wasm_kernel, &ImportsBuilder::default())
|
let instance = ModuleInstance::new(&wasm_kernel, &ImportsBuilder::default())
|
||||||
.expect("failed to instantiate wasm module")
|
.expect("failed to instantiate wasm module")
|
||||||
|
@ -48,9 +48,8 @@ fn bench_tiny_keccak(b: &mut Bencher) {
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_rev_comp(b: &mut Bencher) {
|
fn bench_rev_comp(b: &mut Bencher) {
|
||||||
let wasm_kernel = load_from_file(
|
let wasm_kernel = load_from_file("./wasm-kernel/target/wasm32-unknown-unknown/release/wasm_kernel.wasm")
|
||||||
"./wasm-kernel/target/wasm32-unknown-unknown/release/wasm_kernel.wasm",
|
.expect("failed to load wasm_kernel. Is `build.rs` broken?");
|
||||||
).expect("failed to load wasm_kernel. Is `build.rs` broken?");
|
|
||||||
|
|
||||||
let instance = ModuleInstance::new(&wasm_kernel, &ImportsBuilder::default())
|
let instance = ModuleInstance::new(&wasm_kernel, &ImportsBuilder::default())
|
||||||
.expect("failed to instantiate wasm module")
|
.expect("failed to instantiate wasm module")
|
||||||
|
@ -74,7 +73,8 @@ fn bench_rev_comp(b: &mut Bencher) {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Copy test data inside the wasm memory.
|
// Copy test data inside the wasm memory.
|
||||||
let memory = instance.export_by_name("memory")
|
let memory = instance
|
||||||
|
.export_by_name("memory")
|
||||||
.expect("Expected export with a name 'memory'")
|
.expect("Expected export with a name 'memory'")
|
||||||
.as_memory()
|
.as_memory()
|
||||||
.expect("'memory' should be a memory instance")
|
.expect("'memory' should be a memory instance")
|
||||||
|
@ -103,9 +103,8 @@ fn bench_rev_comp(b: &mut Bencher) {
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_regex_redux(b: &mut Bencher) {
|
fn bench_regex_redux(b: &mut Bencher) {
|
||||||
let wasm_kernel = load_from_file(
|
let wasm_kernel = load_from_file("./wasm-kernel/target/wasm32-unknown-unknown/release/wasm_kernel.wasm")
|
||||||
"./wasm-kernel/target/wasm32-unknown-unknown/release/wasm_kernel.wasm",
|
.expect("failed to load wasm_kernel. Is `build.rs` broken?");
|
||||||
).expect("failed to load wasm_kernel. Is `build.rs` broken?");
|
|
||||||
|
|
||||||
let instance = ModuleInstance::new(&wasm_kernel, &ImportsBuilder::default())
|
let instance = ModuleInstance::new(&wasm_kernel, &ImportsBuilder::default())
|
||||||
.expect("failed to instantiate wasm module")
|
.expect("failed to instantiate wasm module")
|
||||||
|
@ -129,7 +128,8 @@ fn bench_regex_redux(b: &mut Bencher) {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Copy test data inside the wasm memory.
|
// Copy test data inside the wasm memory.
|
||||||
let memory = instance.export_by_name("memory")
|
let memory = instance
|
||||||
|
.export_by_name("memory")
|
||||||
.expect("Expected export with a name 'memory'")
|
.expect("Expected export with a name 'memory'")
|
||||||
.as_memory()
|
.as_memory()
|
||||||
.expect("'memory' should be a memory instance")
|
.expect("'memory' should be a memory instance")
|
||||||
|
@ -158,7 +158,7 @@ r#"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
"#
|
"#,
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
let module = Module::from_buffer(&wasm).unwrap();
|
let module = Module::from_buffer(&wasm).unwrap();
|
||||||
|
@ -168,8 +168,7 @@ r#"
|
||||||
.assert_no_start();
|
.assert_no_start();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let value = instance
|
let value = instance.invoke_export("fac-rec", &[RuntimeValue::I64(25)], &mut NopExternals);
|
||||||
.invoke_export("fac-rec", &[RuntimeValue::I64(25)], &mut NopExternals);
|
|
||||||
assert_matches!(value, Ok(Some(RuntimeValue::I64(7034535277573963776))));
|
assert_matches!(value, Ok(Some(RuntimeValue::I64(7034535277573963776))));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -192,7 +191,7 @@ r#"
|
||||||
)
|
)
|
||||||
(get_local 1)
|
(get_local 1)
|
||||||
)
|
)
|
||||||
"#
|
"#,
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
let module = Module::from_buffer(&wasm).unwrap();
|
let module = Module::from_buffer(&wasm).unwrap();
|
||||||
|
@ -202,8 +201,7 @@ r#"
|
||||||
.assert_no_start();
|
.assert_no_start();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let value = instance
|
let value = instance.invoke_export("fac-opt", &[RuntimeValue::I64(25)], &mut NopExternals);
|
||||||
.invoke_export("fac-opt", &[RuntimeValue::I64(25)], &mut NopExternals);
|
|
||||||
assert_matches!(value, Ok(Some(RuntimeValue::I64(7034535277573963776))));
|
assert_matches!(value, Ok(Some(RuntimeValue::I64(7034535277573963776))));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -228,7 +226,7 @@ fn recursive_ok(b: &mut Bencher) {
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
"#
|
"#,
|
||||||
).unwrap();
|
).unwrap();
|
||||||
let module = Module::from_buffer(&wasm).unwrap();
|
let module = Module::from_buffer(&wasm).unwrap();
|
||||||
|
|
||||||
|
@ -237,8 +235,7 @@ fn recursive_ok(b: &mut Bencher) {
|
||||||
.assert_no_start();
|
.assert_no_start();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let value = instance
|
let value = instance.invoke_export("call", &[RuntimeValue::I32(8000)], &mut NopExternals);
|
||||||
.invoke_export("call", &[RuntimeValue::I32(8000)], &mut NopExternals);
|
|
||||||
assert_matches!(value, Ok(Some(RuntimeValue::I32(0))));
|
assert_matches!(value, Ok(Some(RuntimeValue::I32(0))));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -262,7 +259,7 @@ fn recursive_trap(b: &mut Bencher) {
|
||||||
unreachable
|
unreachable
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
"#
|
"#,
|
||||||
).unwrap();
|
).unwrap();
|
||||||
let module = Module::from_buffer(&wasm).unwrap();
|
let module = Module::from_buffer(&wasm).unwrap();
|
||||||
|
|
||||||
|
@ -271,8 +268,7 @@ fn recursive_trap(b: &mut Bencher) {
|
||||||
.assert_no_start();
|
.assert_no_start();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let value = instance
|
let value = instance.invoke_export("call", &[RuntimeValue::I32(1000)], &mut NopExternals);
|
||||||
.invoke_export("call", &[RuntimeValue::I32(1000)], &mut NopExternals);
|
|
||||||
assert_matches!(value, Err(_));
|
assert_matches!(value, Err(_));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,310 @@
|
||||||
|
use std::error;
|
||||||
|
use std::fs::File;
|
||||||
|
use test::Bencher;
|
||||||
|
use wasmi::{
|
||||||
|
FuncInstance, ImportsBuilder, Interpreter, Module, ModuleInstance, NopExternals, RuntimeValue, StackSize,
|
||||||
|
StackWithLimit,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Load a module from a file.
|
||||||
|
fn load_from_file(filename: &str) -> Result<Module, Box<error::Error>> {
|
||||||
|
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)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_kernel() -> Module {
|
||||||
|
load_from_file("./wasm-kernel/target/wasm32-unknown-unknown/release/wasm_kernel.wasm")
|
||||||
|
.expect("failed to load wasm_kernel. Is `build.rs` broken?")
|
||||||
|
}
|
||||||
|
|
||||||
|
const REVCOMP_INPUT: &'static [u8] = include_bytes!("./revcomp-input.txt");
|
||||||
|
const REVCOMP_OUTPUT: &'static [u8] = include_bytes!("./revcomp-output.txt");
|
||||||
|
|
||||||
|
fn new_interpreter() -> Interpreter {
|
||||||
|
let value_stack = StackWithLimit::with_size(StackSize::from_element_count(1024 * 1024));
|
||||||
|
let call_stack = StackWithLimit::with_size(StackSize::from_element_count(1024 * 1024));
|
||||||
|
Interpreter::new(value_stack, call_stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_tiny_keccak(b: &mut Bencher) {
|
||||||
|
let wasm_kernel = load_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
|
||||||
|
);
|
||||||
|
|
||||||
|
let func = instance.export_by_name("bench_tiny_keccak").unwrap();
|
||||||
|
let func = func.as_func().unwrap();
|
||||||
|
let mut interpreter = new_interpreter();
|
||||||
|
|
||||||
|
b.iter(|| {
|
||||||
|
interpreter.reset();
|
||||||
|
FuncInstance::invoke_configurable(&func, &[test_data_ptr], &mut NopExternals, &mut interpreter).unwrap()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_rev_comp(b: &mut Bencher) {
|
||||||
|
let wasm_kernel = load_kernel();
|
||||||
|
|
||||||
|
let instance = ModuleInstance::new(&wasm_kernel, &ImportsBuilder::default())
|
||||||
|
.expect("failed to instantiate wasm module")
|
||||||
|
.assert_no_start();
|
||||||
|
|
||||||
|
// Allocate buffers for the input and output.
|
||||||
|
let test_data_ptr: RuntimeValue = {
|
||||||
|
let input_size = RuntimeValue::I32(REVCOMP_INPUT.len() as i32);
|
||||||
|
assert_matches!(
|
||||||
|
instance.invoke_export("prepare_rev_complement", &[input_size], &mut NopExternals),
|
||||||
|
Ok(Some(v @ RuntimeValue::I32(_))) => v,
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get the pointer to the input buffer.
|
||||||
|
let input_data_mem_offset = assert_matches!(
|
||||||
|
instance.invoke_export("rev_complement_input_ptr", &[test_data_ptr], &mut NopExternals),
|
||||||
|
Ok(Some(RuntimeValue::I32(v))) => v as u32,
|
||||||
|
"",
|
||||||
|
);
|
||||||
|
|
||||||
|
// Copy test data inside the wasm memory.
|
||||||
|
let memory = instance
|
||||||
|
.export_by_name("memory")
|
||||||
|
.expect("Expected export with a name 'memory'")
|
||||||
|
.as_memory()
|
||||||
|
.expect("'memory' should be a memory instance")
|
||||||
|
.clone();
|
||||||
|
memory
|
||||||
|
.set(input_data_mem_offset, REVCOMP_INPUT)
|
||||||
|
.expect("can't load test data into a wasm memory");
|
||||||
|
|
||||||
|
let func = instance.export_by_name("bench_rev_complement").unwrap();
|
||||||
|
let func = func.as_func().unwrap();
|
||||||
|
let mut interpreter = new_interpreter();
|
||||||
|
|
||||||
|
b.iter(|| {
|
||||||
|
interpreter.reset();
|
||||||
|
FuncInstance::invoke_configurable(&func, &[test_data_ptr], &mut NopExternals, &mut interpreter).unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
|
// Verify the result.
|
||||||
|
let output_data_mem_offset = assert_matches!(
|
||||||
|
instance.invoke_export("rev_complement_output_ptr", &[test_data_ptr], &mut NopExternals),
|
||||||
|
Ok(Some(RuntimeValue::I32(v))) => v as u32,
|
||||||
|
"",
|
||||||
|
);
|
||||||
|
let result = memory
|
||||||
|
.get(output_data_mem_offset, REVCOMP_OUTPUT.len())
|
||||||
|
.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_kernel();
|
||||||
|
|
||||||
|
let instance = ModuleInstance::new(&wasm_kernel, &ImportsBuilder::default())
|
||||||
|
.expect("failed to instantiate wasm module")
|
||||||
|
.assert_no_start();
|
||||||
|
|
||||||
|
// Allocate buffers for the input and output.
|
||||||
|
let test_data_ptr: RuntimeValue = {
|
||||||
|
let input_size = RuntimeValue::I32(REVCOMP_INPUT.len() as i32);
|
||||||
|
assert_matches!(
|
||||||
|
instance.invoke_export("prepare_regex_redux", &[input_size], &mut NopExternals),
|
||||||
|
Ok(Some(v @ RuntimeValue::I32(_))) => v,
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get the pointer to the input buffer.
|
||||||
|
let input_data_mem_offset = assert_matches!(
|
||||||
|
instance.invoke_export("regex_redux_input_ptr", &[test_data_ptr], &mut NopExternals),
|
||||||
|
Ok(Some(RuntimeValue::I32(v))) => v as u32,
|
||||||
|
"",
|
||||||
|
);
|
||||||
|
|
||||||
|
// Copy test data inside the wasm memory.
|
||||||
|
let memory = instance
|
||||||
|
.export_by_name("memory")
|
||||||
|
.expect("Expected export with a name 'memory'")
|
||||||
|
.as_memory()
|
||||||
|
.expect("'memory' should be a memory instance")
|
||||||
|
.clone();
|
||||||
|
memory
|
||||||
|
.set(input_data_mem_offset, REVCOMP_INPUT)
|
||||||
|
.expect("can't load test data into a wasm memory");
|
||||||
|
|
||||||
|
let func = instance.export_by_name("bench_regex_redux").unwrap();
|
||||||
|
let func = func.as_func().unwrap();
|
||||||
|
let mut interpreter = new_interpreter();
|
||||||
|
|
||||||
|
b.iter(|| {
|
||||||
|
interpreter.reset();
|
||||||
|
FuncInstance::invoke_configurable(&func, &[test_data_ptr], &mut NopExternals, &mut interpreter).unwrap()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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 module = Module::from_buffer(&wasm).unwrap();
|
||||||
|
|
||||||
|
let instance = ModuleInstance::new(&module, &ImportsBuilder::default())
|
||||||
|
.expect("failed to instantiate wasm module")
|
||||||
|
.assert_no_start();
|
||||||
|
|
||||||
|
let func = instance.export_by_name("fac-rec").unwrap();
|
||||||
|
let func = func.as_func().unwrap();
|
||||||
|
let mut interpreter = new_interpreter();
|
||||||
|
|
||||||
|
b.iter(|| {
|
||||||
|
interpreter.reset();
|
||||||
|
let value =
|
||||||
|
FuncInstance::invoke_configurable(&func, &[RuntimeValue::I64(25)], &mut NopExternals, &mut interpreter)
|
||||||
|
.unwrap();
|
||||||
|
assert_matches!(value, Some(RuntimeValue::I64(7034535277573963776)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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 module = Module::from_buffer(&wasm).unwrap();
|
||||||
|
|
||||||
|
let instance = ModuleInstance::new(&module, &ImportsBuilder::default())
|
||||||
|
.expect("failed to instantiate wasm module")
|
||||||
|
.assert_no_start();
|
||||||
|
|
||||||
|
let func = instance.export_by_name("fac-opt").unwrap();
|
||||||
|
let func = func.as_func().unwrap();
|
||||||
|
let mut interpreter = new_interpreter();
|
||||||
|
|
||||||
|
b.iter(|| {
|
||||||
|
interpreter.reset();
|
||||||
|
let value =
|
||||||
|
FuncInstance::invoke_configurable(&func, &[RuntimeValue::I64(25)], &mut NopExternals, &mut interpreter)
|
||||||
|
.unwrap();
|
||||||
|
assert_matches!(value, Some(RuntimeValue::I64(7034535277573963776)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 module = Module::from_buffer(&wasm).unwrap();
|
||||||
|
|
||||||
|
let instance = ModuleInstance::new(&module, &ImportsBuilder::default())
|
||||||
|
.expect("failed to instantiate wasm module")
|
||||||
|
.assert_no_start();
|
||||||
|
|
||||||
|
let func = instance.export_by_name("call").unwrap();
|
||||||
|
let func = func.as_func().unwrap();
|
||||||
|
let mut interpreter = new_interpreter();
|
||||||
|
|
||||||
|
b.iter(|| {
|
||||||
|
interpreter.reset();
|
||||||
|
let value =
|
||||||
|
FuncInstance::invoke_configurable(&func, &[RuntimeValue::I32(8000)], &mut NopExternals, &mut interpreter)
|
||||||
|
.unwrap();
|
||||||
|
assert_matches!(value, Some(RuntimeValue::I32(0)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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 module = Module::from_buffer(&wasm).unwrap();
|
||||||
|
|
||||||
|
let instance = ModuleInstance::new(&module, &ImportsBuilder::default())
|
||||||
|
.expect("failed to instantiate wasm module")
|
||||||
|
.assert_no_start();
|
||||||
|
|
||||||
|
let func = instance.export_by_name("call").unwrap();
|
||||||
|
let func = func.as_func().unwrap();
|
||||||
|
let mut interpreter = new_interpreter();
|
||||||
|
|
||||||
|
b.iter(|| {
|
||||||
|
interpreter.reset();
|
||||||
|
FuncInstance::invoke_configurable(&func, &[RuntimeValue::I32(1000)], &mut NopExternals, &mut interpreter)
|
||||||
|
.unwrap_err();
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue