Browse Source

Fold guest profiling flags into `--profile` CLI option (#6362)

* Fold guest profiling flags into `--profile` CLI option

This commit removes the `--profile-guest` and `--profile-guest-interval`
CLI flags and folds them into the preexisting `--profile` flag.
Specifying guest profiling can now be done with `--profile guest` which
has a default path/interval to write to. The path/interval can be
configured with `--profile guest,path.json` and `--profile
guest,path.json,10ms`.

* Update src/commands/run.rs

Co-authored-by: Nick Fitzgerald <fitzgen@gmail.com>

---------

Co-authored-by: Nick Fitzgerald <fitzgen@gmail.com>
pull/6337/head
Alex Crichton 2 years ago
committed by GitHub
parent
commit
445f05c728
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      crates/cli-flags/src/lib.rs
  2. 14
      crates/wasmtime/src/config.rs
  3. 78
      src/commands/run.rs

7
crates/cli-flags/src/lib.rs

@ -20,7 +20,7 @@ use anyhow::{bail, Result};
use clap::Parser; use clap::Parser;
use std::collections::HashMap; use std::collections::HashMap;
use std::path::PathBuf; use std::path::PathBuf;
use wasmtime::{Config, ProfilingStrategy, Strategy}; use wasmtime::{Config, Strategy};
pub const SUPPORTED_WASM_FEATURES: &[(&str, &str)] = &[ pub const SUPPORTED_WASM_FEATURES: &[(&str, &str)] = &[
("all", "enables all supported WebAssembly features"), ("all", "enables all supported WebAssembly features"),
@ -134,10 +134,6 @@ pub struct CommonOptions {
#[clap(long, value_name = "MODULE,MODULE,...", parse(try_from_str = parse_wasi_modules))] #[clap(long, value_name = "MODULE,MODULE,...", parse(try_from_str = parse_wasi_modules))]
pub wasi_modules: Option<WasiModules>, pub wasi_modules: Option<WasiModules>,
/// Profiling strategy (valid options are: perfmap, jitdump, vtune)
#[clap(long)]
pub profile: Option<ProfilingStrategy>,
/// Generate jitdump file (supported on --features=profiling build) /// Generate jitdump file (supported on --features=profiling build)
/// Run optimization passes on translated functions, on by default /// Run optimization passes on translated functions, on by default
#[clap(short = 'O', long)] #[clap(short = 'O', long)]
@ -285,7 +281,6 @@ impl CommonOptions {
.cranelift_debug_verifier(self.enable_cranelift_debug_verifier) .cranelift_debug_verifier(self.enable_cranelift_debug_verifier)
.debug_info(self.debug_info) .debug_info(self.debug_info)
.cranelift_opt_level(self.opt_level()) .cranelift_opt_level(self.opt_level())
.profiler(self.profile.unwrap_or(ProfilingStrategy::None))
.cranelift_nan_canonicalization(self.enable_cranelift_nan_canonicalization); .cranelift_nan_canonicalization(self.enable_cranelift_nan_canonicalization);
self.enable_wasm_features(&mut config); self.enable_wasm_features(&mut config);

14
crates/wasmtime/src/config.rs

@ -1746,20 +1746,6 @@ pub enum ProfilingStrategy {
VTune, VTune,
} }
impl FromStr for ProfilingStrategy {
type Err = anyhow::Error;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
match s {
"none" => Ok(Self::None),
"perfmap" => Ok(Self::PerfMap),
"jitdump" => Ok(Self::JitDump),
"vtune" => Ok(Self::VTune),
_ => anyhow::bail!("unknown value for profiling strategy"),
}
}
}
/// Select how wasm backtrace detailed information is handled. /// Select how wasm backtrace detailed information is handled.
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum WasmBacktraceDetails { pub enum WasmBacktraceDetails {

78
src/commands/run.rs

@ -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/.");
} }
}); });

Loading…
Cancel
Save