diff --git a/Cargo.lock b/Cargo.lock index e1e3147c8c0..3e32bf47767 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2712,6 +2712,7 @@ dependencies = [ "criterion", "glob", "lazy_static", + "loupe", "rustc_version 0.3.3", "tempfile", "test-generator", diff --git a/Cargo.toml b/Cargo.toml index 40fda1950f5..9f6de974cfe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ wasmer-cache = { version = "1.0.2", path = "lib/cache", optional = true } wasmer-types = { version = "1.0.2", path = "lib/wasmer-types" } wasmer-middlewares = { version = "1.0.2", path = "lib/middlewares", optional = true } cfg-if = "1.0" +loupe = { path = "../loupe/crates/loupe" } [workspace] members = [ diff --git a/examples/hello_world.rs b/examples/hello_world.rs index dbe559226e3..87cb3a0efb5 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -6,6 +6,7 @@ //! cargo run --example hello-world --release --features "cranelift" //! ``` +use loupe::size_of_val; use wasmer::{imports, wat2wasm, Function, Instance, Module, NativeFunc, Store}; use wasmer_compiler_cranelift::Cranelift; use wasmer_engine_jit::JIT; @@ -45,10 +46,15 @@ fn main() -> anyhow::Result<()> { // (`Cranelift`) and pass it to an engine (`JIT`). We then pass the engine to // the store and are now ready to compile and run WebAssembly! let store = Store::new(&JIT::new(Cranelift::default()).engine()); + dbg!(size_of_val(&store)); + // We then use our store and Wasm bytes to compile a `Module`. // A `Module` is a compiled WebAssembly module that isn't ready to execute yet. let module = Module::new(&store, wasm_bytes)?; + dbg!(size_of_val(&store)); + dbg!(size_of_val(&module)); + // Next we'll set up our `Module` so that we can execute it. // We define a function to act as our "env" "say_hello" function imported in the @@ -71,6 +77,10 @@ fn main() -> anyhow::Result<()> { // An `Instance` is a compiled WebAssembly module that has been set up // and is ready to execute. let instance = Instance::new(&module, &import_object)?; + + dbg!(size_of_val(&instance)); + dbg!(&instance.exports); + // We get the `NativeFunc` with no parameters and no results from the instance. // // Recall that the Wasm module exported a function named "run", this is getting diff --git a/lib/api/src/exports.rs b/lib/api/src/exports.rs index 606a052e52a..13082248f42 100644 --- a/lib/api/src/exports.rs +++ b/lib/api/src/exports.rs @@ -3,6 +3,7 @@ use crate::import_object::LikeNamespace; use crate::native::NativeFunc; use crate::WasmTypeList; use indexmap::IndexMap; +use loupe_derive::MemoryUsage; use std::fmt; use std::iter::{ExactSizeIterator, FromIterator}; use std::sync::Arc; @@ -61,7 +62,7 @@ pub enum ExportError { /// the types of instances. /// /// TODO: add examples of using exports -#[derive(Clone, Default)] +#[derive(Clone, Default, MemoryUsage)] pub struct Exports { map: Arc>, } diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index f925852af5c..889b8f37578 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -10,6 +10,7 @@ pub use inner::{FromToNativeWasmType, HostFunction, WasmTypeList, WithEnv, Witho #[cfg(feature = "deprecated")] pub use inner::{UnsafeMutableEnv, WithUnsafeMutableEnv}; +use loupe_derive::MemoryUsage; use std::cmp::max; use std::ffi::c_void; use std::fmt; @@ -22,21 +23,22 @@ use wasmer_vm::{ }; /// A function defined in the Wasm module -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, MemoryUsage)] pub struct WasmFunctionDefinition { // Address of the trampoline to do the call. + #[memoryusage(ignore)] pub(crate) trampoline: VMTrampoline, } /// A function defined in the Host -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, MemoryUsage)] pub struct HostFunctionDefinition { /// If the host function has a custom environment attached pub(crate) has_env: bool, } /// The inner helper -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, MemoryUsage)] pub enum FunctionDefinition { /// A function defined in the Wasm side Wasm(WasmFunctionDefinition), @@ -61,7 +63,7 @@ pub enum FunctionDefinition { /// with native functions. Attempting to create a native `Function` with one will /// result in a panic. /// [Closures as host functions tracking issue](https://github.com/wasmerio/wasmer/issues/1840) -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, MemoryUsage)] pub struct Function { pub(crate) store: Store, pub(crate) definition: FunctionDefinition, diff --git a/lib/api/src/externals/global.rs b/lib/api/src/externals/global.rs index 49f2a4c1234..2f7ce83f78b 100644 --- a/lib/api/src/externals/global.rs +++ b/lib/api/src/externals/global.rs @@ -5,6 +5,7 @@ use crate::types::Val; use crate::GlobalType; use crate::Mutability; use crate::RuntimeError; +use loupe_derive::MemoryUsage; use std::fmt; use std::sync::Arc; use wasmer_engine::{Export, ExportGlobal}; @@ -16,7 +17,7 @@ use wasmer_vm::{Global as RuntimeGlobal, VMExportGlobal}; /// It consists of an individual value and a flag indicating whether it is mutable. /// /// Spec: -#[derive(Clone)] +#[derive(Clone, MemoryUsage)] pub struct Global { store: Store, global: Arc, diff --git a/lib/api/src/externals/memory.rs b/lib/api/src/externals/memory.rs index 423345a27a3..e140c1e5fba 100644 --- a/lib/api/src/externals/memory.rs +++ b/lib/api/src/externals/memory.rs @@ -2,6 +2,7 @@ use crate::exports::{ExportError, Exportable}; use crate::externals::Extern; use crate::store::Store; use crate::{MemoryType, MemoryView}; +use loupe_derive::MemoryUsage; use std::convert::TryInto; use std::slice; use std::sync::Arc; @@ -23,7 +24,7 @@ use wasmer_vm::{Memory as RuntimeMemory, MemoryError, VMExportMemory}; /// mutable from both host and WebAssembly. /// /// Spec: -#[derive(Debug, Clone)] +#[derive(Debug, Clone, MemoryUsage)] pub struct Memory { store: Store, memory: Arc, diff --git a/lib/api/src/externals/mod.rs b/lib/api/src/externals/mod.rs index c8f15e3c16b..8927f830be0 100644 --- a/lib/api/src/externals/mod.rs +++ b/lib/api/src/externals/mod.rs @@ -16,6 +16,7 @@ pub use self::table::Table; use crate::exports::{ExportError, Exportable}; use crate::store::{Store, StoreObject}; use crate::ExternType; +use loupe_derive::MemoryUsage; use std::fmt; use wasmer_engine::Export; @@ -23,7 +24,7 @@ use wasmer_engine::Export; /// can be imported or exported. /// /// Spec: -#[derive(Clone)] +#[derive(Clone, MemoryUsage)] pub enum Extern { /// A external [`Function`]. Function(Function), diff --git a/lib/api/src/externals/table.rs b/lib/api/src/externals/table.rs index 8e2f43696dc..3c625ae27f4 100644 --- a/lib/api/src/externals/table.rs +++ b/lib/api/src/externals/table.rs @@ -4,6 +4,7 @@ use crate::store::Store; use crate::types::{Val, ValFuncRef}; use crate::RuntimeError; use crate::TableType; +use loupe_derive::MemoryUsage; use std::sync::Arc; use wasmer_engine::{Export, ExportTable}; use wasmer_vm::{Table as RuntimeTable, VMCallerCheckedAnyfunc, VMExportTable}; @@ -17,7 +18,7 @@ use wasmer_vm::{Table as RuntimeTable, VMCallerCheckedAnyfunc, VMExportTable}; /// mutable from both host and WebAssembly. /// /// Spec: -#[derive(Clone)] +#[derive(Clone, MemoryUsage)] pub struct Table { store: Store, table: Arc, diff --git a/lib/api/src/instance.rs b/lib/api/src/instance.rs index 93c0b42fe49..327bfb60d75 100644 --- a/lib/api/src/instance.rs +++ b/lib/api/src/instance.rs @@ -3,6 +3,7 @@ use crate::externals::Extern; use crate::module::Module; use crate::store::Store; use crate::{HostEnvInitError, LinkError, RuntimeError}; +use loupe_derive::MemoryUsage; use std::fmt; use std::sync::{Arc, Mutex}; use thiserror::Error; @@ -17,7 +18,7 @@ use wasmer_vm::{InstanceHandle, VMContext}; /// interacting with WebAssembly. /// /// Spec: -#[derive(Clone)] +#[derive(Clone, MemoryUsage)] pub struct Instance { handle: Arc>, module: Module, diff --git a/lib/engine/src/export.rs b/lib/engine/src/export.rs index e3342265abf..754cc689dc0 100644 --- a/lib/engine/src/export.rs +++ b/lib/engine/src/export.rs @@ -1,10 +1,10 @@ +use loupe_derive::MemoryUsage; +use std::sync::Arc; use wasmer_vm::{ ImportInitializerFuncPtr, VMExport, VMExportFunction, VMExportGlobal, VMExportMemory, VMExportTable, }; -use std::sync::Arc; - /// The value of an export passed from one instance to another. #[derive(Debug, Clone)] pub enum Export { @@ -54,7 +54,7 @@ impl From for Export { /// /// This struct owns the original `host_env`, thus when it gets dropped /// it calls the `drop` function on it. -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, MemoryUsage)] pub struct ExportFunctionMetadata { /// This field is stored here to be accessible by `Drop`. /// @@ -69,20 +69,26 @@ pub struct ExportFunctionMetadata { /// See `wasmer_vm::export::VMExportFunction::vmctx` for the version of /// this pointer that is used by the VM when creating an `Instance`. pub(crate) host_env: *mut std::ffi::c_void, + /// Function pointer to `WasmerEnv::init_with_instance(&mut self, instance: &Instance)`. /// /// This function is called to finish setting up the environment after /// we create the `api::Instance`. // This one is optional for now because dynamic host envs need the rest // of this without the init fn + #[memoryusage(ignore)] pub(crate) import_init_function_ptr: Option, + /// A function analogous to `Clone::clone` that returns a leaked `Box`. + #[memoryusage(ignore)] pub(crate) host_env_clone_fn: fn(*mut std::ffi::c_void) -> *mut std::ffi::c_void, + /// The destructor to free the host environment. /// /// # Safety /// - This function should only be called in when properly synchronized. /// For example, in the `Drop` implementation of this type. + #[memoryusage(ignore)] pub(crate) host_env_drop_fn: unsafe fn(*mut std::ffi::c_void), } @@ -132,7 +138,7 @@ impl Drop for ExportFunctionMetadata { /// A function export value with an extra function pointer to initialize /// host environments. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, MemoryUsage)] pub struct ExportFunction { /// The VM function, containing most of the data. pub vm_function: VMExportFunction, diff --git a/lib/vm/src/export.rs b/lib/vm/src/export.rs index e5d3475ea10..500ae967563 100644 --- a/lib/vm/src/export.rs +++ b/lib/vm/src/export.rs @@ -6,6 +6,7 @@ use crate::instance::InstanceRef; use crate::memory::{Memory, MemoryStyle}; use crate::table::{Table, TableStyle}; use crate::vmcontext::{VMFunctionBody, VMFunctionEnvironment, VMFunctionKind, VMTrampoline}; +use loupe_derive::MemoryUsage; use std::sync::Arc; use wasmer_types::{FunctionType, MemoryType, TableType}; @@ -26,7 +27,7 @@ pub enum VMExport { } /// A function export value. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, MemoryUsage)] pub struct VMExportFunction { /// The address of the native-code function. pub address: *const VMFunctionBody, @@ -46,6 +47,7 @@ pub struct VMExportFunction { /// /// May be `None` when the function is a host function (`FunctionType` /// == `Dynamic` or `vmctx` == `nullptr`). + #[memoryusage(ignore)] pub call_trampoline: Option, /// A “reference” to the instance through the diff --git a/lib/vm/src/instance/mod.rs b/lib/vm/src/instance/mod.rs index 986ee9d5156..dd31d3617cf 100644 --- a/lib/vm/src/instance/mod.rs +++ b/lib/vm/src/instance/mod.rs @@ -28,6 +28,7 @@ use crate::vmcontext::{ use crate::{FunctionBodyPtr, ModuleInfo, VMOffsets}; use crate::{VMExportFunction, VMExportGlobal, VMExportMemory, VMExportTable}; use loupe::{MemoryUsage, MemoryUsageTracker}; +use loupe_derive::MemoryUsage; use memoffset::offset_of; use more_asserts::assert_lt; use std::any::Any; @@ -57,6 +58,7 @@ pub type ImportInitializerFuncPtr = /// contain various data. That's why the type has a C representation /// to ensure that the `vmctx` field is last. See the documentation of /// the `vmctx` field to learn more. +#[derive(MemoryUsage)] #[repr(C)] pub(crate) struct Instance { /// The `ModuleInfo` this `Instance` was instantiated from. @@ -78,6 +80,7 @@ pub(crate) struct Instance { functions: BoxedSlice, /// Pointers to function call trampolines in executable memory. + #[memoryusage(ignore)] function_call_trampolines: BoxedSlice, /// Passive elements in this instantiation. As `elem.drop`s happen, these @@ -92,6 +95,7 @@ pub(crate) struct Instance { host_state: Box, /// Handler run when `SIGBUS`, `SIGFPE`, `SIGILL`, or `SIGSEGV` are caught by the instance thread. + #[memoryusage(ignore)] pub(crate) signal_handler: Cell>>, /// Functions to operate on host environments in the imports @@ -105,6 +109,7 @@ pub(crate) struct Instance { /// field is last, and represents a dynamically-sized array that /// extends beyond the nominal end of the struct (similar to a /// flexible array member). + #[memoryusage(ignore)] vmctx: VMContext, } @@ -785,7 +790,7 @@ impl Instance { /// /// This is more or less a public facade of the private `Instance`, /// providing useful higher-level API. -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, MemoryUsage)] pub struct InstanceHandle { /// The [`InstanceRef`]. See its documentation to learn more. instance: InstanceRef, diff --git a/lib/vm/src/instance/ref.rs b/lib/vm/src/instance/ref.rs index c9081bba6cb..77daeddc634 100644 --- a/lib/vm/src/instance/ref.rs +++ b/lib/vm/src/instance/ref.rs @@ -1,5 +1,7 @@ use super::Instance; +use loupe::{MemoryUsage, MemoryUsageTracker}; use std::alloc::Layout; +use std::mem; use std::ptr::{self, NonNull}; use std::sync::{atomic, Arc}; @@ -208,3 +210,13 @@ impl Drop for InstanceRef { unsafe { Self::deallocate_instance(self) }; } } + +impl MemoryUsage for InstanceRef { + fn size_of_val(&self, tracker: &mut dyn MemoryUsageTracker) -> usize { + mem::size_of_val(self) + self.strong.size_of_val(tracker) - mem::size_of_val(&self.strong) + + self.instance_layout.size_of_val(tracker) + - mem::size_of_val(&self.instance_layout) + + self.as_ref().size_of_val(tracker) + - mem::size_of_val(&self.instance) + } +} diff --git a/lib/vm/src/vmcontext.rs b/lib/vm/src/vmcontext.rs index b3f8a50a3c0..114a16eab05 100644 --- a/lib/vm/src/vmcontext.rs +++ b/lib/vm/src/vmcontext.rs @@ -176,7 +176,7 @@ mod test_vmfunction_body { } /// A function kind is a calling convention into and out of wasm code. -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, MemoryUsage)] #[repr(C)] pub enum VMFunctionKind { /// A static function has the native signature: diff --git a/lib/vm/src/vmoffsets.rs b/lib/vm/src/vmoffsets.rs index a786114705a..4b86212c57a 100644 --- a/lib/vm/src/vmoffsets.rs +++ b/lib/vm/src/vmoffsets.rs @@ -8,6 +8,7 @@ use crate::module::ModuleInfo; use crate::VMBuiltinFunctionIndex; +use loupe_derive::MemoryUsage; use more_asserts::assert_lt; use std::convert::TryFrom; use wasmer_types::{ @@ -33,7 +34,7 @@ const fn align(offset: u32, width: u32) -> u32 { /// related structs that JIT code accesses directly. /// /// [`VMContext`]: crate::vmcontext::VMContext -#[derive(Clone, Debug)] +#[derive(Clone, Debug, MemoryUsage)] pub struct VMOffsets { /// The size in bytes of a pointer on the target. pub pointer_size: u8,