Skip to content

Commit

Permalink
bench: add more WASI benchmarks
Browse files Browse the repository at this point in the history
This follows up on bytecodealliance#5274 to add several more scenarios with which to
benchmark WASI performance:
- `open-file.wat`: opens and closes a file
- `read-file.wat`: opens a file, reads 4K bytes from it, then closes it
- `read-dir.wat`: reads a directory's entries

Each benchmark is hand-crafted WAT to more clearly control what WASI
calls are made. As with bytecodealliance#5274, these modules' sole entry point takes a
parameter indicating the number of iterations to run in order to use
`criterion`'s `iter_custom` feature.
  • Loading branch information
abrown committed Nov 21, 2022
1 parent c74706a commit afe206f
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 1 deletion.
34 changes: 33 additions & 1 deletion benches/wasi.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
//! Measure some common WASI call scenarios.

use criterion::{criterion_group, criterion_main, Criterion};
use std::time::Instant;
use std::{
fs::File,
path::{Path, PathBuf},
time::Instant,
};
use wasmtime::{Engine, Linker, Module, Store, TypedFunc};
use wasmtime_wasi::{sync::WasiCtxBuilder, WasiCtx};

criterion_group!(benches, bench_wasi);
criterion_main!(benches);

fn bench_wasi(c: &mut Criterion) {
let _ = env_logger::try_init();

let test_file = Path::new("benches/wasi/test.bin");
if !test_file.is_file() {
fill_file_with_zeroes(test_file, 4096);
}

// Benchmark each `*.wat` file in the `wasi` directory.
for file in std::fs::read_dir("benches/wasi").unwrap() {
let path = file.unwrap().path();
Expand Down Expand Up @@ -67,5 +78,26 @@ fn wasi_context() -> WasiCtx {
"--flag4".to_string(),
])
.unwrap()
.preopened_dir(
wasmtime_wasi::Dir::open_ambient_dir(
get_fixture_directory(),
wasmtime_wasi::ambient_authority(),
)
.unwrap(),
"/fixtures",
)
.unwrap()
.build()
}

fn get_fixture_directory() -> PathBuf {
let mut dir = PathBuf::from(file!());
dir.pop();
dir.push("wasi");
dir
}

