dart-archive/wasm

Multiprocessing use case.

modulovalue opened this issue · 5 comments

The parallel programming facilities in Dart do not support shared memory parallelism. Any computation that can't block the main isolate needs to run in a different isolate where exchange of data can only happen through message passing. This is safe, but restricting. In general, message passing between isolates isn't free and there are data structures (e.g. the fat node approach for Persistent Data Structures) that can't be efficiently implemented (or simulated) with message passing only.

One workaround is to allocate memory not on the dart heap, but natively via ffi. Pointers to that natively allocated memory can be shared between isolates and shared memory parallelism can be simulated that way.

The wasmer bindings shouldn't necessarily focus on solving this use case, but they shouldn't prohibit making use of the workaround mentioned above. We should allow for that by being general enough and provide at least the facilities to allow for the following:

  • manual memory management (e.g. by providing a way to use wasmer without having to use finalizers for memory management)
  • manual memory allocation (e.g. by not forcing users to use dart:typed_data for memory allocation)

I plan to investigate this, and I think it can be achieved by:

  • having explicit wasmer bindings in the style of #92 without finalizers and with a delegate for injecting a custom memory allocator.
  • an adapter between the wasm_api.dart from #92 and the wasmer bindings. This adapter could use #95 for memory management and dart:typed_data for memory allocation.

What do you mean by memory allocation in wasm? The memory underlying WasmMemory is provided by wasmer, and the typed_data API is just used to give it a handy wrapper.

Can you give an example (pseudo code is fine) of how you'd use package:wasm for this use case, assuming whatever API changes you want.

I was mistaken. Yes, wasmer seems to allocate all the memory itself, sorry for that.
In that case, we should perhaps make it possible to share the pointers to wasmer across isolates (and not pointers to the allocated memory).

Can you give an example (pseudo code is fine) of how you'd use package:wasm for this use case

e.g.

void foo(IsolateProvider p) {
  // We create a >wasmer< module.
  final result = wasmerModuleCreateSync(...);
  // We share that module with other isolates.
  await p.send(result.module);
  // ...
  // We close our isolates.
  await p.exit();
  // We close wasmer.
  result.dispose(); 
}

Whether or not this is possible depends on Wasmer's thread safety. I looked into this a bit. There's a note in the C API that it is possible to share these objects across threads using a wasm_shared_module_t, but other objects can't be shared. According to some github issues this is not actually available yet, but once it's available something like your example might be possible.

However, the wasm module is basically just a compilation artifact, like a .exe file. Sharing it across isolates wouldn't allow shared memory. For that you'd need to be able to share instances.

It might be handy to share modules in some cases to avoid recompiling the same module on multiple isolates, but I'd want to wait for a user reported use case first, since it seems like an edge case to me. I also suspect there's some overhead to using wasm_shared_module_t, but we can't benchmark it until it's available.

Thank you for looking into this. What you're saying makes sense to me.

I guess my main concern was (ignoring all the potential Wasmer related issues) to make sure that we have thin wrappers over the pointers without any closures or logging related objects to make them cheap to move across isolates. That could become unnecessarily painful to correct once this repo loses its experimental status.

I see that there's a nontrivial amount of nuance with this issue. I should have some concrete example soon that I can share. I agree, let's postpone further discussion until then.

@liamappelbe FYI: Pointers can't yet be passed through isolates, one would have to pass integer addresses. (I hope this restriction can be lifted: dart-lang/sdk#50457)