Skip to content

Demo of running Zig code in Elixir with Zigler and in WebAssembly server-side with Wasmex and client-side with native WebAssembly

License

Notifications You must be signed in to change notification settings

ndrean/ex_zig_zigler_wasmex

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Running Zig code in Elixir with Zigler and in Wasi-WebAssembly with Wasmex

I was curious about the difference in execution time between NIF and WebAssembly.

  • NIF with Zigler server-side
  • WASI with Wasmex server-side
  • WASM with native WebAssembly in the browser

And the winner is NIF, about two times faster.

All Zig code compiled ReleaseFast in all cases.

Compilation:

  • Zigler compiles the Zig for you
  • you pass the target .wasi in zig build for WASI
  • you pass or .freestanding in zig build for WebAssembly.

The main difference between the two solutions is the way you pass data to and from the host.

Receive data into Elixir:

  • with Zigler, you can receive a struct as a map. Zigler is quite impressive. It also provides also resources: a (safe) way to return pointers to native data structures from a NIF.
  • with Wasmex or WebAssembly, you receive a memory index when the data is in binary form

When using WebAssembly, the crux of the interaction is the serialisation of the data structure in Zig you want to pass to Elixir in order to fit the linear memory model. It remains to pattern match on the binary on the Elixir side.

Pass data from Elixir:

  • with Zigler, you pass an array of data
  • with Wasmex or WA, you write data to an index that has been allocated by Zig. This way, you can pass strings or serialised data.

Results

The results of the Genetic Algorithm ran 32 times to collect stats back in Elixir are:

Server-side:

# Threaded NIF
iex(24)> :timer.tc(fn -> GAThreaded.calc(10, "I want a beer! What about you?!") end)

{2_624_277,
 %{max: 1733, min: 545, elitism: 10, mean: 969.25, std_dev: 467.44238906711723}}

# unthreaded NIF
iex(26)> :timer.tc(fn -> GAStd.calc(10, "I want a beer! What about you?!") end)

{2_038_405,
 %{max: 1926, min: 537, elitism: 10, mean: 994.46875, std_dev: 347.26}

# WASI
iex(29)> :timer.tc(fn -> GAWasi.calc(10, "I want a beer! What about you?!") end)
{4_613_034,
 %{max: 1532, min: 474, elitism: 10, mean: 894.25, std_dev: 264.93, trials: 32}}

Browser:

4_952_399,
  {
    elitism: 10,
    mean: 1086.98,
    stdDev: 451.45,
    min: 428,
    max: 2668,
    trials: 32,
  };

Dataflow in Javascript.

You need to pass a string from the host (Javascript) to the WebAssembly container, and recover data from the WAC.

  • you call a Zig function that allocates memory of a given length
  • you populate the WA memory at this position (via an ArrayBuffer given by TextDecoder with "ascii" encoding)
  • you call a Zig function to read the memory at this position and populate an internal variable
  • to recover data from Zig, you need to serialise it into a linear format
  • you call a Zig function that sends you the index of this data
  • you populate a DataView at this index and convert the data

About

Demo of running Zig code in Elixir with Zigler and in WebAssembly server-side with Wasmex and client-side with native WebAssembly

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published