Skip to content

Commit

Permalink
extend wastime demo to support wasi32-wasi
Browse files Browse the repository at this point in the history
To support wasi, the PR start to the "wasi_snapshot_preview1".
Cuurently, only the basic functions are supported, which are
needed to run the fibonacci example.

In addition, the fibonacci example is converted from a library
to a common application.
  • Loading branch information
stlankes committed Jun 30, 2024
1 parent d99c4ac commit 956a894
Show file tree
Hide file tree
Showing 9 changed files with 278 additions and 124 deletions.
8 changes: 6 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ jobs:
with:
components: rust-src
- uses: mkroening/rust-toolchain-toml@main
- run: rustup component add clippy llvm-tools
- run: |
rustup component add clippy llvm-tools
rustup target add wasm32-wasi
- name: Clippy
run: |
cargo clippy --all-targets
Expand Down Expand Up @@ -50,7 +52,9 @@ jobs:
with:
components: rust-src
- uses: mkroening/rust-toolchain-toml@main
- run: rustup component add llvm-tools
- run: |
rustup component add llvm-tools
rustup target add wasi32-wasm
- name: Check docs
run: cargo doc --no-deps --document-private-items

Expand Down
6 changes: 2 additions & 4 deletions examples/fibonacci/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ version = "0.1.0"
authors = ["Stefan Lankes <[email protected]>"]
edition = "2021"

