Skip to content
This repository has been archived by the owner on Jul 1, 2023. It is now read-only.

Configure Wasmer engine to use: Singlepass, Cranelift, (LLVM) #60

Open
rhobro opened this issue Nov 7, 2021 · 12 comments
Open

Configure Wasmer engine to use: Singlepass, Cranelift, (LLVM) #60

rhobro opened this issue Nov 7, 2021 · 12 comments
Labels
enhancement New feature or request

Comments

@rhobro
Copy link

rhobro commented Nov 7, 2021

The way that wasm_bindgen in Rust can access functions that are defined externally, how does one allow the WASM to call dart functions?

@liamappelbe
Copy link
Contributor

When you're instantiating the module, you can fill any function imports with Dart functions:

var inst = (WasmModule(data).builder()
      ..addFunction('env', 'myFunction', (int x) {
        // Do stuff
      }))
    .build();

You can see an example here: https://github.com/dart-lang/wasm/blob/main/wasm/test/fn_import_test.dart

On the C side, you just declare the function, but don't give it a body (this would usually give you a linker error, but you can tell your compiler to treat it as a function to be filled in later).

void myFunction(int x);

@rhobro
Copy link
Author

rhobro commented Nov 8, 2021

That's brilliant. I'll try that out.

To save creating another issue for each question, I hope it is ok if I put them here. I'll edit the title accordingly.

As far as I know, this plugin uses Wasmer to run the code. Looking at the Wasmer docs, I found that it is possible to use the Singlepass, Cranelift or LLVM compiler in increasing order of runtime performance and compilation time. How can I configure this through the WASM plugin?

In my use case, I have a WASM file which acts as a package. I need to write a Rust program to interact with this package. For this, I plan to use Wasmer rust. I need to then compile the Rust program to WASM which will then run on the phone using this plugin. Is there any way I can import the contents of the package WASM file into rust to avoid having nested Wasmer runtimes?

@rhobro rhobro changed the title Call host functions from WebAssembly Call host code & Wasmer engine configuration & how to avoid nested runtimes Nov 8, 2021
@liamappelbe
Copy link
Contributor

As far as I know, this plugin uses Wasmer to run the code. Looking at the Wasmer docs, I found that it is possible to use the Singlepass, Cranelift or LLVM compiler in increasing order of runtime performance and compilation time. How can I configure this through the WASM plugin?

Right now we use cranelift and there's no way to configure it. You can check out wasm/bin/cargo.toml to see all the config options we're using. Why do you want to configure this?

In my use case, I have a WASM file which acts as a package. I need to write a Rust program to interact with this package. For this, I plan to use Wasmer rust. I need to then compile the Rust program to WASM which will then run on the phone using this plugin. Is there any way I can import the contents of the package WASM file into rust to avoid having nested Wasmer runtimes?

You mean import package:wasm into rust? I don't know of any way to import dart into rust, but I don't do much rust programming. I think you'd still end up with multiple wasm runtimes, one in an .so file, and one in wasm code.

What if you compile your rust program to wasm, without the wasmer runtime, and with api surface between your rust library and wasm module exposed as function imports and exports? Then you could just import the rust and wasm modules into dart using package:wasm, and wire up the function imports and exports through dart. That way you'd only have package:wasm's runtime.

@rhobro
Copy link
Author

rhobro commented Nov 8, 2021

I want to configure this because the LLVM compiler is supposed to be the highest performing compiler out of them. My use-case requires as much performance as possible. Is it even possible to have this as an option on mobile?

Would it work if I used Wasmer to compile the package wasm into a .so or .dylib or whatever and then import that into Rust and then compile the result into WASM?

That could be a possibility. I'll look into it.

@liamappelbe
Copy link
Contributor

I want to configure this because the LLVM compiler is supposed to be the highest performing compiler out of them. My use-case requires as much performance as possible. Is it even possible to have this as an option on mobile?

