Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Metering. #450

Merged
merged 35 commits into from
Jun 7, 2019
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
6aa87a0
Add the `internals` field and necessary structures for metering.
losfair May 16, 2019
7e79dd2
Metering middleware.
losfair May 16, 2019
e7297b9
Update singlepass backend to support metering.
losfair May 16, 2019
14fcd78
Update bin/wasmer and run cargo fmt.
losfair May 16, 2019
b830f10
Update metering data on return
losfair May 16, 2019
8e0d71b
Fix missing `internals` in test.
losfair May 16, 2019
6aec1c4
Use `INTERNALS_SIZE`
losfair May 16, 2019
cf58305
Dynamically allocate internal fields.
losfair May 23, 2019
dcf52ef
Cargo fmt
losfair May 23, 2019
9919dd7
Merge remote-tracking branch 'origin/master' into feature/metering
losfair May 23, 2019
68a8800
Temporarily use the original zbox.
losfair May 23, 2019
fd86753
Merge remote-tracking branch 'origin/master' into feature/metering
losfair May 29, 2019
b834b4f
Metering for LLVM.
losfair May 31, 2019
8019505
Merge remote-tracking branch 'origin/feature/clif-cgapi' into feature…
losfair May 31, 2019
c1e817b
Add missing relaxed moves.
losfair May 31, 2019
f029ea6
Merge branch 'master' into feature/metering
bjfish Jun 2, 2019
995ecef
Cargo fmt
bjfish Jun 2, 2019
e533a8a
Add tests for metering, add option to compiler config
bjfish Jun 2, 2019
c020c39
Move get/set points used to middleware
bjfish Jun 2, 2019
f9c8f41
Remove points_limit and update tests
bjfish Jun 2, 2019
8fdc4f9
Start documenting Metering
bjfish Jun 2, 2019
0c3109f
Update Makefile and test configuration
bjfish Jun 2, 2019
605c0dc
Fix indentation in Makefile
bjfish Jun 2, 2019
151af82
Remove debugging println
bjfish Jun 2, 2019
66f9049
Reset LLVM related code to master
bjfish Jun 3, 2019
69944c1
Fix ctx layout in LLVM.
losfair Jun 4, 2019
0867208
Implement {get,set}_points_used.
losfair Jun 4, 2019
f2d8aad
Support checking the execution limit exceeded error.
losfair Jun 5, 2019
f5243af
Cargo fmt
losfair Jun 5, 2019
f832c8d
Try to fix unused import error
bjfish Jun 5, 2019
27eacf0
Add metering benchmark
bjfish Jun 6, 2019
c6cd49a
Support getting/setting metering points and internal fields with a Ctx.
losfair Jun 6, 2019
418764a
Add get/set gas used for benchmark
bjfish Jun 7, 2019
e87d507
Add black_box to benchmarking
bjfish Jun 7, 2019
f6ecfa4
Merge branch 'master' into feature/metering
bjfish Jun 7, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/llvm-backend/src/code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,7 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
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
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 = void_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
2 changes: 1 addition & 1 deletion lib/middleware-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
edition = "2018"

[dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.1" }
wasmer-runtime-core = { path = "../runtime-core" }
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;
90 changes: 90 additions & 0 deletions lib/middleware-common/src/metering.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use wasmer_runtime_core::{
codegen::{Event, EventSink, FunctionMiddleware, InternalEvent},
module::ModuleInfo,
wasmparser::{Operator, Type as WpType},
};

pub struct Metering {
limit: u64,
current_block: u64,
}

impl Metering {
pub fn new(limit: u64) -> Metering {
Metering {
limit,
current_block: 0,
}
}
}

impl FunctionMiddleware for Metering {
type Error = String;
fn feed_event<'a, 'b: 'a>(
&mut self,
op: Event<'a, 'b>,
_module_info: &ModuleInfo,
sink: &mut EventSink<'a, 'b>,
) -> Result<(), Self::Error> {
match op {
Event::Internal(InternalEvent::FunctionBegin(_)) => {
self.current_block = 0;
}
Event::Wasm(&ref op) | Event::WasmOwned(ref op) => {
self.current_block += 1;
match *op {
Operator::Loop { .. }
| Operator::Block { .. }
| Operator::End
| Operator::If { .. }
| Operator::Else
| Operator::Unreachable
| Operator::Br { .. }
| Operator::BrTable { .. }
| Operator::BrIf { .. }
| Operator::Call { .. }
| Operator::CallIndirect { .. }
| Operator::Return => {
sink.push(Event::Internal(InternalEvent::GetInternal(0)));
losfair marked this conversation as resolved.
Show resolved Hide resolved
sink.push(Event::WasmOwned(Operator::I64Const {
value: self.current_block as i64,
}));
sink.push(Event::WasmOwned(Operator::I64Add));
sink.push(Event::Internal(InternalEvent::SetInternal(0)));
self.current_block = 0;
}
_ => {}
}
match *op {
Operator::Br { .. }
| Operator::BrTable { .. }
| Operator::BrIf { .. }
| Operator::Call { .. }
| Operator::CallIndirect { .. } => {
sink.push(Event::Internal(InternalEvent::GetInternal(0)));
sink.push(Event::WasmOwned(Operator::I64Const {
value: self.limit as i64,
}));
sink.push(Event::WasmOwned(Operator::I64GeU));
sink.push(Event::WasmOwned(Operator::If {
ty: WpType::EmptyBlockType,
}));
sink.push(Event::Internal(InternalEvent::Breakpoint(Box::new(
move |ctx| {
eprintln!("execution limit reached");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should remove debugging printlns before merging.

unsafe {
(ctx.throw)();
}
},
))));
sink.push(Event::WasmOwned(Operator::End));
}
_ => {}
}
}
_ => {}
}
sink.push(op);
Ok(())
}
}
16 changes: 15 additions & 1 deletion lib/runtime-core/src/backing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,17 @@ use crate::{
},
vm,
};
use std::slice;
use std::{fmt::Debug, slice};

