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 std::collections::HashMap;
use std::path::PathBuf;
use wasmtime::{Config, ProfilingStrategy, Strategy};
use wasmtime::{Config, Strategy};
pub const SUPPORTED_WASM_FEATURES: &[(&str, &str)] = &[
("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))]
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)
/// Run optimization passes on translated functions, on by default
#[clap(short = 'O', long)]
@ -285,7 +281,6 @@ impl CommonOptions {
.cranelift_debug_verifier(self.enable_cranelift_debug_verifier)
.debug_info(self.debug_info)
.cranelift_opt_level(self.opt_level())
.profiler(self.profile.unwrap_or(ProfilingStrategy::None))
.cranelift_nan_canonicalization(self.enable_cranelift_nan_canonicalization);
self.enable_wasm_features(&mut config);

14
crates/wasmtime/src/config.rs

@ -1746,20 +1746,6 @@ pub enum ProfilingStrategy {
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.
#[derive(Debug, Clone, Copy)]
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()))
}
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());
/// Runs a WebAssembly module
@ -169,22 +191,27 @@ pub struct RunCommand {
)]
wasm_timeout: Option<Duration>,
/// Enable in-process sampling profiling of the guest WebAssembly program,
/// and write the captured profile to the given path. The resulting file
/// can be viewed using https://profiler.firefox.com/.
#[clap(long, value_name = "PATH")]
profile_guest: Option<PathBuf>,
/// Sampling interval for in-process profiling with `--profile-guest`. When
/// used together with `--wasm-timeout`, the timeout will be rounded up to
/// the nearest multiple of this interval.
/// Profiling strategy (valid options are: perfmap, jitdump, vtune, guest)
///
/// The perfmap, jitdump, and vtune profiling strategies integrate Wasmtime
/// with external profilers such as `perf`. The guest profiling strategy
/// enables in-process sampling and will write the captured profile to
/// `wasmtime-guest-profile.json` by default which can be viewed at
/// https://profiler.firefox.com/.
///
/// 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(
long,
default_value = "10ms",
value_name = "TIME",
parse(try_from_str = parse_dur),
value_name = "STRATEGY",
parse(try_from_str = parse_profile),
)]
profile_guest_interval: Duration,
profile: Option<Profile>,
/// Enable coredump generation after a WebAssembly trap.
#[clap(long = "coredump-on-trap", value_name = "PATH")]
@ -228,6 +255,11 @@ pub struct RunCommand {
trap_on_grow_failure: bool,
}
enum Profile {
Native(wasmtime::ProfilingStrategy),
Guest { path: String, interval: Duration },
}
impl RunCommand {
/// Executes the command.
pub fn execute(&self) -> Result<()> {
@ -235,9 +267,19 @@ impl RunCommand {
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);
}
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)?;
@ -398,8 +440,8 @@ impl RunCommand {
module_name: &str,
modules: Vec<(String, Module)>,
) -> Box<dyn FnOnce(&mut Store<Host>)> {
if let Some(path) = &self.profile_guest {
let interval = self.profile_guest_interval;
if let Some(Profile::Guest { path, interval }) = &self.profile {
let interval = *interval;
store.data_mut().guest_profiler =
Some(Arc::new(GuestProfiler::new(module_name, interval, modules)));
@ -449,10 +491,10 @@ impl RunCommand {
.map_err(anyhow::Error::new)
.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 {
eprintln!();
eprintln!("Profile written to: {}", path.display());
eprintln!("Profile written to: {path}");
eprintln!("View this profile at https://profiler.firefox.com/.");
}
});

Loading…
Cancel
Save