Skip to content

Commit

Permalink
Merge #450
Browse files Browse the repository at this point in the history
450: Metering. r=bjfish a=losfair

TODO
- [x] Add test to verify points used after function call
- [x] Add test to verify function call will trap
- [x] Add documentation

Co-authored-by: losfair <[email protected]>
Co-authored-by: Brandon Fish <[email protected]>
  • Loading branch information
3 people committed Jun 7, 2019
2 parents ade70c6 + f6ecfa4 commit 5db8c13
Show file tree
Hide file tree
Showing 17 changed files with 821 additions and 23 deletions.
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,21 @@ do-install:

test:
# We use one thread so the emscripten stdouts doesn't collide
cargo test --all --exclude wasmer-runtime-c-api --exclude wasmer-emscripten --exclude wasmer-spectests --exclude wasmer-singlepass-backend --exclude wasmer-wasi -- $(runargs)
cargo test --all --exclude wasmer-runtime-c-api --exclude wasmer-emscripten --exclude wasmer-spectests --exclude wasmer-singlepass-backend --exclude wasmer-wasi --exclude wasmer-middleware-common -- $(runargs)
# cargo test --all --exclude wasmer-emscripten -- --test-threads=1 $(runargs)
cargo test --manifest-path lib/spectests/Cargo.toml --features clif
cargo test --manifest-path lib/middleware-common/Cargo.toml --features clif
@if [ ! -z "${CIRCLE_JOB}" ]; then rm -f /home/circleci/project/target/debug/deps/libcranelift_wasm* && rm -f /Users/distiller/project/target/debug/deps/libcranelift_wasm*; fi;
cargo test --manifest-path lib/spectests/Cargo.toml --features llvm
cargo test --manifest-path lib/runtime/Cargo.toml --features llvm
cargo test --manifest-path lib/middleware-common/Cargo.toml --features llvm
cargo build -p wasmer-runtime-c-api
cargo test -p wasmer-runtime-c-api -- --nocapture

test-singlepass:
cargo test --manifest-path lib/spectests/Cargo.toml --features singlepass
cargo test --manifest-path lib/runtime/Cargo.toml --features singlepass
cargo test --manifest-path lib/middleware-common/Cargo.toml --features singlepass

