Kino 7 – Friday, 2 pm – Buzzing Technologies

Creating High-Performance Web Apps with WebAssembly

Konstantin Möllers

Konstantin Möllers

Creating High-Performance Web Apps with WebAssembly

Buzzing Technologies

$ whoami

Konstantin Möllers
Performance Engineer @ Baqend
Master of Science @ Uni Hamburg
Professional working experience for 6 years

A Bit of History …

Machine Assembly
Imperative Code
Object Orientation
Patterns & Functions
WebAssembly ???

What is WebAssembly?

WebAssembly (abbreviated Wasm) is a binary in­struc­tion format for a stack-based virtual machine. Wasm is designed as a portable target for compilation of high-level languages like C/C++/Rust, enabling deployment on the web for client and server app­li­ca­tions.

self description on webassembly.org

Stack-Based Machines

Imperative


a = b + c
d = a * e
        

Stack-Based


b
c
+
set(a)
e
*
set(d)
              

WebAssembly  ’s Benefits

57+
52+
16+
44+
11+
8+

JavaScript & Wasm

  • slow to parse & execute
  • large file sizes
  • insecure
  • open world
  • can be written by hand
  • easy to debug
  • fast to parse & execute
  • smaller file sizes
  • secure
  • closed box
  • needs compiling
  • difficult to debug

JS and Wasm are a perfect match for hybrid apps!

Have ES6 & Wasm Modules Combined!

Enabled Use Cases

  • Block Chain and Coin Miners
  • AI and Machine Learning
  • 2D and 3D games
  • Music and video editing
  • Image manipulation
  • Emulation and VMs
  • High Security Applications



Web Assembly Features

Data Types

number
  • i32
  • i64
  • f32
  • f64
boolean
  • i32
string
function
object

Operations

But how do I create a Wasm binary and use it?

Instantiating WebAssembly Code


async function initWebAssembly(wasmUrl: string, importObject?: any) {
  const response = await fetch(wasmUrl)
  const bytes = await response.arrayBuffer()

  // Compile the bytecode to a WASM module
  const module = await WebAssembly.compile(bytes)

  // Wake up the module: „importObject“ is bound to the module
  return new WebAssembly.Instance(module, importObject)
}

// For the Fibonacci Example:
// Call the exported function “fibonacci” with 6.
initWebAssembly('fibonacci.wasm')
  .then(instance => instance.exports.fibonacci(6))
  .then(console.log)
        

Programming Languages

Using C


// fibonacci.c
int fibonacci(int n) {
  if (n <= 0) return 0;
  if (n == 1) return 1;
  return fibonacci(n - 1) + fibonacci(n - 2);
}
        

$ emcc fibonacci.c \
       -s WASM=1 \
       -s ONLY_MY_CODE=1 \
       -s EXPORTED_FUNCTIONS="['_fibonacci']" \
       -Os \
       -o fibonacci.c.js
        

// Usage from JavaScript
const response = await fetch('./fibonacci.c.wasm')
const instance = await WebAssembly.instantiateStreaming(response)
const result = instance.exports._fibonacci(21, 21) // Mind the "_"!
console.log(result) // Logs "42"
        

Using Rust


// fibonacci.rs

#[no_mangle]
pub fn fibonacci(n: i32) -> i32 {
  match n {
    std::i32::MIN...0 => 0,
    1 => 1,
    _ => fibonacci(n - 1) + fibonacci(n - 2),
  }
}

        

$ rustc -O --crate-type=cdylib --target=wasm32-unknown-unknown \
        -o fibonacci.rs.wasm \
        fibonacci.rs
        

// Usage from JavaScript
const response = await fetch('./fibonacci.rs.wasm')
const instance = await WebAssembly.instantiateStreaming(response)
const result = instance.exports.fibonacci(21, 21)
console.log(result) // Logs "42"
        

Using asm.js


// fibonacci.asm.js
function fibonacci() {
  "use asm";

  function fibonacci(n) {
    n = n | 0;
    if (n <= 0) return 0 | 0;
    if (n == 1) return 1 | 0;

    return ((fibonacci(n - 1) | 0) + (fibonacci(n - 2) | 0)) | 0;
  }

  return { fibonacci: fibonacci };
}
        

$ asm2wasm fibonacci.asm.js -Os -o fibonacci.asm.js.wasm
        

// Usage from JavaScript
const response = await fetch('./fibonacci.asm.js.wasm')
const instance = await WebAssembly.instantiateStreaming(response)
const result = instance.exports.fibonacci(21, 21)
console.log(result) // Logs "42"
        

Using Wasm Text Format


;; fibonacci.wat
(func $fibonacci
  (export "fibonacci") ;; Function export name
  (param $n i32) (result i32) ;; Signature: (i32) -> i32

  ;; If condition $n ≤ 0
  (if (i32.le_s (get_local $n) (i32.const 0))
    (then
      (return (i32.const 0))))

  ;; If condition $n = 1
  (if (i32.eq (get_local $n) (i32.const 1))
    (then
      (return (i32.const 1))))

  (return
    (i32.add
      (call $fibonacci ;; Recursive function call
        (i32.sub (get_local $n) (i32.const 1)))
      (call $fibonacci
        (i32.sub (get_local $n) (i32.const 2))))))
        

$ wat2wasm fibonacci.wat -o fibonacci.wat.wasm
        

Debugging Wasm Code

Demo App

Mandelbrot Fractal
with Rust + WebAssembly

Calculating the Mandelbrot Fractal

For each pixel c, calculate

Which is the same as

until |zn| > 2, or a limit of 40 iterations occurs.

wasm-bindgen


extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;

#[wasm_bindgen(module = "./greet")]
extern {
  pub fn greet(greeted: &str) -> String;
}

#[wasm_bindgen]
pub fn say_hi(name: &str) -> String {
  let greeting = greet(name);
  format!("{}! Nice to see you at my talk!", greeting)
}
        

// greet.js
export function greet(name) {
  return `Hello, ${name}`
}
        

// index.js
import('./wasm-package')
  .then(pkg => pkg.say_hi('Markus'))
  .then(msg => console.log(msg))
        

Benchmark

Average Latency 561 ms 396 ms 569 ms 331 ms 994 ms 295 ms
– 42 % – 72 % – 237 %
Median Latency 557 ms 388 ms 558 ms 329 ms 984 ms 293 ms
– 44 % – 70 % – 236 %
Throughput 1.78/s 2.52/s 1.76/s 3.02/s 1.01/s 3.39/s
+ 42 % + 72 % + 236 %

Fork me on GitHub!

github.com/ksm2/wasm-mandelbrot

Who We Are

product

Our Product

Speed Kit:

  • Accelerates any website
  • Pluggable
  • Easy Setup

test.speed-kit.com

services

Our Services

  • Web & Data Management Consulting
  • Performance Auditing
  • Implementation Services

consulting@baqend.com

Our Other Talks

  • Kino 5 – Today, 11 am – Frontend
    Enhancing Data Processing in Browsers Using Streams
    by Konstantin Möllers
  • Kino 5 – Today, 12 am – Frontend
    Service Workers: The Technology Behind Progressive Web Apps
    by Felix Gessert
  • Kino 6 – Today, 3 pm – Architecture
    Real-Time Processing Explained: A Survey of Storm, Samza, Spark & Flink
    by Wolfram Wingerath

slides.baqend.com QR Code

Thanks for Watching!

Konstantin Möllers
ksm@baqend.com
@ksm2
@k_moellers

slides.baqend.com QR Code