[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
[target.'cfg(target_os = "hermit")'.dependencies]
hermit = { path = "../../hermit", default-features = false, features = ["acpi", "pci"] }

37 changes: 0 additions & 37 deletions examples/fibonacci/src/lib.rs

This file was deleted.

44 changes: 44 additions & 0 deletions examples/fibonacci/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use std::hint::black_box;
use std::time::Instant;

#[cfg(target_os = "hermit")]
use hermit as _;

// Number of iteration to stress the benchmark
const N: u64 = 1000000;

// Calculating fibonacci numbers
fn fibonacci(n: u64) -> u64 {
let mut fib: u64 = 1;
let mut fib1: u64 = 1;
let mut fib2: u64 = 1;

for _ in 3..=n {
fib = fib1 + fib2;
fib1 = fib2;
fib2 = fib;
}

fib
}

pub fn main() {
println!("Call function fibonacci");
let result = fibonacci(30);
println!("fibonacci(30) = {}", result);
assert!(
result == 832040,
"Error in the calculation of fibonacci(30) "
);

let now = Instant::now();
for _ in 0..N {
black_box(fibonacci(black_box(30)));
}
let elapsed = now.elapsed();
println!(
"Time to call {} times native_fibonacci(30): {} s",
N,
elapsed.as_secs_f32()
);
}
6 changes: 4 additions & 2 deletions examples/wasmtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ anyhow = "1.0"
bitflags = "2.5"
cfg-if = "1"
log = { version = "0.4" } #, features = ["kv_unstable"]}
simple_logger = { version = "5.0", default-features = false, features = ["nightly"]}
wasmtime = { version = "22.0", default-features = false, features = ["std", "runtime", "cranelift", "threads", "gc", "component-model"] }
simple_logger = { version = "5.0", default-features = false }
wasmtime = { version = "22.0", default-features = false, features = ["std", "runtime", "cranelift", "threads"] } #, "gc", "component-model"] }
zerocopy = { version = "0.7" }

[target.'cfg(target_os = "hermit")'.dependencies]
hermit = { path = "../../hermit", default-features = false, features = ["smp", "acpi", "pci", "fsgsbase", "fs", "tcp", "dhcpv4", "mmap"] }
hermit-abi = { path = "../../hermit-abi", default-features = false }
hermit-sync = { version = "0.1" }
2 changes: 1 addition & 1 deletion examples/wasmtime/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ fn main() -> io::Result<()> {
.arg("build")
.arg("-Zunstable-options")
.arg("-Zbuild-std=std,panic_abort")
.arg("--target=wasm32-unknown-unknown")
.arg("--target=wasm32-wasi")
.arg("--package=fibonacci")
.arg("--release")
.arg("--out-dir")
Expand Down
2 changes: 1 addition & 1 deletion examples/wasmtime/src/capi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ pub extern "C" fn wasmtime_memory_image_map_at(
_len: usize,
) -> i32 {
error!("Currently. HermitOS doesn't support wasmtime_memory_image_map_at!");
-hermit_abi::ENOSYS
hermit_abi::ENOSYS
}

/// Deallocates the provided `wasmtime_memory_image`.
Expand Down
111 changes: 34 additions & 77 deletions examples/wasmtime/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
#![feature(duration_millis_float)]
#![allow(dependency_on_unit_never_type_fallback)]

use std::hint::black_box;
use std::time::{Instant, SystemTime};
use std::time::Instant;

use anyhow::Result;
use anyhow::{Context, Result};
#[cfg(target_os = "hermit")]
use hermit as _;
use log::{debug, info};
Expand All @@ -15,27 +14,11 @@ use wasmtime::*;
mod arch;
#[cfg(target_os = "hermit")]
mod capi;
#[cfg(target_os = "hermit")]
mod preview1;

// Number of iteration to stress the benchmark
const N: u64 = 1000000;

#[inline(never)]
pub fn native_fibonacci(n: u64) -> u64 {
let mut fib: u64 = 1;
let mut fib1: u64 = 1;
let mut fib2: u64 = 1;

for _ in 3..=n {
fib = fib1 + fib2;
fib1 = fib2;
fib2 = fib;
}

fib
}

fn main() -> Result<()> {
simple_logger::init_with_level(log::Level::Info).unwrap();
pub fn main() -> Result<()> {
simple_logger::init_with_level(log::Level::Info)?;

println!("Start Wasmtime demo!");

Expand All @@ -53,79 +36,53 @@ fn main() -> Result<()> {
let now = Instant::now();
let module = Module::new(&engine, &module_bytes[..])?;
let elapsed = now.elapsed();
println!("Time to create mdoule: {} msec", elapsed.as_millis());
println!("Time to create module: {} msec", elapsed.as_millis());

let imports = module.imports();
/*let imports = module.imports();
for i in imports {
info!("import from module `{}` symbol `{}`", i.module(), i.name());
}
let exports = module.exports();
for i in exports {
info!("exports symbol `{}`", i.name());
}*/

debug!("Create Linker");
#[allow(unused_mut)]
let mut linker = Linker::new(&engine);

// In case WASI, it is required to emulate
// https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md

linker.func_wrap("env", "now", || {
match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
Ok(n) => n.as_millis_f64(),
Err(_) => panic!("SystemTime before UNIX EPOCH!"),
#[cfg(target_os = "hermit")]
{
let mut imports = module.imports();
if imports.any(|i| i.module() == "wasi_snapshot_preview1") {
preview1::init(&mut linker)?;
}
})?;
linker.func_wrap("env", "exit", || panic!("Panic in WASM module"))?;
}

// All wasm objects operate within the context of a "store". Each
// `Store` has a type parameter to store host-specific data, which in
// this case we're using `4` for.
let mut store = Store::new(&engine, 4);
let instance = linker.instantiate(&mut store, &module)?;

debug!("Try to find function fibonacci");
let fibonacci = instance.get_typed_func::<u64, u64>(&mut store, "fibonacci")?;
debug!("Try to find symbol _start");
let func = instance.get_func(&mut store, "_start").unwrap();

// And finally we can call the wasm!
debug!("Call function fibonacci");
let result = fibonacci.call(&mut store, 30)?;
println!("fibonacci(30) = {}", result);
assert!(
result == 832040,
"Error in the calculation of fibonacci(30) "
);

let now = Instant::now();
for _ in 0..N {
let _result = black_box(fibonacci.call(&mut store, black_box(30)))?;
let ty = func.ty(&store);
if ty.params().len() > 0 {
panic!("Currently, _start should not receive arguments");
}
let elapsed = now.elapsed();
println!(
"Time to call {} times fibonacci(30): {} usec",
N,
elapsed.as_micros()
);

let now = Instant::now();
for _ in 0..N {
let _result = black_box(native_fibonacci(black_box(30)));
}
let elapsed = now.elapsed();
println!(
"Time to call {} times native_fibonacci(30): {} usec",
N,
elapsed.as_micros()
);

let bench = instance.get_typed_func::<(u64, u64), f64>(&mut store, "bench")?;
let msec = bench.call(&mut store, (N, 30))?;
println!("Benchmark takes {} usec", msec * 1000.0f64);

let function_foo = instance.get_typed_func::<(), ()>(&mut store, "foo")?;
function_foo.call(&mut store, ())?;
let now = Instant::now();
for _ in 0..N {
function_foo.call(&mut store, ())?;
}
let elapsed = now.elapsed();
println!("Time to call {} times foo: {} usec", N, elapsed.as_micros());
// Invoke the function and then afterwards print all the results that came
// out, if there are any.
let mut results = vec![Val::null_func_ref(); ty.results().len()];
let values = Vec::new();
let invoke_res = func
.call(&mut store, &values, &mut results)
.with_context(|| "failed to invoke command default".to_string());

info!("Return value of entry point: {:?}", invoke_res);

Ok(())
}
Loading

0 comments on commit 956a894

Please sign in to comment.