I think LLVM would greatly increase your app size, and make your startup time slower, and only give you a modest speed boost. It wouldn't be possible to use this on iOS. I'm not sure if it would be possible on Android (that's a question for the Wasmer folks).

Before you conclude that LLVM is what you want, you should try running a benchmark. Run your library in Wasmer using LLVM and cranelift, and see how fast it runs, and how big the Wasmer binary is. I suspect that cranelift is the best trade-off between binary size and speed, but if you have data that says otherwise I can make this option configurable.

Would it work if I used Wasmer to compile the package wasm into a .so or .dylib or whatever and then import that into Rust and then compile the result into WASM?

If you do that, you'll have 2 copies of Wasmer in your app, one in package:wasm's .so file, and one in your wasm module. Also I don't know if it's even possible. Maybe try asking on the Rust stack overflow page.

@rhobro
Copy link
Author

rhobro commented Nov 8, 2021

My app is not one that is to be used by a wide audience and is only for my own use so the app size and startup time are not particularly important. Due to the performance critical nature of the app, I'd happily accept a modest speed boost haha. But if it's not possible, then nothing can be done about that. I might create an issue on the wasmer repo regarding this.

Out of interest, why would LLVM not run on iOS?

I'll run some benchmarks once the full custom WASM code is written. In the meantime, would it be possible to provide an option between Singleness and Cranelift anyway? Any customisability is appreciated.

That sounds inefficient, I'll try formulate a better plan. Thank you though.

@rhobro
Copy link
Author

rhobro commented Nov 8, 2021

Regarding the customisability for the compiler and engine of wasmer, it'll just allow the dev to choose the best option for their needs

@liamappelbe
Copy link
Contributor

Out of interest, why would LLVM not run on iOS?

I think LLVM is going to be generating machine code at runtime, which is not allowed on iOS. But I might be wrong about that. Check with the wasmer team.

If your project is just for you, you might fine it easier and faster to use FFI to load your Rust library. You could still use package:wasm to load the wasm library if you want.

@rhobro
Copy link
Author

rhobro commented Nov 9, 2021

The project is just for me but I have 2 reasons for wanting to load my rust code through WASM:

  1. This app will just be an interface to a physical device which only works with mobile. The rust code will contain the logic. I want to be able to load in different logic at any time.

  2. It will make development a bit faster because I won't have to recompile the app each time but just recompile the WASM and upload it

It seems like it'll be necessary to have nested wasmer runtimes for now but I'll check it out with the wasmer team as you suggested.

@liamappelbe
Copy link
Contributor

liamappelbe commented Nov 9, 2021

I mentioned this before, but I'll elaborate: it's possible to load both your rust module and your wasm module using package:wasm, without needing nested wasm runtimes.

  1. Compile both your modules to wasm
  2. Load them both into Dart using package:wasm
  3. When you want to call from the rust module into the wasm module, do so by exporting the function from the wasm module, and importing the function into the rust module. Then you can use Dart as the bridge:
// Load the wasm module.
var wasmInst = (WasmModule(wasmModuleData).builder()).build();
var myFunction = wasmInst.lookupFunction('myFunction');

// Load the rust module.
var rustInst = (WasmModule(rustModuleData).builder()
      ..addFunction('env', 'myFunction', myFunction))
    .build();

From the Rust library's perspective, the wasm module will just be an external shared library that it imports some functions from. The Rust library won't need to run a wasm runtime. I don't know how you declare function imports in Rust, but the C equivalent would be:

void myFunction(int x);

@rhobro
Copy link
Author

rhobro commented Nov 10, 2021

Unfortunately, that doesn't work for my use case. But thank you very much anyway.

@rhobro rhobro changed the title Call host code & Wasmer engine configuration & how to avoid nested runtimes Configure Wasmer engine to use: Singlepass, Cranelift, (LLVM) Nov 10, 2021
@liamappelbe liamappelbe added the enhancement New feature or request label Nov 10, 2021
@liamappelbe
Copy link
Contributor

Making this configurable should be doable. It's just plumbing.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request
Development

No branches or pull requests

2 participants