Strategi optimasi modul WebAssembly: mengecilkan ukuran dengan wasm-opt dan wasm-strip, memakai --release dan opt-level z, code splitting dengan lazy instantiation, serta benchmark dan menghindari alokasi di hot-path

Setelah di episode 14 kalian punya strategi testing dan debugging — pada episode ini kita bicara performance engineering: mengecilkan ukuran modul dan mempercepat eksekusinya. Dua metrik ini menentukan pengalaman nyata: ukuran mempengaruhi waktu download, performa mempengaruhi kecepatan interaksi.
Mengapa ini krusial di Wasm? Karena modul Wasm di-download, dikompilasi, dan dijalankan di perangkat pengguna — dan konteks itu berbeda dengan binary server. Di browser, setiap kilobyte diperhitungkan; di serverless, cold start diukur dalam milidetik. Optimasi di sini bukan kemewahan, melainkan syarat kelayakan produksi.
Binaryen menyediakan wasm-opt — optimizer modul Wasm seperti -O2 untuk compiler:
cargo install binaryen
# atau: sudo apt install binaryenOptimasi modul yang sudah jadi:
wasm-opt -O3 -o modul.opt.wasm modul.wasmLevel umum: -O1 (cepat, kecil), -O2 (seimbang), -O3 (maksimal, bisa lebih lambat compile), -Oz (fokus ukuran paling kecil). Untuk workload yang dijalankan sekali (serverless), -O3 dan -Oz hampir selalu menang.
Modul produksi tidak butuh section name dan DWARF:
wasm-strip modul.opt.wasm -o modul.stripped.wasmHasilnya sering berupa penghematan 10-30% — untuk beberapa modul bahkan lebih besar jika compiler menyertakan banyak debug info. Bandingkan sebelum/sesudah:
ls -l modul.wasm modul.opt.wasm modul.stripped.wasmOptimasi terbaik datang dari sumbernya. Dua pengaturan penting di Cargo.toml:
[profile.release]
opt-level = "z" # ukuran minimal (default "3" untuk kecepatan)
lto = true # link-time optimization
codegen-units = 1 # satu unit kompilasi -> optimasi global
panic = "abort" # hilangkan unwinding, ukuran lebih kecil
strip = true # buang simbolcargo build --release --target wasm32-unknown-unknownopt-level = "z" (size) sering menjadi pilihan untuk Wasm karena waktu download lebih berdampak daripada beberapa persen kecepatan eksekusi. lto dan codegen-units = 1 memungkinkan compiler mengoptimasi melintasi batas crate — biasanya menghemat 5-15% ukuran.
Di jalur C/C++:
emcc -O3 -flto -s STRIP_DEBUG=1 -s ALLOW_MEMORY_GROWTH=1 hello.c -o hello.jsModul yang besar tidak harus di-download sekaligus. Prinsipnya sama dengan code splitting di frontend: muat hanya saat dibutuhkan.
let modulBerat = null
export async function processBerat(data) {
if (!modulBerat) {
const modul = await import("./berat/wasm_berat.js")
await modul.default() // init dulu
modulBerat = modul
}
return modulBerat.fungsi(data)
}Untuk aplikasi dengan banyak fitur — editor, converter, analyzer — lazy loading menjaga bundle awal tetap kecil dan halaman cepat terbuka. Pasangkan dengan caching WebAssembly.Module dari episode 13 untuk meniadakan biaya kompilasi ulang.
Tip
Ukur dulu sebelum mengoptimasi: bundle yang di-download hanyalah sebagian dari total waktu. Jalankan timing kompilasi (WebAssembly.compile) dan eksekusi secara terpisah, lalu putuskan apakah mengecilkan ukuran atau mempercepat eksekusi yang lebih berdampak.
Alokasi memory — baik di Wasm (alloc) maupun di JS (new Uint8Array) — adalah biaya tersembunyi terbesar. Pola yang benar untuk loop panas:
Vec/String baru per iterasi.// BURUK: alokasi per iterasi
#[wasm_bindgen]
pub fn proses_loop(data: &[f32]) -> Vec<f32> {
data.iter().map(|x| x * 2.0 + 1.0).collect()
}
// BAIK: menulis ke buffer yang sudah disediakan host
#[wasm_bindgen]
pub fn proses_ke_buffer(input: &[f32], out: &mut [f32]) {
for (i, x) in input.iter().enumerate() {
out[i] = x * 2.0 + 1.0;
}
}Dengan versi kedua, JS menyediakan Uint8Array dari memory yang sama dan mengirim pointer-nya — nol alokasi baru dalam loop.
Setiap panggilan Wasm ↔ JS punya biaya (marshalling, boxed values). Aturan praktis:
Untuk I/O server-side, WASI 0.3 async (episode 10) memungkinkan operasi non-blocking tanpa menyita thread — menaikkan throughput jauh dibandingkan pola blokir per request.
Jangan percaya insting — ukur. Tool yang dipakai umum:
wasmtime benchmark --profile modul.wasmDi browser, gunakan Performance API:
const t0 = performance.now()
for (let i = 0; i < 1000; i++) {
instance.exports.fungsi(1000)
}
const elapsed = performance.now() - t0
console.log("rata-rata per panggilan:", elapsed / 1000, "ms")Uji pada data yang realistis, setelah warm-up (ingat tier-up JIT di episode 13), dan pada beberapa browser — hasilnya bisa sangat berbeda.
Warning
Optimasi tanpa benchmark adalah spekulasi. Tetapkan baseline dulu, ubah satu variabel, ukur lagi. Perubahan yang terlihat "jelas lebih cepat" sering kali tidak terukur — dan pengukuran yang buruk bahkan bisa menghasilkan keputusan yang merugikan.
opt-level="z" membuat kode sedikit lebih lambat; untuk loop numerik ketat, gunakan opt-level=3 dengan LTO.Pada episode 15 ini, kalian telah menguasai strategi optimasi ukuran dan performa modul WebAssembly.
Inti yang harus dibawa pulang:
wasm-opt -O3/-Oz + wasm-strip mengecilkan ukuran modul siap distribusi.opt-level="z", lto, panic="abort" mengecilkan binary Rust; -O3 -flto -s STRIP_DEBUG=1 untuk Emscripten.Di episode 16 selanjutnya kita akan membahas keamanan & sandboxing — isolasi memory per-instance, capability-based WASI tanpa raw syscall, Content Security Policy, validasi imports, dan supply-chain security dengan cargo audit. Sampai jumpa di episode 16!