Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Mirror Wasmtime API in wasmi #287

Merged
merged 417 commits into from
Jan 6, 2022
Merged

[WIP] Mirror Wasmtime API in wasmi #287

merged 417 commits into from
Jan 6, 2022

Conversation

Robbepop
Copy link
Member

@Robbepop Robbepop commented Dec 20, 2021

This PR builds a new API for wasmi inspired by Wasmtime: https://docs.rs/wasmtime/0.32.0/wasmtime/

Preliminary Benchmarks

test bench_compile_and_validate    ... bench:   6,796,640 ns/iter (+/- 371,322)
test bench_compile_and_validate_v1 ... bench:   8,010,305 ns/iter (+/- 308,968)
test bench_instantiate_module      ... bench:     420,247 ns/iter (+/- 32,465)
test bench_instantiate_module_v1   ... bench:      61,995 ns/iter (+/- 3,467)
test bench_tiny_keccak             ... bench:   1,304,626 ns/iter (+/- 51,768)
test bench_tiny_keccak_v1          ... bench:   1,276,489 ns/iter (+/- 41,213)
test fac_opt                       ... bench:      27,856 ns/iter (+/- 4,120)
test fac_opt_v1                    ... bench:         800 ns/iter (+/- 69)
test fac_recursive                 ... bench:      29,064 ns/iter (+/- 4,505)
test fac_recursive_v1              ... bench:       1,907 ns/iter (+/- 248)
test host_calls                    ... bench:      80,189 ns/iter (+/- 7,856)
test host_calls_v1                 ... bench:      78,542 ns/iter (+/- 2,816)
test recursive_ok                  ... bench:     501,695 ns/iter (+/- 109,610)
test recursive_ok_v1               ... bench:     487,757 ns/iter (+/- 53,118)

The above benchmarks show that the general overhead of v1 is greatly reduced compared to v0 and for long running tasks for engines seem to operate with a comparable performance. Note though that v1 has not yet been optimized.

Benchmark profile ran with lto = "fat" and codegen-units = 1, otherwise performance is going to be worse for v1.

Expected Results

  • Highly improved usability.
  • Removal of tons of RefCell and Rc that are counter intuitive for Rust.
  • Native implementation of the multivalue Wasm proposal. (partial)
  • A more efficient and extensible runtime and interpreter.
  • Ideally: Drop-in replacement between wasmi and Wasmtime.

Follow-up PRs

Usage

The typical usage of the new API is very similar to the usage of the Wasmtime API. In summary:

  • Create an Engine type. This is the new wasmi interpreter. We call it Engine instead of Interpreter since it also hosts all the Wasm function bodies as the Wasmtime Engine does. This has two main reasons.

Affected Issues

What the WIP won't do

  • Change the parsing and validation infrastructure to Wasmtime's wasm-tools such as wasmparser, yet.
  • Instructions won't be compacted as suggested by Optimization: Use compact encoding of bytecode #100 but the codebase will be prepared for this step as a follow-up.
  • The WIP tries to take as much of the existing runner.rs, compile.rs as possible but tries to make it simpler for follow-ups to make changes to those parts of the code.