pub const INTERNALS_SIZE: usize = 256;

pub(crate) struct Internals(pub(crate) [u64; INTERNALS_SIZE]);

impl Debug for Internals {
fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(formatter, "Internals({:?})", &self.0[..])
}
}

/// The `LocalBacking` "owns" the memory used by all the local resources of an Instance.
/// That is, local memories, tables, and globals (as well as some additional
Expand All @@ -40,6 +50,8 @@ pub struct LocalBacking {
/// as well) are subject to change.
pub(crate) dynamic_sigindices: BoxedMap<SigIndex, vm::SigId>,
pub(crate) local_functions: BoxedMap<LocalFuncIndex, *const vm::Func>,

pub(crate) internals: Internals,
}

impl LocalBacking {
Expand All @@ -66,6 +78,8 @@ impl LocalBacking {

dynamic_sigindices,
local_functions,

internals: Internals([0; INTERNALS_SIZE]),
}
}

Expand Down
5 changes: 4 additions & 1 deletion lib/runtime-core/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use wasmparser::{Operator, Type as WpType};
pub enum Event<'a, 'b> {
Internal(InternalEvent),
Wasm(&'b Operator<'a>),
WasmOwned(Operator<'a>),
}

pub enum InternalEvent {
Expand All @@ -39,7 +40,9 @@ impl fmt::Debug for InternalEvent {
}
}

pub struct BkptInfo {}
pub struct BkptInfo {
pub throw: unsafe extern "C" fn() -> !,
}

pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator<E>, RM: RunnableModule, E: Debug> {
/// Creates a new module code generator.
Expand Down
2 changes: 2 additions & 0 deletions lib/runtime-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ pub use self::module::Module;
pub use self::typed_func::Func;
use std::sync::Arc;

pub use wasmparser;

use self::cache::{Artifact, Error as CacheError};

pub mod prelude {
Expand Down
21 changes: 19 additions & 2 deletions lib/runtime-core/src/vm.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub use crate::backing::{ImportBacking, LocalBacking};
pub use crate::backing::{ImportBacking, LocalBacking, INTERNALS_SIZE};
use crate::{
memory::{Memory, MemoryType},
module::{ModuleInfo, ModuleInner},
Expand Down Expand Up @@ -92,6 +92,8 @@ pub struct InternalCtx {

pub memory_base: *mut u8,
pub memory_bound: usize,

pub internals: *mut [u64; INTERNALS_SIZE], // TODO: Make this dynamic?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we consider embedding array?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Internals are intended to be statically allocated to middleware modules. I think a fixed-size array would be suitable for this case.

}

#[repr(C)]
Expand Down Expand Up @@ -200,6 +202,8 @@ impl Ctx {

memory_base: mem_base,
memory_bound: mem_bound,

internals: &mut local_backing.internals.0,
},
local_functions: local_backing.local_functions.as_ptr(),

Expand Down Expand Up @@ -249,6 +253,8 @@ impl Ctx {

memory_base: mem_base,
memory_bound: mem_bound,

internals: &mut local_backing.internals.0,
},
local_functions: local_backing.local_functions.as_ptr(),

Expand Down Expand Up @@ -356,9 +362,13 @@ impl Ctx {
11 * (mem::size_of::<usize>() as u8)
}

pub fn offset_local_functions() -> u8 {
pub fn offset_internals() -> u8 {
12 * (mem::size_of::<usize>() as u8)
}

pub fn offset_local_functions() -> u8 {
13 * (mem::size_of::<usize>() as u8)
}
}

enum InnerFunc {}
Expand Down Expand Up @@ -572,6 +582,11 @@ mod vm_offset_tests {
offset_of!(InternalCtx => memory_bound).get_byte_offset(),
);

assert_eq!(
Ctx::offset_internals() as usize,
offset_of!(InternalCtx => internals).get_byte_offset(),
);

assert_eq!(
Ctx::offset_local_functions() as usize,
offset_of!(Ctx => local_functions).get_byte_offset(),
Expand Down Expand Up @@ -684,6 +699,8 @@ mod vm_ctx_tests {

dynamic_sigindices: Map::new().into_boxed_map(),
local_functions: Map::new().into_boxed_map(),

internals: crate::backing::Internals([0; crate::backing::INTERNALS_SIZE]),
};
let mut import_backing = ImportBacking {
memories: Map::new().into_boxed_map(),
Expand Down
70 changes: 67 additions & 3 deletions lib/singlepass-backend/src/codegen_x64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use wasmer_runtime_core::{
FuncIndex, FuncSig, GlobalIndex, LocalFuncIndex, LocalOrImport, MemoryIndex, SigIndex,
TableIndex, Type,
},
vm::{self, LocalGlobal, LocalTable},
vm::{self, LocalGlobal, LocalTable, INTERNALS_SIZE},
};
use wasmparser::{Operator, Type as WpType};

Expand Down Expand Up @@ -1496,6 +1496,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {

let op = match ev {
Event::Wasm(x) => x,
Event::WasmOwned(ref x) => x,
Event::Internal(x) => {
match x {
InternalEvent::Breakpoint(callback) => {
Expand All @@ -1505,8 +1506,71 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
.unwrap()
.insert(a.get_offset(), callback);
}
InternalEvent::FunctionBegin(_) | InternalEvent::FunctionEnd => {}
_ => unimplemented!(),
InternalEvent::FunctionBegin(_) | InternalEvent::FunctionEnd => {},
InternalEvent::GetInternal(idx) => {
let idx = idx as usize;
assert!(idx < INTERNALS_SIZE);

let tmp = self.machine.acquire_temp_gpr().unwrap();

// Load `internals` pointer.
a.emit_mov(
Size::S64,
Location::Memory(
Machine::get_vmctx_reg(),
vm::Ctx::offset_internals() as i32,
),
Location::GPR(tmp),
);

let loc = self.machine.acquire_locations(
a,
&[WpType::I64],
false,
)[0];
self.value_stack.push((loc, LocalOrTemp::Temp));

// Move internal into the result location.
Self::emit_relaxed_binop(
a,
&mut self.machine,
Assembler::emit_mov,
Size::S64,
Location::Memory(tmp, (idx * 8) as i32),
loc,
);

self.machine.release_temp_gpr(tmp);
}
InternalEvent::SetInternal(idx) => {
let idx = idx as usize;
assert!(idx < INTERNALS_SIZE);

let tmp = self.machine.acquire_temp_gpr().unwrap();

// Load `internals` pointer.
a.emit_mov(
Size::S64,
Location::Memory(
Machine::get_vmctx_reg(),
vm::Ctx::offset_internals() as i32,
),
Location::GPR(tmp),
);
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());

// Move internal into storage.
Self::emit_relaxed_binop(
a,
&mut self.machine,
Assembler::emit_mov,
Size::S64,
loc,
Location::Memory(tmp, (idx * 8) as i32),
);
self.machine.release_temp_gpr(tmp);
}
//_ => unimplemented!(),
}
return Ok(());
}
Expand Down
10 changes: 9 additions & 1 deletion lib/singlepass-backend/src/protect_unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ extern "C" fn signal_trap_handler(
let bkpt_map = BKPT_MAP.with(|x| x.borrow().last().map(|x| x.clone()));
if let Some(bkpt_map) = bkpt_map {
if let Some(ref x) = bkpt_map.get(&(ip as usize)) {
(x)(BkptInfo {});
(x)(BkptInfo { throw: throw });
return;
}
}
Expand Down Expand Up @@ -128,6 +128,14 @@ pub fn call_protected<T>(f: impl FnOnce() -> T) -> Result<T, CallProtError> {
}
}

pub unsafe extern "C" fn throw() -> ! {
let jmp_buf = SETJMP_BUFFER.with(|buf| buf.get());
if *jmp_buf == [0; SETJMP_BUFFER_LEN] {
::std::process::abort();
}
longjmp(jmp_buf as *mut ::nix::libc::c_void, 0xffff);
}

/// Unwinds to last protected_call.
pub unsafe fn do_unwind(signum: i32, siginfo: *const c_void, ucontext: *const c_void) -> ! {
// Since do_unwind is only expected to get called from WebAssembly code which doesn't hold any host resources (locks etc.)
Expand Down
Loading