test-emscripten-llvm:
cargo test --manifest-path lib/emscripten/Cargo.toml --features llvm -- --test-threads=1 $(runargs)
Expand Down
1 change: 1 addition & 0 deletions lib/clif-backend/src/code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1122,6 +1122,7 @@ impl FunctionCodeGenerator<CodegenError> for CraneliftFunctionCodeGenerator {
fn feed_event(&mut self, event: Event, _module_info: &ModuleInfo) -> Result<(), CodegenError> {
let op = match event {
Event::Wasm(x) => x,
Event::WasmOwned(ref x) => x,
Event::Internal(_x) => {
return Ok(());
}
Expand Down
1 change: 1 addition & 0 deletions lib/llvm-backend/src/code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,7 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
Event::Internal(_x) => {
return Ok(());
}
Event::WasmOwned(ref x) => x,
};

let mut state = &mut self.state;
Expand Down
4 changes: 4 additions & 0 deletions lib/llvm-backend/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ impl Intrinsics {
let stack_lower_bound_ty = i8_ty;
let memory_base_ty = i8_ty;
let memory_bound_ty = void_ty;
let internals_ty = i64_ty;
let local_function_ty = i8_ptr_ty;

let anyfunc_ty = context.struct_type(
Expand Down Expand Up @@ -218,6 +219,9 @@ impl Intrinsics {
memory_bound_ty
.ptr_type(AddressSpace::Generic)
.as_basic_type_enum(),
internals_ty
.ptr_type(AddressSpace::Generic)
.as_basic_type_enum(),
local_function_ty
.ptr_type(AddressSpace::Generic)
.as_basic_type_enum(),
Expand Down
18 changes: 17 additions & 1 deletion lib/middleware-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,20 @@ authors = ["The Wasmer Engineering Team <[email protected]>"]
edition = "2018"

[dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.2" }
wasmer-runtime-core = { path = "../runtime-core" }
wasmer-clif-backend = { path = "../clif-backend", version = "0.4.2" }
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.4.2", optional = true }
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.4.2", optional = true }

[dev-dependencies]
wabt = "0.7.4"
criterion = "0.2"

[features]
clif = []
llvm = ["wasmer-llvm-backend"]
singlepass = ["wasmer-singlepass-backend"]

[[bench]]
name = "metering_benchmark"
harness = false
230 changes: 230 additions & 0 deletions lib/middleware-common/benches/metering_benchmark.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
#[macro_use]
extern crate criterion;

use criterion::black_box;
use criterion::{Benchmark, Criterion};

use wabt::wat2wasm;

use wasmer_middleware_common::metering::Metering;
use wasmer_runtime_core::vm::Ctx;
use wasmer_runtime_core::{backend::Compiler, compile_with, imports, Func};

//export function add_to(x: i32, y: i32): i32 {
// for(var i = 0; i < x; i++){
// if(i % 1 == 0){
// y += i;
// } else {
// y *= i
// }
// }
// return y;
//}
static WAT: &'static str = r#"
(module
(type $t0 (func (param i32 i32) (result i32)))
(type $t1 (func))
(func $add_to (export "add_to") (type $t0) (param $p0 i32) (param $p1 i32) (result i32)
(local $l0 i32)
block $B0
i32.const 0
set_local $l0
loop $L1
get_local $l0
get_local $p0
i32.lt_s
i32.eqz
br_if $B0
get_local $l0
i32.const 1
i32.rem_s
i32.const 0
i32.eq
if $I2
get_local $p1
get_local $l0
i32.add
set_local $p1
else
get_local $p1
get_local $l0
i32.mul
set_local $p1
end
get_local $l0
i32.const 1
i32.add
set_local $l0
br $L1
unreachable
end
unreachable
end
get_local $p1)
(func $f1 (type $t1))
(table $table (export "table") 1 anyfunc)
(memory $memory (export "memory") 0)
(global $g0 i32 (i32.const 8))
(elem (i32.const 0) $f1))
"#;

static WAT_GAS: &'static str = r#"
(module
(type $t0 (func (param i32 i32) (result i32)))
(type $t1 (func))
(type $t2 (func (param i32)))
(import "env" "gas" (func $env.gas (type $t2)))
(func $add_to (type $t0) (param $p0 i32) (param $p1 i32) (result i32)
(local $l0 i32)
i32.const 3
call $env.gas
block $B0
i32.const 5
call $env.gas
i32.const 0
set_local $l0
loop $L1
i32.const 18
call $env.gas
get_local $l0
get_local $p0
i32.lt_s
i32.eqz
br_if $B0
get_local $l0
i32.const 1
i32.rem_s
i32.const 0
i32.eq
if $I2
i32.const 5
call $env.gas
get_local $p1
get_local $l0
i32.add
set_local $p1
else
i32.const 5
call $env.gas
get_local $p1
get_local $l0
i32.mul
set_local $p1
end
get_local $l0
i32.const 1
i32.add
set_local $l0
br $L1
unreachable
end
unreachable
end
get_local $p1)
(func $f2 (type $t1)
i32.const 1
call $env.gas)
(table $table 1 anyfunc)
(memory $memory 0)
(global $g0 i32 (i32.const 8))
(export "memory" (memory 0))
(export "table" (table 0))
(export "add_to" (func $add_to))
(elem (i32.const 0) $f2))
"#;

#[cfg(feature = "llvm")]
fn get_compiler(limit: u64, metering: bool) -> impl Compiler {
use wasmer_llvm_backend::code::LLVMModuleCodeGenerator;
use wasmer_runtime_core::codegen::{MiddlewareChain, StreamingCompiler};
let c: StreamingCompiler<LLVMModuleCodeGenerator, _, _, _, _> =
StreamingCompiler::new(move || {
let mut chain = MiddlewareChain::new();
if metering {
chain.push(Metering::new(limit));
}
chain
});

c
}

#[cfg(feature = "singlepass")]
fn get_compiler(limit: u64, metering: bool) -> impl Compiler {
use wasmer_runtime_core::codegen::{MiddlewareChain, StreamingCompiler};
use wasmer_singlepass_backend::ModuleCodeGenerator as SinglePassMCG;
let c: StreamingCompiler<SinglePassMCG, _, _, _, _> = StreamingCompiler::new(move || {
let mut chain = MiddlewareChain::new();
if metering {
chain.push(Metering::new(limit));
}
chain
});
c
}

#[cfg(not(any(feature = "llvm", feature = "clif", feature = "singlepass")))]
fn get_compiler(_limit: u64, metering: bool) -> impl Compiler {
panic!("compiler not specified, activate a compiler via features");
use wasmer_clif_backend::CraneliftCompiler;
CraneliftCompiler::new()
}

#[cfg(feature = "clif")]
fn get_compiler(_limit: u64, metering: bool) -> impl Compiler {
panic!("cranelift does not implement metering");
use wasmer_clif_backend::CraneliftCompiler;
CraneliftCompiler::new()
}

fn gas(ctx: &mut Ctx, gas_amount: u32) {
use wasmer_middleware_common::metering;
let used = metering::get_points_used_ctx(ctx);
metering::set_points_used_ctx(ctx, used + u64::from(gas_amount));
()
}

fn bench_metering(c: &mut Criterion) {
use wasmer_middleware_common::metering;

c.bench(
"Meter",
Benchmark::new("No Metering", |b| {
let compiler = get_compiler(0, false);
let wasm_binary = wat2wasm(WAT).unwrap();
let module = compile_with(&wasm_binary, &compiler).unwrap();
let import_object = imports! {};
let mut instance = module.instantiate(&import_object).unwrap();
let add_to: Func<(i32, i32), i32> = instance.func("add_to").unwrap();
b.iter(|| black_box(add_to.call(100, 4)))
})
.with_function("Gas Metering", |b| {
let compiler = get_compiler(0, false);
let gas_wasm_binary = wat2wasm(WAT_GAS).unwrap();
let gas_module = compile_with(&gas_wasm_binary, &compiler).unwrap();
let gas_import_object = imports! {
"env" => {
"gas" => Func::new(gas),
},
};
let mut gas_instance = gas_module.instantiate(&gas_import_object).unwrap();
let gas_add_to: Func<(i32, i32), i32> = gas_instance.func("add_to").unwrap();
b.iter(|| black_box(gas_add_to.call(100, 4)))
})
.with_function("Built-in Metering", |b| {
let metering_compiler = get_compiler(std::u64::MAX, true);
let wasm_binary = wat2wasm(WAT).unwrap();
let metering_module = compile_with(&wasm_binary, &metering_compiler).unwrap();
let metering_import_object = imports! {};
let mut metering_instance = metering_module
.instantiate(&metering_import_object)
.unwrap();
metering::set_points_used(&mut metering_instance, 0u64);
let metering_add_to: Func<(i32, i32), i32> = metering_instance.func("add_to").unwrap();
b.iter(|| black_box(metering_add_to.call(100, 4)))
}),
);
}

criterion_group!(benches, bench_metering);
criterion_main!(benches);
1 change: 1 addition & 0 deletions lib/middleware-common/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]

pub mod call_trace;
pub mod metering;
Loading

0 comments on commit 5db8c13

Please sign in to comment.