Skip to content

Latest commit

 

History

History
66 lines (57 loc) · 4.96 KB

File metadata and controls

66 lines (57 loc) · 4.96 KB

Why Compile Phoenix to WASM?

Every Phoenix request touches the same hot paths: template rendering, HTML escaping, JSON encoding, route matching, CSRF validation, cookie parsing. These are compute-bound operations where BEAM's strengths (concurrency, fault tolerance, I/O) don't help — but WASM's compiled execution dominates.

The headline numbers:

Phoenix Hot Path BEAM WASM Speedup Why
Template (150 vars) 880 μs 9.4 μs 94x Indexed slots vs String.replace chain
Template (60 vars) 316 μs 5.6 μs 56x Pre-compiled, no key hashing
Batch Dispatch (1K reqs) 3,110 μs 64 μs 49x Zero per-request boundary crossing
Batch Dispatch (1M reqs) 3,110,000 μs 64,000 μs 49x Linear scaling, amortized NIF call
JSON Encode (12 fields) 50.6 μs 1.2 μs 42x Single-pass compiled serializer
HTML Hash (change detect) 30.7 μs 0.8 μs 38x FNV-1a tight loop, no allocation
JSON Encode (4 fields) 20.2 μs 0.71 μs 28x No map traversal or intermediate lists
Content Negotiation (5 types) 7.25 μs 0.50 μs 14.4x Single-pass parse+sort+match
Batch Routing (1K reqs) 1,950 μs 147 μs 13.3x Compiled trie, amortized calls
Batch Routing (1M reqs) 1,950,000 μs 147,000 μs 13.3x Compiled trie, fully amortized
WS Upgrade Detection 6.48 μs 0.52 μs 12.4x Compiled header parser
Form (17 fields + selects) 174 μs 26.3 μs 6.6x SIMD escaping + pre-alloc buffer
HTML Escape (4.9KB page) 101 μs 17.3 μs 5.8x SIMD128 vectorized scanning
Request Dispatch 2.68 μs 0.46 μs 5.8x Compiled trie + action lookup
CSRF Token Generation 5.53 μs 0.81 μs 6.8x WASM PRNG + compiled signing
Cookie Signing 3.81 μs 0.68 μs 5.6x Compiled HMAC, no NIF crossing
JSON Response (20 fields) 60.1 μs 5.8 μs 10.3x Compiled encode + frame in one pass
Batch JSON Responses (1K) 35,800 μs 3,830 μs 9.3x Amortized encode + frame pipeline
Batch JSON Responses (1M) 35,800,000 μs 3,830,000 μs 9.3x Amortized encode + frame pipeline
Query String (10 params) 10.15 μs 1.27 μs 8.0x Compiled parser + URL decode
Redirect (302) 3.42 μs 0.50 μs 6.9x Compiled escape + template + frame
Paginated API (10 items) 213 μs 39.8 μs 5.4x Compiled JSON array + metadata
JSON Array (20 items) 396 μs 67.4 μs 5.9x Single-pass array serializer
Session Decode (8 fields) 6.08 μs 1.27 μs 4.8x Compiled hex decoder
Paginated API (25 items) 736 μs 151 μs 4.9x Compiled encode + pagination meta
Error Response (404) 2.34 μs 0.53 μs 4.4x Compiled JSON + status + frame
LiveView Full Cycle 94.6 μs 24.0 μs 3.9x Compiled diff→hash→render

Your existing Phoenix code. Same semantics. Faster execution.

Benchmarked on Elixir 1.14.0 / OTP 25, single vCPU. All results reproducible — see Performance Deep Dive for methodology and 75+ benchmarks.

Note: 1K and 1M batch numbers are extrapolated from per-request costs measured at smaller batch sizes, assuming linear scaling. Actual benchmarks at these scales may show slightly better WASM speedups due to further amortization of NIF call overhead.

The Hybrid Approach: WASM + BEAM

The key insight: not everything should be WASM. Use WASM for compute-bound hot paths, BEAM for what it's built for.

 WASM wins (compute-bound)              BEAM wins (I/O-bound)
 ──────────────────────────             ──────────────────────
 ✅ Template rendering (8-94x)          ✅ Database queries (Ecto)
 ✅ JSON encoding (28-42x)              ✅ Network I/O (HTTP clients)
 ✅ API pagination (4-6x, arrays)       ✅ Ecto queries / changesets
 ✅ HTML escaping (5-7x, SIMD)          ✅ GenServer orchestration
 ✅ Query string parsing (7-10x)        ✅ PubSub / message passing
 ✅ Route matching (3-13x, trie)        ✅ Process supervision
 ✅ CSRF/HMAC/signing (5-7x)            ✅ O(1) binary append
 ✅ Cookie & session ops (2-5x)         ✅ Pattern matching (trivial)
 ✅ LiveView diffs (2-4x)               ✅ Base.encode16 (native NIF)
 ✅ Form building (5-8x)                ✅ URL decode (no encoding, trivial)
 ✅ Content negotiation (3-14x)         ✅ WS frame encode (binary)
 ✅ Response building (4-10x)           ✅ Trivial validations (<200ns)
 ✅ Request dispatch (6-49x batch 1K-1M) ✅ Rate limiting (simple map ops)
                                        ✅ HTTP framing (pre-built body)

Firebird makes this seamless — annotate compute-hot functions with @wasm true and they compile to WebAssembly automatically. BEAM handles supervision, I/O, and message passing. WASM handles the math.