diff --git a/.github/workflows/Benchmarks.yml b/.github/workflows/Benchmarks.yml index 8152bf77..57760cc2 100644 --- a/.github/workflows/Benchmarks.yml +++ b/.github/workflows/Benchmarks.yml @@ -40,7 +40,9 @@ jobs: - name: Build Wasm Runtime Binary working-directory: ./src/hyperlight_wasm - run: just build-wasm-runtime ${{ matrix.config }} + run: | + just ensure-tools + just build-wasm-runtime ${{ matrix.config }} - uses: dtolnay/rust-toolchain@1.89 with: diff --git a/.github/workflows/dep_rust.yml b/.github/workflows/dep_rust.yml index 9415c080..07d798eb 100644 --- a/.github/workflows/dep_rust.yml +++ b/.github/workflows/dep_rust.yml @@ -69,7 +69,9 @@ jobs: - name: Build Wasm Runtime Binary working-directory: ./src/hyperlight_wasm - run: just build-wasm-runtime ${{ matrix.config }} + run: | + just ensure-tools + just build-wasm-runtime ${{ matrix.config }} - name: Download Wasm Modules uses: actions/download-artifact@v5 @@ -81,7 +83,6 @@ jobs: run: | # this must be build before the formatting and other jobs run # because the component model example depends on the wasm component built here - just ensure-tools just compile-wit just build-rust-component-examples ${{ matrix.config }} diff --git a/Justfile b/Justfile index a844c8e6..e4d03f94 100644 --- a/Justfile +++ b/Justfile @@ -18,8 +18,9 @@ ensure-tools: cargo install wasm-tools --locked --version 1.235.0 cargo install cargo-component --locked --version 0.21.1 cargo install wit-bindgen-cli --locked --version 0.43.0 + cargo install --git https://github.com/hyperlight-dev/cargo-hyperlight cargo-hyperlight -build-all target=default-target features="": (build target features) (build-wasm-examples target features) (build-rust-wasm-examples target features) (build-rust-component-examples target) (build-wasm-runtime target features) +build-all target=default-target features="": (build target features) (build-examples target features) (build-wasm-runtime target features) build target=default-target features="": (fmt-check) cargo build {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F " + features } }} --verbose --profile={{ if target == "debug" {"dev"} else { target } }} @@ -33,9 +34,11 @@ compile-wit: wasm-tools component wit ./src/component_sample/wit/example.wit -w -o ./src/component_sample/wit/component-world.wasm build-wasm-runtime target=default-target features="": - cd ./src/wasm_runtime && cargo build --verbose {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--features " + features } }} --profile={{ if target == "debug" {"dev"} else { target } }} && rm -R target + cd ./src/wasm_runtime && cargo hyperlight build --verbose {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--features " + features } }} --profile={{ if target == "debug" {"dev"} else { target } }} && rm -R target -build-wasm-examples target=default-target features="": (compile-wit) +build-examples target=default-target features="": (build-wasm-examples target features) (build-rust-wasm-examples target features) (build-rust-component-examples target features) + +build-wasm-examples target=default-target features="": (compile-wit) {{ build-wasm-examples-command }} {{target}} {{features}} build-rust-wasm-examples target=default-target features="": (mkdir-redist target) @@ -54,7 +57,7 @@ check target=default-target: cargo check --profile={{ if target == "debug" {"dev"} else { target } }} cd src/rust_wasm_samples && cargo check --profile={{ if target == "debug" {"dev"} else { target } }} cd src/component_sample && cargo check --profile={{ if target == "debug" {"dev"} else { target } }} - cd src/wasm_runtime && cargo check --profile={{ if target == "debug" {"dev"} else { target } }} + cd src/wasm_runtime && cargo hyperlight check --profile={{ if target == "debug" {"dev"} else { target } }} cd src/hyperlight_wasm_macro && cargo check --profile={{ if target == "debug" {"dev"} else { target } }} fmt-check: @@ -79,7 +82,7 @@ clippy target=default-target: (check target) cargo clippy --profile={{ if target == "debug" {"dev"} else { target } }} --all-targets --all-features -- -D warnings cd src/rust_wasm_samples && cargo clippy --profile={{ if target == "debug" {"dev"} else { target } }} --all-targets --all-features -- -D warnings cd src/component_sample && cargo clippy --profile={{ if target == "debug" {"dev"} else { target } }} --all-targets --all-features -- -D warnings - cd src/wasm_runtime && cargo clippy --profile={{ if target == "debug" {"dev"} else { target } }} --all-targets --all-features -- -D warnings + cd src/wasm_runtime && cargo hyperlight clippy --profile={{ if target == "debug" {"dev"} else { target } }} --all-targets --all-features -- -D warnings cd src/hyperlight_wasm_macro && cargo clippy --profile={{ if target == "debug" {"dev"} else { target } }} --all-targets --all-features -- -D warnings # TESTING @@ -99,7 +102,8 @@ examples-ci target=default-target features="": (build-rust-wasm-examples target) cargo run {{ if features =="" {"--no-default-features --features kvm,mshv3"} else {"--no-default-features -F function_call_metrics," + features } }} --profile={{ if target == "debug" {"dev"} else { target } }} --example metrics examples-components target=default-target features="": (build-rust-component-examples target) - {{ wit-world }} cargo run {{ if features =="" {''} else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" {"dev"} else { target } }} --example component_example + {{ wit-world }} cargo run {{ if features =="" {''} else {"--no-default-features -F kvm -F " + features } }} --profile={{ if target == "debug" {"dev"} else { target } }} --example component_example + {{ wit-world-c }} cargo run {{ if features =="" {''} else {"--no-default-features -F kvm -F " + features } }} --profile={{ if target == "debug" {"dev"} else { target } }} --example c-component # warning, compares to and then OVERWRITES the given baseline bench-ci baseline target="release" features="": diff --git a/src/hyperlight_wasm/build.rs b/src/hyperlight_wasm/build.rs index 535925c3..0096c333 100644 --- a/src/hyperlight_wasm/build.rs +++ b/src/hyperlight_wasm/build.rs @@ -22,24 +22,14 @@ limitations under the License. // this file is included in lib.rs. // The wasm_runtime binary is expected to be in the x64/{config} directory. -use std::ffi::OsString; use std::fs::OpenOptions; use std::io::Write; -use std::iter::once; use std::path::{Path, PathBuf}; use std::{env, fs}; use anyhow::Result; use built::write_built_file; -fn path_with(path: impl Into) -> OsString { - let path = path.into(); - let paths = env::var_os("PATH").unwrap_or_default(); - let paths = env::split_paths(&paths); - let paths = once(path).chain(paths); - env::join_paths(paths).unwrap() -} - fn get_wasm_runtime_path() -> PathBuf { let manifest_dir = env::var_os("CARGO_MANIFEST_DIR").unwrap(); let manifest_dir = PathBuf::from(manifest_dir); @@ -105,7 +95,6 @@ fn build_wasm_runtime() -> PathBuf { let out_dir = env::var_os("OUT_DIR").unwrap(); let target_dir = Path::new("").join(&out_dir).join("target"); - let toolchain_dir = Path::new("").join(&out_dir).join("toolchain"); let in_repo_dir = get_wasm_runtime_path(); @@ -126,19 +115,17 @@ fn build_wasm_runtime() -> PathBuf { let mut cargo_cmd = std::process::Command::new(&cargo_bin); let mut cmd = cargo_cmd + .arg("hyperlight") .arg("build") + .arg("--target-dir") + .arg(&target_dir) .arg("--profile") .arg(cargo_profile) .arg("-v") - .arg("--target-dir") - .arg(&target_dir) .current_dir(&in_repo_dir) .env_clear() - // On windows when `gdb` features is enabled this is not set correctly - .env("CFLAGS_x86_64_unknown_none", "-fPIC") .envs(env_vars) - .env("PATH", path_with(&toolchain_dir)) - .env("HYPERLIGHT_GUEST_TOOLCHAIN_ROOT", &toolchain_dir); + .env("CFLAGS_x86_64_unknown_none", "-fPIC"); // Should this go on cargo hyperlight // Add --features gdb if the gdb feature is enabled for this build script if std::env::var("CARGO_FEATURE_GDB").is_ok() { @@ -156,7 +143,7 @@ fn build_wasm_runtime() -> PathBuf { panic!("could not compile wasm_runtime"); } let resource = target_dir - .join("x86_64-unknown-none") + .join("x86_64-hyperlight-none") .join(profile) .join("wasm_runtime"); diff --git a/src/hyperlight_wasm/examples/c-component/main.rs b/src/hyperlight_wasm/examples/c-component/main.rs new file mode 100644 index 00000000..1a6de5fc --- /dev/null +++ b/src/hyperlight_wasm/examples/c-component/main.rs @@ -0,0 +1,68 @@ +use examples_common::get_wasm_module_path; +use hyperlight_wasm::SandboxBuilder; + +use crate::bindings::example::runcomponent::Guest; + +extern crate alloc; +mod bindings { + hyperlight_component_macro::host_bindgen!( + "../../src/wasmsamples/components/runcomponent-world.wasm" + ); +} + +pub struct State {} +impl State { + pub fn new() -> Self { + State {} + } +} + +impl Default for State { + fn default() -> Self { + Self::new() + } +} + +impl bindings::example::runcomponent::Host for State { + fn r#get_time_since_boot_microsecond(&mut self) -> i64 { + let res = std::time::SystemTime::now() + .duration_since(std::time::SystemTime::UNIX_EPOCH) + .unwrap() + .as_micros(); + i64::try_from(res).unwrap() + } +} + +impl bindings::example::runcomponent::RuncomponentImports for State { + type Host = State; + + fn r#host(&mut self) -> impl ::core::borrow::BorrowMut { + self + } +} + +fn main() { + let state = State::new(); + let mut sandbox = SandboxBuilder::new() + .with_guest_input_buffer_size(70000000) + .with_guest_heap_size(200000000) + .with_guest_stack_size(100000000) + //.with_debugging_enabled(8080) + .build() + .unwrap(); + let rt = bindings::register_host_functions(&mut sandbox, state); + + let sb = sandbox.load_runtime().unwrap(); + + let mod_path = get_wasm_module_path("runcomponent.aot").unwrap(); + let sb = sb.load_module(mod_path).unwrap(); + + let mut wrapped = bindings::RuncomponentSandbox { sb, rt }; + let instance = bindings::example::runcomponent::RuncomponentExports::guest(&mut wrapped); + let echo = instance.echo("Hello World!".to_string()); + println!("{}", echo); + + let result = instance.round_to_nearest_int(1.331, 24.0); + println!("rounded result {}", result); + assert_eq!(result, 32); +} diff --git a/src/hyperlight_wasm/examples/helloworld/main.rs b/src/hyperlight_wasm/examples/helloworld/main.rs index fe21a02e..730844d3 100644 --- a/src/hyperlight_wasm/examples/helloworld/main.rs +++ b/src/hyperlight_wasm/examples/helloworld/main.rs @@ -83,5 +83,37 @@ fn main() -> Result<()> { ); } } + + let tests = [ + (1.331, 24.0, 32), + (std::f32::consts::PI, std::f32::consts::E, 9), + (-5.7, 10.3, -59), + (0.0, 0.0, 0), + (99.999, 0.001, 0), + (-std::f32::consts::PI, -2.86, 9), + (1.5, 1.5, 2), + ]; + let mut sandbox = SandboxBuilder::new().build()?; + sandbox + .register( + "GetTimeSinceBootMicrosecond", + get_time_since_boot_microsecond, + ) + .unwrap(); + let wasm_sandbox = sandbox.load_runtime()?; + let mod_path = get_wasm_module_path("RunWasm.aot")?; + let mut loaded_wasm_sandbox = wasm_sandbox.load_module(mod_path)?; + let snapshot = loaded_wasm_sandbox.snapshot()?; + + for (idx, case) in tests.iter().enumerate() { + let (a, b, expected_result): (f32, f32, i32) = *case; + let result: i32 = loaded_wasm_sandbox.call_guest_function("RoundToNearestInt", (a, b))?; + assert_eq!( + result, expected_result, + "RoundToInt test case {idx} failed: got {}, expected {}", + result, expected_result + ); + loaded_wasm_sandbox.restore(&snapshot)? + } Ok(()) } diff --git a/src/wasm_runtime/.cargo/config.toml b/src/wasm_runtime/.cargo/config.toml deleted file mode 100644 index a8e6c8ec..00000000 --- a/src/wasm_runtime/.cargo/config.toml +++ /dev/null @@ -1,21 +0,0 @@ -[build] -target = "x86_64-unknown-none" - -[target.x86_64-unknown-none] -rustflags = [ - "-C", - "code-model=small", - "-C", - "link-args=-e entrypoint", -] -linker = "rust-lld" - -[env] -HYPERLIGHT_GUEST_TOOLCHAIN_ROOT = { value = "guest-toolchain", relative = true } - -[profile.release] -panic = "abort" - -[profile.dev] -opt-level = 0 -panic = "abort" diff --git a/src/wasm_runtime/build.rs b/src/wasm_runtime/build.rs index 8780d60b..2aa4b60c 100644 --- a/src/wasm_runtime/build.rs +++ b/src/wasm_runtime/build.rs @@ -14,21 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -use std::path::{Path, PathBuf}; +use std::path::Path; use std::{env, fs}; use cargo_metadata::{MetadataCommand, Package}; fn main() { - let toolchain_dir = env::var_os("HYPERLIGHT_GUEST_TOOLCHAIN_ROOT").unwrap(); - let toolchain_dir = PathBuf::from(toolchain_dir); - let clang_path = toolchain_dir.join("clang"); - - assert!( - clang_path.exists(), - "could not find clang at {clang_path:?}" - ); - println!("cargo:rerun-if-changed=."); let mut cfg = cc::Build::new(); @@ -63,7 +54,6 @@ fn main() { cfg.include("src/include"); cfg.file("src/platform.c"); - cfg.compiler(clang_path); if cfg!(windows) { env::set_var("AR_x86_64_unknown_none", "llvm-ar"); } diff --git a/src/wasmsamples/RunWasm.c b/src/wasmsamples/RunWasm.c index 3d40682d..6736e5c6 100644 --- a/src/wasmsamples/RunWasm.c +++ b/src/wasmsamples/RunWasm.c @@ -20,6 +20,7 @@ limitations under the License. #include #include #include +#include int HostPrint(char* msg); // Implementation of this will be available in the native host @@ -129,3 +130,12 @@ int KeepCPUBusy(int ms) printf("Kept CPU busy for %d ms using %d iterations of fib(10) %d|toreach max = %d|", ms, iter, INT_MAX, INT_MAX-iter); return ms; } + +__attribute__((export_name("RoundToNearestInt"))) +int RoundToNearestInt(float a, float b) +{ + float c = a*b; + float r = lrintf(c); + printf("rounded answer: %f\n", r); + return r; +} \ No newline at end of file diff --git a/src/wasmsamples/components/runcomponent.c b/src/wasmsamples/components/runcomponent.c index 0d3d43e7..c958a4dd 100644 --- a/src/wasmsamples/components/runcomponent.c +++ b/src/wasmsamples/components/runcomponent.c @@ -1,6 +1,7 @@ #include "bindings/runcomponent.h" #include #include +#include void exports_example_runcomponent_guest_echo(runcomponent_string_t *msg, runcomponent_string_t *ret) { @@ -8,4 +9,11 @@ void exports_example_runcomponent_guest_echo(runcomponent_string_t *msg, runcomp ret->ptr = (uint8_t *) malloc(ret->len); memcpy(ret->ptr, msg->ptr, ret->len); runcomponent_string_free(msg); +} + +int32_t exports_example_runcomponent_guest_round_to_nearest_int(float a, float b) +{ + float c = a*b; + float r = lrintf(c); + return r; } \ No newline at end of file diff --git a/src/wasmsamples/components/runcomponent.wit b/src/wasmsamples/components/runcomponent.wit index 941fcbfe..876efdb5 100644 --- a/src/wasmsamples/components/runcomponent.wit +++ b/src/wasmsamples/components/runcomponent.wit @@ -2,6 +2,7 @@ package example:runcomponent; interface guest { echo: func(msg: string) -> string; + round-to-nearest-int: func(a: f32, b: f32) -> s32; } interface host {