@ -83,6 +83,28 @@ fn parse_preloads(s: &str) -> Result<(String, PathBuf)> {
Ok ( ( parts [ 0 ] . into ( ) , parts [ 1 ] . into ( ) ) )
Ok ( ( parts [ 0 ] . into ( ) , parts [ 1 ] . into ( ) ) )
}
}
fn parse_profile ( s : & str ) -> Result < Profile > {
let parts = s . split ( ',' ) . collect ::< Vec < _ > > ( ) ;
match & parts [ . . ] {
[ "perfmap" ] = > Ok ( Profile ::Native ( wasmtime ::ProfilingStrategy ::PerfMap ) ) ,
[ "jitdump" ] = > Ok ( Profile ::Native ( wasmtime ::ProfilingStrategy ::JitDump ) ) ,
[ "vtune" ] = > Ok ( Profile ::Native ( wasmtime ::ProfilingStrategy ::VTune ) ) ,
[ "guest" ] = > Ok ( Profile ::Guest {
path : "wasmtime-guest-profile.json" . to_string ( ) ,
interval : Duration ::from_millis ( 10 ) ,
} ) ,
[ "guest" , path ] = > Ok ( Profile ::Guest {
path : path . to_string ( ) ,
interval : Duration ::from_millis ( 10 ) ,
} ) ,
[ "guest" , path , dur ] = > Ok ( Profile ::Guest {
path : path . to_string ( ) ,
interval : parse_dur ( dur ) ? ,
} ) ,
_ = > bail ! ( "unknown profiling strategy: {s}" ) ,
}
}
static AFTER_HELP : Lazy < String > = Lazy ::new ( | | crate ::FLAG_EXPLANATIONS . to_string ( ) ) ;
static AFTER_HELP : Lazy < String > = Lazy ::new ( | | crate ::FLAG_EXPLANATIONS . to_string ( ) ) ;
/// Runs a WebAssembly module
/// Runs a WebAssembly module
@ -169,22 +191,27 @@ pub struct RunCommand {
) ]
) ]
wasm_timeout : Option < Duration > ,
wasm_timeout : Option < Duration > ,
/// Enable in-process sampling profiling of the guest WebAssembly program,
/// Profiling strategy (valid options are: perfmap, jitdump, vtune, guest)
/// and write the captured profile to the given path. The resulting file
///
/// can be viewed using https://profiler.firefox.com/.
/// The perfmap, jitdump, and vtune profiling strategies integrate Wasmtime
#[ clap(long, value_name = " PATH " ) ]
/// with external profilers such as `perf`. The guest profiling strategy
profile_guest : Option < PathBuf > ,
/// enables in-process sampling and will write the captured profile to
/// `wasmtime-guest-profile.json` by default which can be viewed at
/// Sampling interval for in-process profiling with `--profile-guest`. When
/// https://profiler.firefox.com/.
/// used together with `--wasm-timeout`, the timeout will be rounded up to
///
/// the nearest multiple of this interval.
/// The `guest` option can be additionally configured as:
///
/// --profile=guest[,path[,interval]]
///
/// where `path` is where to write the profile and `interval` is the
/// duration between samples. When used with `--wasm-timeout` the timeout
/// will be rounded up to the nearest multiple of this interval.
#[ clap(
#[ clap(
long ,
long ,
default_value = "10ms" ,
value_name = "STRATEGY" ,
value_name = "TIME" ,
parse ( try_from_str = parse_profile ) ,
parse ( try_from_str = parse_dur ) ,
) ]
) ]
profile_guest_interval : Duration ,
profile : Option < Profile > ,
/// Enable coredump generation after a WebAssembly trap.
/// Enable coredump generation after a WebAssembly trap.
#[ clap(long = " coredump-on-trap " , value_name = " PATH " ) ]
#[ clap(long = " coredump-on-trap " , value_name = " PATH " ) ]
@ -228,6 +255,11 @@ pub struct RunCommand {
trap_on_grow_failure : bool ,
trap_on_grow_failure : bool ,
}
}
enum Profile {
Native ( wasmtime ::ProfilingStrategy ) ,
Guest { path : String , interval : Duration } ,
}
impl RunCommand {
impl RunCommand {
/// Executes the command.
/// Executes the command.
pub fn execute ( & self ) -> Result < ( ) > {
pub fn execute ( & self ) -> Result < ( ) > {
@ -235,9 +267,19 @@ impl RunCommand {
let mut config = self . common . config ( None ) ? ;
let mut config = self . common . config ( None ) ? ;
if self . wasm_timeout . is_some ( ) | | self . profile_guest . is_some ( ) {
if self . wasm_timeout . is_some ( ) {
config . epoch_interruption ( true ) ;
config . epoch_interruption ( true ) ;
}
}
match self . profile {
Some ( Profile ::Native ( s ) ) = > {
config . profiler ( s ) ;
}
Some ( Profile ::Guest { . . } ) = > {
// Further configured down below as well.
config . epoch_interruption ( true ) ;
}
None = > { }
}
let engine = Engine ::new ( & config ) ? ;
let engine = Engine ::new ( & config ) ? ;
@ -398,8 +440,8 @@ impl RunCommand {
module_name : & str ,
module_name : & str ,
modules : Vec < ( String , Module ) > ,
modules : Vec < ( String , Module ) > ,
) -> Box < dyn FnOnce ( & mut Store < Host > ) > {
) -> Box < dyn FnOnce ( & mut Store < Host > ) > {
if let Some ( path ) = & self . profile_guest {
if let Some ( Profile ::Guest { path , interval } ) = & self . profile {
let interval = self . profile_guest_ interval;
let interval = * interval ;
store . data_mut ( ) . guest_profiler =
store . data_mut ( ) . guest_profiler =
Some ( Arc ::new ( GuestProfiler ::new ( module_name , interval , modules ) ) ) ;
Some ( Arc ::new ( GuestProfiler ::new ( module_name , interval , modules ) ) ) ;
@ -449,10 +491,10 @@ impl RunCommand {
. map_err ( anyhow ::Error ::new )
. map_err ( anyhow ::Error ::new )
. and_then ( | output | profiler . finish ( std ::io ::BufWriter ::new ( output ) ) )
. and_then ( | output | profiler . finish ( std ::io ::BufWriter ::new ( output ) ) )
{
{
eprintln ! ( "failed writing profile at {}: {e:#}" , path . display ( ) ) ;
eprintln ! ( "failed writing profile at {path }: {e:#}" ) ;
} else {
} else {
eprintln ! ( ) ;
eprintln ! ( ) ;
eprintln ! ( "Profile written to: {}" , path . display ( ) ) ;
eprintln ! ( "Profile written to: {path }" ) ;
eprintln ! ( "View this profile at https://profiler.firefox.com/." ) ;
eprintln ! ( "View this profile at https://profiler.firefox.com/." ) ;
}
}
} ) ;
} ) ;