Browse Source

bench-api: Pass in explicit stdin/stdout/stderr

Instead of inheriting stdio, pass in explicit file paths that are opened for
reading (stdin) or writing (stderr/stdout). This will allow sightglass to assert
that benchmarks produce the expected output.
pull/2937/head
Nick Fitzgerald 4 years ago
parent
commit
ba6635dba0
  1. 2
      crates/bench-api/.gitignore
  2. 122
      crates/bench-api/src/lib.rs

2
crates/bench-api/.gitignore

@ -0,0 +1,2 @@
stdout.log
stderr.log

122
crates/bench-api/src/lib.rs

@ -25,9 +25,23 @@
//! use wasmtime_bench_api::*; //! use wasmtime_bench_api::*;
//! //!
//! let working_dir = std::env::current_dir().unwrap().display().to_string(); //! let working_dir = std::env::current_dir().unwrap().display().to_string();
//! let stdout_path = "./stdout.log";
//! let stderr_path = "./stderr.log";
//!
//! let config = WasmBenchConfig {
//! working_dir_ptr: working_dir.as_ptr(),
//! working_dir_len: working_dir.len(),
//! stdout_path_ptr: stdout_path.as_ptr(),
//! stdout_path_len: stdout_path.len(),
//! stderr_path_ptr: stderr_path.as_ptr(),
//! stderr_path_len: stderr_path.len(),
//! stdin_path_ptr: ptr::null(),
//! stdin_path_len: 0,
//! };
//!
//! let mut bench_api = ptr::null_mut(); //! let mut bench_api = ptr::null_mut();
//! unsafe { //! unsafe {
//! let code = wasm_bench_create(working_dir.as_ptr(), working_dir.len(), &mut bench_api); //! let code = wasm_bench_create(config, &mut bench_api);
//! assert_eq!(code, OK); //! assert_eq!(code, OK);
//! assert!(!bench_api.is_null()); //! assert!(!bench_api.is_null());
//! }; //! };
@ -98,6 +112,65 @@ pub const ERR: ExitCode = -1;
static ALLOC: shuffling_allocator::ShufflingAllocator<std::alloc::System> = static ALLOC: shuffling_allocator::ShufflingAllocator<std::alloc::System> =
shuffling_allocator::wrap!(&std::alloc::System); shuffling_allocator::wrap!(&std::alloc::System);
/// Configuration options for the benchmark.
#[repr(C)]
pub struct WasmBenchConfig {
/// The working directory where benchmarks should be executed.
pub working_dir_ptr: *const u8,
pub working_dir_len: usize,
/// The file path that should be created and used as `stdout`.
pub stdout_path_ptr: *const u8,
pub stdout_path_len: usize,
/// The file path that should be created and used as `stderr`.
pub stderr_path_ptr: *const u8,
pub stderr_path_len: usize,
/// The (optional) file path that should be opened and used as `stdin`. If
/// not provided, then the WASI context will not have a `stdin` initialized.
pub stdin_path_ptr: *const u8,
pub stdin_path_len: usize,
}
impl WasmBenchConfig {
fn working_dir(&self) -> Result<&str> {
let working_dir =
unsafe { std::slice::from_raw_parts(self.working_dir_ptr, self.working_dir_len) };
let working_dir = std::str::from_utf8(working_dir)
.context("given working directory is not valid UTF-8")?;
Ok(working_dir)
}
fn stdout_path(&self) -> Result<&str> {
let stdout_path =
unsafe { std::slice::from_raw_parts(self.stdout_path_ptr, self.stdout_path_len) };
let stdout_path =
std::str::from_utf8(stdout_path).context("given stdout path is not valid UTF-8")?;
Ok(stdout_path)
}
fn stderr_path(&self) -> Result<&str> {
let stderr_path =
unsafe { std::slice::from_raw_parts(self.stderr_path_ptr, self.stderr_path_len) };
let stderr_path =
std::str::from_utf8(stderr_path).context("given stderr path is not valid UTF-8")?;
Ok(stderr_path)
}
fn stdin_path(&self) -> Result<Option<&str>> {
if self.stdin_path_ptr.is_null() {
return Ok(None);
}
let stdin_path =
unsafe { std::slice::from_raw_parts(self.stdin_path_ptr, self.stdin_path_len) };
let stdin_path =
std::str::from_utf8(stdin_path).context("given stdin path is not valid UTF-8")?;
Ok(Some(stdin_path))
}
}
/// Exposes a C-compatible way of creating the engine from the bytes of a single /// Exposes a C-compatible way of creating the engine from the bytes of a single
/// Wasm module. /// Wasm module.
/// ///
@ -107,15 +180,20 @@ static ALLOC: shuffling_allocator::ShufflingAllocator<std::alloc::System> =
/// untouched. /// untouched.
#[no_mangle] #[no_mangle]
pub extern "C" fn wasm_bench_create( pub extern "C" fn wasm_bench_create(
working_dir_ptr: *const u8, config: WasmBenchConfig,
working_dir_len: usize,
out_bench_ptr: *mut *mut c_void, out_bench_ptr: *mut *mut c_void,
) -> ExitCode { ) -> ExitCode {
let result = (|| -> Result<_> { let result = (|| -> Result<_> {
let working_dir = unsafe { std::slice::from_raw_parts(working_dir_ptr, working_dir_len) }; let working_dir = config.working_dir()?;
let working_dir = std::str::from_utf8(working_dir) let stdout_path = config.stdout_path()?;
.context("given working directory is not valid UTF-8")?; let stderr_path = config.stderr_path()?;
let state = Box::new(BenchState::new(working_dir)?); let stdin_path = config.stdin_path()?;
let state = Box::new(BenchState::new(
working_dir,
stdout_path,
stderr_path,
stdin_path,
)?);
Ok(Box::into_raw(state) as _) Ok(Box::into_raw(state) as _)
})(); })();
@ -197,7 +275,12 @@ struct BenchState {
} }
impl BenchState { impl BenchState {
fn new(working_dir: impl AsRef<Path>) -> Result<Self> { fn new(
working_dir: impl AsRef<Path>,
stdout: impl AsRef<Path>,
stderr: impl AsRef<Path>,
stdin: Option<impl AsRef<Path>>,
) -> Result<Self> {
let mut config = Config::new(); let mut config = Config::new();
config.wasm_simd(true); config.wasm_simd(true);
// NB: do not configure a code cache. // NB: do not configure a code cache.
@ -210,12 +293,33 @@ impl BenchState {
// Create a WASI environment. // Create a WASI environment.
let mut cx = WasiCtxBuilder::new(); let mut cx = WasiCtxBuilder::new();
cx = cx.inherit_stdio();
let stdout = std::fs::File::create(stdout.as_ref())
.with_context(|| format!("failed to create {}", stdout.as_ref().display()))?;
let stdout = unsafe { cap_std::fs::File::from_std(stdout) };
let stdout = wasi_cap_std_sync::file::File::from_cap_std(stdout);
cx = cx.stdout(Box::new(stdout));
let stderr = std::fs::File::create(stderr.as_ref())
.with_context(|| format!("failed to create {}", stderr.as_ref().display()))?;
let stderr = unsafe { cap_std::fs::File::from_std(stderr) };
let stderr = wasi_cap_std_sync::file::File::from_cap_std(stderr);
cx = cx.stderr(Box::new(stderr));
if let Some(stdin) = stdin {
let stdin = std::fs::File::open(stdin.as_ref())
.with_context(|| format!("failed to open {}", stdin.as_ref().display()))?;
let stdin = unsafe { cap_std::fs::File::from_std(stdin) };
let stdin = wasi_cap_std_sync::file::File::from_cap_std(stdin);
cx = cx.stdin(Box::new(stdin));
}
// Allow access to the working directory so that the benchmark can read // Allow access to the working directory so that the benchmark can read
// its input workload(s). // its input workload(s).
let working_dir = unsafe { cap_std::fs::Dir::open_ambient_dir(working_dir) } let working_dir = unsafe { cap_std::fs::Dir::open_ambient_dir(working_dir) }
.context("failed to preopen the working directory")?; .context("failed to preopen the working directory")?;
cx = cx.preopened_dir(working_dir, ".")?; cx = cx.preopened_dir(working_dir, ".")?;
// Pass this env var along so that the benchmark program can use smaller // Pass this env var along so that the benchmark program can use smaller
// input workload(s) if it has them and that has been requested. // input workload(s) if it has them and that has been requested.
if let Ok(val) = env::var("WASM_BENCH_USE_SMALL_WORKLOAD") { if let Ok(val) = env::var("WASM_BENCH_USE_SMALL_WORKLOAD") {

Loading…
Cancel
Save