Skip to content

Commit

Permalink
Adds perf jitdump support
Browse files Browse the repository at this point in the history
Patch adds support for the perf jitdump file specification.
With this patch it should be possible to see profile data for code
generated and maped at runtime. Specifically the patch adds support
for the JIT_CODE_LOAD and the JIT_DEBUG_INFO record as described in
the specification. Dumping jitfiles is enabled with the --jitdump
flag. When the -g flag is also used there is an attempt to dump file
and line number information where this option would be most useful
when the WASM file already includes DWARF debug information.
  • Loading branch information
jlb6740 committed Sep 24, 2019
1 parent bd613ec commit 94001b3
Show file tree
Hide file tree
Showing 16 changed files with 825 additions and 14 deletions.
11 changes: 8 additions & 3 deletions src/bin/wasmtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ including calling the start function if one is present. Additional functions
given with --invoke are then called.
Usage:
wasmtime [-odg] [--enable-simd] [--wasi-c] [--cache | --cache-config=<cache_config_file>] [--create-cache-config] [--preload=<wasm>...] [--env=<env>...] [--dir=<dir>...] [--mapdir=<mapping>...] <file> [<arg>...]
wasmtime [-odg] [--enable-simd] [--wasi-c] [--cache | --cache-config=<cache_config_file>] [--create-cache-config] [--env=<env>...] [--dir=<dir>...] [--mapdir=<mapping>...] --invoke=<fn> <file> [<arg>...]
wasmtime [-odg] [--enable-simd] [--jitdump] [--wasi-c] [--cache | --cache-config=<cache_config_file>] [--create-cache-config] [--preload=<wasm>...] [--env=<env>...] [--dir=<dir>...] [--mapdir=<mapping>...] <file> [<arg>...]
wasmtime [-odg] [--enable-simd] [--jitdump] [--wasi-c] [--cache | --cache-config=<cache_config_file>] [--create-cache-config] [--env=<env>...] [--dir=<dir>...] [--mapdir=<mapping>...] --invoke=<fn> <file> [<arg>...]
wasmtime --help | --version
Options:
Expand All @@ -78,6 +78,7 @@ Options:
-g generate debug information
-d, --debug enable debug output on stderr/stdout
--enable-simd enable proposed SIMD instructions
--jitdump generate perf jitdump files for runtime generated code
--wasi-c enable the wasi-c implementation of WASI
--preload=<wasm> load an additional wasm module before loading the main module
--env=<env> pass an environment variable (\"key=value\") to the program
Expand All @@ -99,6 +100,7 @@ struct Args {
flag_debug: bool,
flag_g: bool,
flag_enable_simd: bool,
flag_jitdump: bool,
flag_invoke: Option<String>,
flag_preload: Vec<String>,
flag_env: Vec<String>,
Expand Down Expand Up @@ -254,12 +256,15 @@ fn rmain() -> Result<(), Error> {
features.simd = true;
}

// Enable Jitdump if requested
let perf_profile = args.flag_jitdump;

// Enable optimization if requested.
if args.flag_optimize {
flag_builder.set("opt_level", "best")?;
}

let config = Config::new(settings::Flags::new(flag_builder), features, debug_info);
let config = Config::new(settings::Flags::new(flag_builder), features, debug_info, perf_profile);
let engine = HostRef::new(Engine::new(config));
let store = HostRef::new(Store::new(engine));

Expand Down
12 changes: 9 additions & 3 deletions wasmtime-api/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,31 @@ pub struct Context {
compiler: Rc<RefCell<Compiler>>,
features: Features,
debug_info: bool,
perf_profile: bool,
}

impl Context {
pub fn new(compiler: Compiler, features: Features, debug_info: bool) -> Context {
pub fn new(compiler: Compiler, features: Features, debug_info: bool, perf_profile: bool) -> Context {
Context {
compiler: Rc::new(RefCell::new(compiler)),
features,
debug_info,
perf_profile,
}
}

pub fn create(flags: settings::Flags, features: Features, debug_info: bool) -> Context {
Context::new(create_compiler(flags), features, debug_info)
pub fn create(flags: settings::Flags, features: Features, debug_info: bool, perf_profile: bool) -> Context {
Context::new(create_compiler(flags), features, debug_info, perf_profile)
}

pub(crate) fn debug_info(&self) -> bool {
self.debug_info
}

pub(crate) fn perf_profile(&self) -> bool {
self.perf_profile
}

pub(crate) fn compiler(&mut self) -> RefMut<Compiler> {
self.compiler.borrow_mut()
}
Expand Down
2 changes: 2 additions & 0 deletions wasmtime-api/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,15 @@ pub fn instantiate_in_context(
) -> Result<(InstanceHandle, HashSet<Context>), Error> {
let mut contexts = HashSet::new();
let debug_info = context.debug_info();
let perf_profile = context.perf_profile();
let mut resolver = SimpleResolver { imports };
let instance = instantiate(
&mut context.compiler(),
data,
&mut resolver,
exports,
debug_info,
perf_profile,
)?;
contexts.insert(context);
Ok((instance, contexts))
Expand Down
12 changes: 10 additions & 2 deletions wasmtime-api/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,29 +21,36 @@ pub struct Config {
flags: settings::Flags,
features: Features,
debug_info: bool,
perf_profile: bool,
}

impl Config {
pub fn default() -> Config {
Config {
debug_info: false,
perf_profile: false,
features: Default::default(),
flags: default_flags(),
}
}

pub fn new(flags: settings::Flags, features: Features, debug_info: bool) -> Config {
pub fn new(flags: settings::Flags, features: Features, debug_info: bool, perf_profile: bool) -> Config {
Config {
flags,
features,
debug_info,
perf_profile,
}
}

pub(crate) fn debug_info(&self) -> bool {
self.debug_info
}

pub(crate) fn perf_profile(&self) -> bool {
self.perf_profile
}

pub(crate) fn flags(&self) -> &settings::Flags {
&self.flags
}
Expand Down Expand Up @@ -92,9 +99,10 @@ impl Store {
let flags = engine.borrow().config().flags().clone();
let features = engine.borrow().config().features().clone();
let debug_info = engine.borrow().config().debug_info();
let perf_profile = engine.borrow().config().perf_profile();
Store {
engine,
context: Context::create(flags, features, debug_info),
context: Context::create(flags, features, debug_info, perf_profile),
global_exports: Rc::new(RefCell::new(HashMap::new())),
signature_cache: HashMap::new(),
}
Expand Down
1 change: 1 addition & 0 deletions wasmtime-api/src/trampoline/create_handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ pub(crate) fn create_handle(
&data_initializers,
signatures.into_boxed_slice(),
None,
None,
state,
)
.expect("instance"))
Expand Down
2 changes: 2 additions & 0 deletions wasmtime-jit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ failure_derive = { version = "0.1.3", default-features = false }
target-lexicon = { version = "0.4.0", default-features = false }
hashbrown = { version = "0.6.0", optional = true }
wasmparser = "0.36.0"
gimli = "0.19.0"
object = "0.14.0"

[features]
default = ["std"]
Expand Down
10 changes: 9 additions & 1 deletion wasmtime-jit/src/code_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use region;
use std::boxed::Box;
use std::string::String;
use std::vec::Vec;
use wasmtime_runtime::{Mmap, VMFunctionBody};
use wasmtime_runtime::{Mmap, VMFunctionBody, JitDumpAgent};

/// Memory manager for executable code.
pub(crate) struct CodeMemory {
Expand Down Expand Up @@ -99,4 +99,12 @@ impl CodeMemory {
}
self.published = self.mmaps.len();
}

pub fn perf_module_load(&mut self, module_name: &str, jit_dump_agent: &JitDumpAgent, dbg_image: Option<&[u8]>) -> () {
for map in &mut self.mmaps {
if map.len() > 0 {
jit_dump_agent.clone().module_load(module_name, map.as_ptr(), map.len(), dbg_image);
}
}
}
}
6 changes: 5 additions & 1 deletion wasmtime-jit/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use wasmtime_environ::{
Compilation, CompileError, Compiler as _C, FunctionBodyData, Module, ModuleVmctxInfo,
Relocations, Tunables, VMOffsets,
};
use wasmtime_runtime::{InstantiationError, SignatureRegistry, VMFunctionBody};
use wasmtime_runtime::{InstantiationError, SignatureRegistry, VMFunctionBody, JitDumpAgent};

/// A WebAssembly code JIT compiler.
///
Expand Down Expand Up @@ -181,6 +181,10 @@ impl Compiler {
self.code_memory.publish();
}

pub(crate) fn perf_module_load(&mut self, module_name: &str, jit_dump_agent: &JitDumpAgent, dbg_image: Option<&[u8]>) -> () {
self.code_memory.perf_module_load( module_name, jit_dump_agent, dbg_image);
}

/// Shared signature registry.
pub fn signatures(&mut self) -> &mut SignatureRegistry {
&mut self.signatures
Expand Down
9 changes: 9 additions & 0 deletions wasmtime-jit/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ pub struct Context {
compiler: Box<Compiler>,
global_exports: Rc<RefCell<HashMap<String, Option<wasmtime_runtime::Export>>>>,
debug_info: bool,
perf_profile: bool,
features: Features,
}

Expand All @@ -89,6 +90,7 @@ impl Context {
compiler,
global_exports: Rc::new(RefCell::new(HashMap::new())),
debug_info: false,
perf_profile: false,
features: Default::default(),
}
}
Expand All @@ -98,6 +100,11 @@ impl Context {
self.debug_info
}

/// Get debug_info settings.
pub fn perf_profile(&self) -> bool {
self.perf_profile
}

/// Set debug_info settings.
pub fn set_debug_info(&mut self, value: bool) {
self.debug_info = value;
Expand Down Expand Up @@ -127,13 +134,15 @@ impl Context {
fn instantiate(&mut self, data: &[u8]) -> Result<InstanceHandle, SetupError> {
self.validate(&data).map_err(SetupError::Validate)?;
let debug_info = self.debug_info();
let perf_profile = self.perf_profile();

instantiate(
&mut *self.compiler,
&data,
&mut self.namespace,
Rc::clone(&self.global_exports),
debug_info,
perf_profile,
)
}

Expand Down
37 changes: 33 additions & 4 deletions wasmtime-jit/src/instantiate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use wasmtime_environ::{
CompileError, DataInitializer, DataInitializerLocation, Module, ModuleEnvironment,
};
use wasmtime_runtime::{
Export, GdbJitImageRegistration, Imports, InstanceHandle, InstantiationError, VMFunctionBody,
Export, GdbJitImageRegistration, JitDumpAgent, Imports, InstanceHandle, InstantiationError, VMFunctionBody,
VMSharedSignatureIndex,
};

Expand Down Expand Up @@ -55,6 +55,7 @@ struct RawCompiledModule<'data> {
data_initializers: Box<[DataInitializer<'data>]>,
signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
dbg_jit_registration: Option<GdbJitImageRegistration>,
jit_dump_agent: Option<JitDumpAgent>,
}

impl<'data> RawCompiledModule<'data> {
Expand All @@ -64,6 +65,7 @@ impl<'data> RawCompiledModule<'data> {
data: &'data [u8],
resolver: &mut dyn Resolver,
debug_info: bool,
perf_profile: bool,
) -> Result<Self, SetupError> {
let environ = ModuleEnvironment::new(compiler.frontend_config(), compiler.tunables());

Expand Down Expand Up @@ -117,6 +119,24 @@ impl<'data> RawCompiledModule<'data> {
// Make all code compiled thus far executable.
compiler.publish_compiled_code();

// Create jitdump files
let jit_dump_agent = if perf_profile {
let agent = JitDumpAgent::new().ok();
let region_name = String::from("wasm_module");
match &agent {
Some(agent) => {
match &dbg_image {
Some(dbg) => compiler.perf_module_load(&region_name, agent, Some(&dbg)),
_ => compiler.perf_module_load(&region_name, agent, None),
}
},
_ => (),
}
agent
} else {
None
};

let dbg_jit_registration = if let Some(img) = dbg_image {
let mut bytes = Vec::new();
bytes.write_all(&img).expect("all written");
Expand All @@ -133,6 +153,7 @@ impl<'data> RawCompiledModule<'data> {
data_initializers: translation.data_initializers.into_boxed_slice(),
signatures: signatures.into_boxed_slice(),
dbg_jit_registration,
jit_dump_agent,
})
}
}
Expand All @@ -146,6 +167,7 @@ pub struct CompiledModule {
signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
global_exports: Rc<RefCell<HashMap<String, Option<Export>>>>,
dbg_jit_registration: Option<Rc<GdbJitImageRegistration>>,
jit_dump_agent: Option<JitDumpAgent>,
}

impl CompiledModule {
Expand All @@ -156,8 +178,9 @@ impl CompiledModule {
resolver: &mut dyn Resolver,
global_exports: Rc<RefCell<HashMap<String, Option<Export>>>>,
debug_info: bool,
perf_profile: bool,
) -> Result<Self, SetupError> {
let raw = RawCompiledModule::<'data>::new(compiler, data, resolver, debug_info)?;
let raw = RawCompiledModule::<'data>::new(compiler, data, resolver, debug_info, perf_profile)?;

Ok(Self::from_parts(
raw.module,
Expand All @@ -171,6 +194,7 @@ impl CompiledModule {
.into_boxed_slice(),
raw.signatures.clone(),
raw.dbg_jit_registration,
raw.jit_dump_agent,
))
}

Expand All @@ -183,6 +207,7 @@ impl CompiledModule {
data_initializers: Box<[OwnedDataInitializer]>,
signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
dbg_jit_registration: Option<GdbJitImageRegistration>,
jit_dump_agent: Option<JitDumpAgent>,
) -> Self {
Self {
module: Rc::new(module),
Expand All @@ -192,6 +217,7 @@ impl CompiledModule {
data_initializers,
signatures,
dbg_jit_registration: dbg_jit_registration.map(|r| Rc::new(r)),
jit_dump_agent,
}
}

Expand All @@ -217,6 +243,7 @@ impl CompiledModule {
&data_initializers,
self.signatures.clone(),
self.dbg_jit_registration.as_ref().map(|r| Rc::clone(&r)),
self.jit_dump_agent.clone(),
Box::new(()),
)
}
Expand All @@ -243,16 +270,17 @@ impl OwnedDataInitializer {

/// Create a new wasm instance by compiling the wasm module in `data` and instatiating it.
///
/// This is equivalent to createing a `CompiledModule` and calling `instantiate()` on it,
/// This is equivalent to creating a `CompiledModule` and calling `instantiate()` on it,
/// but avoids creating an intermediate copy of the data initializers.
pub fn instantiate(
compiler: &mut Compiler,
data: &[u8],
resolver: &mut dyn Resolver,
global_exports: Rc<RefCell<HashMap<String, Option<Export>>>>,
debug_info: bool,
perf_profile: bool,
) -> Result<InstanceHandle, SetupError> {
let raw = RawCompiledModule::new(compiler, data, resolver, debug_info)?;
let raw = RawCompiledModule::new(compiler, data, resolver, debug_info, perf_profile)?;

InstanceHandle::new(
Rc::new(raw.module),
Expand All @@ -262,6 +290,7 @@ pub fn instantiate(
&*raw.data_initializers,
raw.signatures,
raw.dbg_jit_registration.map(|r| Rc::new(r)),
raw.jit_dump_agent,
Box::new(()),
)
.map_err(SetupError::Instantiate)
Expand Down
Loading

0 comments on commit 94001b3

Please sign in to comment.