ToDo List

  • Properly implement Caller with respect to its internal Instance handle.
  • Extract maximum stack heights per Wasm function during compilation.
    • This information is required for efficient use of the dynamic value stack of the new v1 interpreter.
  • Fix remaining Wasm spec tests for v1 engine:
    • wasm_f32
    • wasm_f32_bitwise
    • wasm_f64
    • wasm_f64_bitwise
    • float_misc
    • wasm_imports
    • wasm_linking
      • wasm_linking test fails because instantiation of a module where the failure happens after element section and data sections are processed may leave the respective manipulated tables or linear memories in an invalid state. The fix is that instantiation should happen as if it was a transaction with this regard. Since version 1.1 WebAssembly no longer demands this behavior and the current v1 implementation seems to be fine. The only issue is that our currently embraced Wasm spec testsuite is quite outdated. Updating is not easy since many unimplemented Wasm proposals (such as multivalue) are included by default in later revisions.
    • wasm_skip_stack_guard_page
      • wasm_skip_guard_page test fails because the value stack currently is missing adjustment with respect to function stack height requirements. This is planned to be implemented soon anyways. When artificially increasing the default value stack height, the test starts to succeed.
    • wasm_start
  • Implement Wasm spec test suite tests for the new v1 interpreter.
    • Use wast instead of wabt for parsing of .wast files.
  • Implement Instance::exports method and make Instance::get_export public.
  • Carve out new LittleEndianConvert trait into its own PR for wasmi.
  • Remove Func::instance and Func::func_body and use Func::as_internal instead.
    • Reason: Func::as_internal is more efficient and covers more use cases.
  • Implement Wasm module instantiation.
    • Implement partial module instantiation where start function has not yet been executed.
    • Implement Linker::instantiate for better user experience with respect to imports resolution.
    • Implemented InstancePre to properly control execution of the start function.
  • Implement new wasmi interpreter.
    • Properly advance the program counter.
    • Lazily load default linear memory and table in FunctionFrame.
    • Implement proper function dispatch.
      • Wasm function dispatch.
      • Host function dispatch.
  • Compile and validate function bodies into the new wasmi bytecode.
    • This is still using the parity_wasm Module and wasmi-validator as well as most of the existing compilation process.
    • The only difference is that the new wasmi bytecode is generated instead of the old one and that code is fed into the new wasmi Engine instead of being collected inside the wasmi Module.
  • Add unit tests for new wasmi codegen.

Rendered Docs (WIP)

Rendered docs of what has been implemented so far (2021-12-27):

2021-12-27-234408_1299x1202_scrot

@codecov-commenter
Copy link

codecov-commenter commented Dec 20, 2021

Codecov Report

Merging #287 (0e01442) into master (94efad8) will decrease coverage by 0.08%.
The diff coverage is 79.34%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #287      +/-   ##
==========================================
- Coverage   79.56%   79.48%   -0.09%     
==========================================
  Files          31       69      +38     
  Lines        4738     9118    +4380     
==========================================
+ Hits         3770     7247    +3477     
- Misses        968     1871     +903     
Impacted Files Coverage Δ
benches/src/lib.rs 0.00% <ø> (ø)
src/lib.rs 27.27% <ø> (ø)
src/types.rs 60.41% <0.00%> (-8.64%) ⬇️
src/v1/memory/buffer_vmem.rs 0.00% <0.00%> (ø)
tests/spec/v0/run.rs 74.65% <ø> (ø)
tests/spec/v1/error.rs 8.69% <8.69%> (ø)
src/v1/func/caller.rs 33.33% <33.33%> (ø)
tests/spec/v1/descriptor.rs 35.71% <35.71%> (ø)
src/v1/error.rs 40.00% <40.00%> (ø)
src/v1/linker.rs 46.76% <46.76%> (ø)
... and 40 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 94efad8...0e01442. Read the comment docs.

This allows the wasmi v2 interpreter to eliminate an indirection when calling a Wasm function.
For visit to work properly for BrTable targets we need access to the underlying slice of instructions.
This will later include the entire interpreter implementation specific to each wasmi bytecode instruction.
These two fields are not necessary but act as optimizations in the common case of accessing the default linear memory or default table of the associated module instance.
The local variables are now stored directly in the bytecode.
This reduces the number of indirections required upon calling.
Running the start function has not yet been implemented.
@Robbepop Robbepop merged commit da92f43 into master Jan 6, 2022
@Robbepop
Copy link
Member Author

Robbepop commented Jan 6, 2022

We clarified internally that this PR is too big to be reviewed properly so we concentrate QA on follow-up PRs for extra fuzzing, and polishing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants