Skip to content

Commit d1c1cb6

Browse files
fitzgenabrown
authored andcommitted
bench-api: receive working directory as an argument
Rather than implicitly use the current working directory.
1 parent be1ac15 commit d1c1cb6

1 file changed

Lines changed: 68 additions & 42 deletions

File tree

crates/bench-api/src/lib.rs

Lines changed: 68 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,16 @@
2121
//! # Example
2222
//!
2323
//! ```
24+
//! use std::ptr;
2425
//! use wasmtime_bench_api::*;
2526
//!
26-
//! let engine = unsafe { wasm_bench_create() };
27-
//! assert!(!engine.is_null());
27+
//! let working_dir = std::env::current_dir().unwrap().display().to_string();
28+
//! let mut bench_api = ptr::null_mut();
29+
//! unsafe {
30+
//! let code = wasm_bench_create(working_dir.as_ptr(), working_dir.len(), &mut bench_api);
31+
//! assert_eq!(code, OK);
32+
//! assert!(!bench_api.is_null());
33+
//! };
2834
//!
2935
//! let wasm = wat::parse_bytes(br#"
3036
//! (module
@@ -42,7 +48,7 @@
4248
//! "#).unwrap();
4349
//!
4450
//! // Start your compilation timer here.
45-
//! let code = unsafe { wasm_bench_compile(engine, wasm.as_ptr(), wasm.len()) };
51+
//! let code = unsafe { wasm_bench_compile(bench_api, wasm.as_ptr(), wasm.len()) };
4652
//! // End your compilation timer here.
4753
//! assert_eq!(code, OK);
4854
//!
@@ -57,24 +63,25 @@
5763
//! }
5864
//!
5965
//! // Start your instantiation timer here.
60-
//! let code = unsafe { wasm_bench_instantiate(engine, bench_start, bench_stop) };
66+
//! let code = unsafe { wasm_bench_instantiate(bench_api, bench_start, bench_stop) };
6167
//! // End your instantiation timer here.
6268
//! assert_eq!(code, OK);
6369
//!
6470
//! // No need to start timers for the execution since, by convention, the timer
6571
//! // functions we passed during instantiation will be called by the benchmark
6672
//! // at the appropriate time (before and after the benchmarked section).
67-
//! let code = unsafe { wasm_bench_execute(engine) };
73+
//! let code = unsafe { wasm_bench_execute(bench_api) };
6874
//! assert_eq!(code, OK);
6975
//!
7076
//! unsafe {
71-
//! wasm_bench_free(engine);
77+
//! wasm_bench_free(bench_api);
7278
//! }
7379
//! ```
7480
7581
use anyhow::{anyhow, Context, Result};
7682
use std::env;
7783
use std::os::raw::{c_int, c_void};
84+
use std::path::Path;
7885
use std::slice;
7986
use wasi_common::WasiCtxBuilder;
8087
use wasmtime::{Config, Engine, Instance, Linker, Module, Store};
@@ -95,12 +102,32 @@ static ALLOC: shuffling_allocator::ShufflingAllocator<std::alloc::System> =
95102
/// Exposes a C-compatible way of creating the engine from the bytes of a single
96103
/// Wasm module.
97104
///
98-
/// This function returns a pointer to a structure that contains the engine's
99-
/// initialized state.
105+
/// On success, the `out_bench_ptr` is initialized to a pointer to a structure
106+
/// that contains the engine's initialized state, and `0` is returned. On
107+
/// failure, a non-zero status code is returned and `out_bench_ptr` is left
108+
/// untouched.
100109
#[no_mangle]
101-
pub extern "C" fn wasm_bench_create() -> *mut c_void {
102-
let state = Box::new(BenchState::new());
103-
Box::into_raw(state) as _
110+
pub extern "C" fn wasm_bench_create(
111+
working_dir_ptr: *const u8,
112+
working_dir_len: usize,
113+
out_bench_ptr: *mut *mut c_void,
114+
) -> ExitCode {
115+
let result = (|| -> Result<_> {
116+
let working_dir = unsafe { std::slice::from_raw_parts(working_dir_ptr, working_dir_len) };
117+
let working_dir = std::str::from_utf8(working_dir)
118+
.context("given working directory is not valid UTF-8")?;
119+
let state = Box::new(BenchState::new(working_dir)?);
120+
Ok(Box::into_raw(state) as _)
121+
})();
122+
123+
if let Ok(bench_ptr) = result {
124+
unsafe {
125+
assert!(!out_bench_ptr.is_null());
126+
*out_bench_ptr = bench_ptr;
127+
}
128+
}
129+
130+
to_exit_code(result.map(|_| ()))
104131
}
105132

106133
/// Free the engine state allocated by this library.
@@ -164,27 +191,49 @@ fn to_exit_code<T>(result: impl Into<Result<T>>) -> ExitCode {
164191
/// to manage the Wasmtime engine between calls.
165192
struct BenchState {
166193
engine: Engine,
167-
store: Store,
194+
linker: Linker,
168195
module: Option<Module>,
169196
instance: Option<Instance>,
170197
did_execute: bool,
171198
}
172199

173200
impl BenchState {
174-
fn new() -> Self {
201+
fn new(working_dir: impl AsRef<Path>) -> Result<Self> {
175202
let mut config = Config::new();
176203
config.wasm_simd(true);
177204
// NB: do not configure a code cache.
178205

179206
let engine = Engine::new(&config);
180207
let store = Store::new(&engine);
181-
Self {
208+
209+
let mut linker = Linker::new(&store);
210+
211+
// Create a WASI environment.
212+
213+
let mut cx = WasiCtxBuilder::new();
214+
cx.inherit_stdio();
215+
// Allow access to the working directory so that the benchmark can read
216+
// its input workload(s).
217+
let working_dir = wasi_common::preopen_dir(working_dir)
218+
.context("failed to preopen the working directory")?;
219+
cx.preopened_dir(working_dir, ".");
220+
// Pass this env var along so that the benchmark program can use smaller
221+
// input workload(s) if it has them and that has been requested.
222+
if let Ok(val) = env::var("WASM_BENCH_USE_SMALL_WORKLOAD") {
223+
cx.env("WASM_BENCH_USE_SMALL_WORKLOAD", &val);
224+
}
225+
226+
let cx = cx.build()?;
227+
let wasi = Wasi::new(&store, cx);
228+
wasi.add_to_linker(&mut linker)?;
229+
230+
Ok(Self {
182231
engine,
183-
store,
232+
linker,
184233
module: None,
185234
instance: None,
186235
did_execute: false,
187-
}
236+
})
188237
}
189238

190239
fn compile(&mut self, bytes: &[u8]) -> Result<()> {
@@ -210,34 +259,11 @@ impl BenchState {
210259
.as_mut()
211260
.expect("compile the module before instantiating it");
212261

213-
let mut linker = Linker::new(&self.store);
214-
215-
// Create a WASI environment.
216-
217-
let mut cx = WasiCtxBuilder::new();
218-
cx.inherit_stdio();
219-
// Allow access to the current working directory so that the benchmark
220-
// can read its input workload(s). The sightglass benchmark runner will
221-
// make sure that this process is spawned with its current directory set
222-
// to the current benchmark's directory.
223-
let cwd = wasi_common::preopen_dir(".")
224-
.context("failed to open the current working directory")?;
225-
cx.preopened_dir(cwd, ".");
226-
// Pass this env var along so that the benchmark program can use smaller
227-
// input workload(s) if it has them and that has been requested.
228-
if let Ok(val) = env::var("WASM_BENCH_USE_SMALL_WORKLOAD") {
229-
cx.env("WASM_BENCH_USE_SMALL_WORKLOAD", &val);
230-
}
231-
232-
let cx = cx.build()?;
233-
let wasi = Wasi::new(linker.store(), cx);
234-
wasi.add_to_linker(&mut linker)?;
235-
236262
// Import the specialized benchmarking functions.
237-
linker.func("bench", "start", move || bench_start())?;
238-
linker.func("bench", "end", move || bench_end())?;
263+
self.linker.func("bench", "start", move || bench_start())?;
264+
self.linker.func("bench", "end", move || bench_end())?;
239265

240-
self.instance = Some(linker.instantiate(&module)?);
266+
self.instance = Some(self.linker.instantiate(&module)?);
241267
Ok(())
242268
}
243269

0 commit comments

Comments
 (0)