bench: add more WASI benchmarks (#5309)
* bench: add more WASI benchmarks This follows up on #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 #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. * fix: reduce expected size of directory entries
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
//! Measure some common WASI call scenarios.
|
//! Measure some common WASI call scenarios.
|
||||||
|
|
||||||
use criterion::{criterion_group, criterion_main, Criterion};
|
use criterion::{criterion_group, criterion_main, Criterion};
|
||||||
use std::time::Instant;
|
use std::{fs::File, path::Path, time::Instant};
|
||||||
use wasmtime::{Engine, Linker, Module, Store, TypedFunc};
|
use wasmtime::{Engine, Linker, Module, Store, TypedFunc};
|
||||||
use wasmtime_wasi::{sync::WasiCtxBuilder, WasiCtx};
|
use wasmtime_wasi::{sync::WasiCtxBuilder, WasiCtx};
|
||||||
|
|
||||||
@@ -9,6 +9,15 @@ criterion_group!(benches, bench_wasi);
|
|||||||
criterion_main!(benches);
|
criterion_main!(benches);
|
||||||
|
|
||||||
fn bench_wasi(c: &mut Criterion) {
|
fn bench_wasi(c: &mut Criterion) {
|
||||||
|
let _ = env_logger::try_init();
|
||||||
|
|
||||||
|
// Build a zero-filled test file if it does not yet exist.
|
||||||
|
let test_file = Path::new("benches/wasi/test.bin");
|
||||||
|
if !test_file.is_file() {
|
||||||
|
let file = File::create(test_file).unwrap();
|
||||||
|
file.set_len(4096).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
// Benchmark each `*.wat` file in the `wasi` directory.
|
// Benchmark each `*.wat` file in the `wasi` directory.
|
||||||
for file in std::fs::read_dir("benches/wasi").unwrap() {
|
for file in std::fs::read_dir("benches/wasi").unwrap() {
|
||||||
let path = file.unwrap().path();
|
let path = file.unwrap().path();
|
||||||
@@ -67,5 +76,11 @@ fn wasi_context() -> WasiCtx {
|
|||||||
"--flag4".to_string(),
|
"--flag4".to_string(),
|
||||||
])
|
])
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
.preopened_dir(
|
||||||
|
wasmtime_wasi::Dir::open_ambient_dir("benches/wasi", wasmtime_wasi::ambient_authority())
|
||||||
|
.unwrap(),
|
||||||
|
"/",
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|||||||
1
benches/wasi/.gitignore
vendored
Normal file
1
benches/wasi/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
test.bin
|
||||||
53
benches/wasi/open-file.wat
Normal file
53
benches/wasi/open-file.wat
Normal file
@@ -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)
|
||||||
|
)
|
||||||
41
benches/wasi/read-dir.wat
Normal file
41
benches/wasi/read-dir.wat
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
;; 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 at least 380 bytes of directory
|
||||||
|
;; entries.
|
||||||
|
(if (i32.lt_u (i32.load (i32.const 8)) (i32.const 300))
|
||||||
|
(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
benches/wasi/read-file.wat
Normal file
78
benches/wasi/read-file.wat
Normal file
@@ -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)
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user