fn fill_file_with_zeroes(path: &Path, num_bytes: usize) {
let file = File::create(path).unwrap();
file.set_len(num_bytes.try_into().unwrap()).unwrap()
}
1 change: 1 addition & 0 deletions benches/wasi/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test.bin
53 changes: 53 additions & 0 deletions benches/wasi/open-file.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
;; Repeatedly open and close `test.bin`.
(module
(import "wasi_snapshot_preview1" "path_open"
(func $__wasi_path_open (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32)))
(import "wasi_snapshot_preview1" "fd_read"
(func $__wasi_fd_read (param i32 i32 i32 i32) (result i32)))
(import "wasi_snapshot_preview1" "fd_close"
(func $__wasi_fd_close (param i32) (result i32)))
(func (export "run") (param $iters i64) (result i64)
(local $i i64)
(local.set $i (i64.const 0))
(loop $cont
;; Open the file `test.bin` under the same directory as this WAT
;; file; this assumes some prior set up of the preopens in
;; `wasi.rs`. See https://github.com/WebAssembly/WASI/blob/d8da230b/phases/snapshot/witx/wasi_snapshot_preview1.witx#L346.
(call $__wasi_path_open
;; The fd of the preopen under which to search for the file;
;; the first three are the `std*` ones.
(i32.const 3)
;; The lookup flags (i.e., whether to follow symlinks).
(i32.const 0)
;; The path to the file under the initial fd.
(i32.const 0)
(i32.const 8)
;; The open flags; in this case we will only attempt to read but
;; this may attempt to create the file if it does not exist, see
;; https://github.com/WebAssembly/WASI/blob/d8da230b/phases/snapshot/witxtypenames.witx#L444).
(i32.const 0)
;; The base rights and the inheriting rights: here we only set
;; the bits for the FD_READ and FD_READDIR capabilities.
(i64.const 0x2002)
(i64.const 0x2002)
;; The file descriptor flags (e.g., whether to append, sync,
;; etc.); see https://github.com/WebAssembly/WASI/blob/d8da230b/phases/snapshot/witx/typenames.witx#L385
(i32.const 0)
;; The address at which to store the opened fd (if the call
;; succeeds)
(i32.const 16))
(if (then unreachable))

;; Close the open file handle we stored at offset 16.
(call $__wasi_fd_close (i32.load (i32.const 16)))
(if (then unreachable))

;; Continue looping until $i reaches $iters.
(local.set $i (i64.add (local.get $i) (i64.const 1)))
(br_if $cont (i64.lt_u (local.get $i) (local.get $iters)))
)
(local.get $i)
)
(data (i32.const 0) "test.bin")
(memory (export "memory") 1)
)
40 changes: 40 additions & 0 deletions benches/wasi/read-dir.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
;; Read the directory entries of the preopened directory.
(module
(import "wasi_snapshot_preview1" "fd_readdir"
(func $__wasi_fd_readdir (param i32 i32 i32 i64 i32) (result i32)))
(func (export "run") (param $iters i64) (result i64)
(local $i i64)
(local.set $i (i64.const 0))

(if (i32.ne (i32.load (i32.const 0)) (i32.const 0))
(then unreachable))

(loop $cont
;; Read the file into the sole iovec buffer.
(call $__wasi_fd_readdir
;; The fd of the preopened directory; the first three are the
;; `std*` ones.
(i32.const 3)
;; The buffer address at which to store the entries and the
;; length of the buffer.
(i32.const 16)
(i32.const 4096)
;; The location at which to start reading entries in the
;; directory; here we start at the first entry.
(i64.const 0)
;; The address at which to store the number of bytes read.
(i32.const 8))
(drop)

;; Check that we indeed read 380 bytes of directory entries.
(if (i32.lt_u (i32.load (i32.const 8)) (i32.const 380))
(then unreachable))

;; Continue looping until $i reaches $iters.
(local.set $i (i64.add (local.get $i) (i64.const 1)))
(br_if $cont (i64.lt_u (local.get $i) (local.get $iters)))
)
(local.get $i)
)
(memory (export "memory") 1)
)
78 changes: 78 additions & 0 deletions benches/wasi/read-file.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
;; Repeatedly read the contents of `test.bin`.
(module
(import "wasi_snapshot_preview1" "path_open"
(func $__wasi_path_open (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32)))
(import "wasi_snapshot_preview1" "fd_read"
(func $__wasi_fd_read (param i32 i32 i32 i32) (result i32)))
(import "wasi_snapshot_preview1" "fd_close"
(func $__wasi_fd_close (param i32) (result i32)))
(func (export "run") (param $iters i64) (result i64)
(local $i i64)
(local.set $i (i64.const 0))

;; Set up the iovec list; the memory usage for this module should be:
;; - offset 0 => file name
;; - offset 16 => the opened file descriptor
;; - offset 24 => the number of read bytes
;; - offset 32 => the iovec list
;; - offset 48 => the first (and only) iovec buffer
(i32.store (i32.const 32) (i32.const 48))
(i32.store (i32.const 36) (i32.const 4096))

(loop $cont
;; Open the file `test.bin` under the same directory as this WAT
;; file; this assumes some prior set up of the preopens in
;; `wasi.rs`. See https://github.com/WebAssembly/WASI/blob/d8da230b/phases/snapshot/witx/wasi_snapshot_preview1.witx#L346.
(call $__wasi_path_open
;; The fd of the preopen under which to search for the file;
;; the first three are the `std*` ones.
(i32.const 3)
;; The lookup flags (i.e., whether to follow symlinks).
(i32.const 0)
;; The path to the file under the initial fd.
(i32.const 0)
(i32.const 8)
;; The open flags; in this case we will only attempt to read but
;; this may attempt to create the file if it does not exist, see
;; https://github.com/WebAssembly/WASI/blob/d8da230b/phases/snapshot/witxtypenames.witx#L444).
(i32.const 0)
;; The base rights and the inheriting rights: here we only set
;; the bits for the FD_READ and FD_READDIR capabilities.
(i64.const 0x2002)
(i64.const 0x2002)
;; The file descriptor flags (e.g., whether to append, sync,
;; etc.); see https://github.com/WebAssembly/WASI/blob/d8da230b/phases/snapshot/witx/typenames.witx#L385
(i32.const 0)
;; The address at which to store the opened fd (if the call
;; succeeds)
(i32.const 16))
(if (then unreachable))

;; Read the file into the sole iovec buffer.
(call $__wasi_fd_read
;; The now-open fd stored at offset 16.
(i32.load (i32.const 16))
;; The address and size of the list of iovecs; here we only use
;; a list of a single iovec set up outside the loop.
(i32.const 32)
(i32.const 1)
;; The address at which to store the number of bytes read.
(i32.const 24))
(if (then unreachable))
;; Check that we indeed read 4096 bytes.
(if (i32.ne (i32.load (i32.const 24)) (i32.const 4096))
(then unreachable))

;; Close the open file handle we stored at offset 16.
(call $__wasi_fd_close (i32.load (i32.const 16)))
(if (then unreachable))

;; Continue looping until $i reaches $iters.
(local.set $i (i64.add (local.get $i) (i64.const 1)))
(br_if $cont (i64.lt_u (local.get $i) (local.get $iters)))
)
(local.get $i)
)
(data (i32.const 0) "test.bin")
(memory (export "memory") 1)
)

0 comments on commit afe206f

Please sign in to comment.