Debug e Profiling
Panoramica
Debuggare WebAssembly è più complesso rispetto a JavaScript, ma gli strumenti sono migliorati significativamente. Chrome DevTools, Firefox DevTools e strumenti specifici permettono di ispezionare, debuggare e profilare moduli Wasm.
Chrome DevTools
Visualizzare il Codice Wasm
Chrome può mostrare il codice WebAssembly Text (WAT) nei DevTools:
- Apri DevTools (F12)
- Vai nella tab Sources
- Trova il file
.wasmnel pannello di navigazione - Chrome mostra il codice WAT decompilato
Source Maps per Codice Sorgente
Con DWARF debug info, Chrome può mostrare il codice sorgente originale (C/C++/Rust) invece del WAT:
# Emscripten: compilare con debug info
emcc main.c -o main.wasm -g -gsource-map
# Rust: compilare con debug info
cargo build --target wasm32-unknown-unknown
# wasm-pack include automaticamente le source maps
Installa l’estensione C/C++ DevTools Support (DWARF) per Chrome per il supporto completo.
Breakpoint
Con le source maps abilitate puoi:
- Impostare breakpoint nel codice C/C++/Rust originale
- Fare step through riga per riga
- Ispezionare variabili locali e i loro valori
- Visualizzare lo stack trace completo
Ispezionare la Memoria
La linear memory di Wasm è ispezionabile:
- Nella tab Sources, trova il modulo Wasm
- Nel pannello Scope, espandi la sezione Memory
- Puoi visualizzare i byte raw della memoria lineare
Firefox DevTools
Firefox offre un supporto simile per il debug Wasm:
- Visualizzazione del codice WAT
- Breakpoint nel WAT
- Ispezione della memoria lineare
- Support per DWARF debug info (dalla versione 120+)
Strumenti da Linea di Comando
wasm-objdump
Parte di WABT (WebAssembly Binary Toolkit), mostra la struttura di un modulo:
# Installare wabt
npm install -g wabt
# Mostra le sezioni del modulo
wasm-objdump -h module.wasm
# Disassembla in WAT
wasm-objdump -d module.wasm
# Mostra import ed export
wasm-objdump -x module.wasm
wasm2wat e wat2wasm
Conversione tra formato binario e testuale:
# Da binario a testo (per ispezione)
wasm2wat module.wasm -o module.wat
# Da testo a binario (per test)
wat2wasm module.wat -o module.wasm
wasm-opt
Parte di Binaryen, ottimizza e analizza moduli Wasm:
# Ottimizzazione aggressiva
wasm-opt -O3 input.wasm -o output.wasm
# Ottimizzazione per dimensione
wasm-opt -Oz input.wasm -o output.wasm
# Mostra metriche
wasm-opt --metrics input.wasm
Profiling con Performance Tab
Chrome Performance Tab
- Apri DevTools → tab Performance
- Clicca Record e esegui l’operazione da profilare
- Nel flame chart, le funzioni Wasm appaiono come
wasm-function[N] - Con source maps, vedrai i nomi originali delle funzioni
Misurare i Tempi
// Misura il tempo di esecuzione nel codice JavaScript
console.time('wasm-operation');
const result = wasmModule.heavyComputation(data);
console.timeEnd('wasm-operation');
// Oppure con Performance API
const start = performance.now();
wasmModule.heavyComputation(data);
const elapsed = performance.now() - start;
console.log(`Operazione completata in ${elapsed.toFixed(2)}ms`);
Analisi Dimensione Bundle
Twiggy
Analizza quali funzioni occupano più spazio in un modulo Wasm:
# Installare twiggy (Rust)
cargo install twiggy
# Top funzioni per dimensione
twiggy top module.wasm
# Struttura ad albero dei dominatori
twiggy dominators module.wasm
# Percorsi dal root
twiggy paths module.wasm
wasm-opt --metrics
wasm-opt --metrics module.wasm
# Output:
# total
# [funcs] : 342
# [memory-data]: 15234
# [total] : 89421
Debugging Comune
Errori di Memoria
Il problema più comune con Wasm è l’accesso alla memoria fuori dai limiti:
try {
const result = wasmModule.exports.myFunction(ptr);
} catch (e) {
if (e instanceof WebAssembly.RuntimeError) {
console.error('Errore runtime Wasm:', e.message);
// "memory access out of bounds"
// "unreachable executed"
// "integer overflow"
}
}
Errori di Linking
try {
const instance = await WebAssembly.instantiate(module, importObject);
} catch (e) {
if (e instanceof WebAssembly.LinkError) {
console.error('Errore di linking:', e.message);
// Import mancante o tipo incompatibile
}
}
Console Logging da Wasm
Per debuggare, puoi passare una funzione di log come import:
const importObject = {
env: {
log_i32: (value) => console.log('Wasm int:', value),
log_f64: (value) => console.log('Wasm float:', value),
log_string: (ptr, len) => {
const bytes = new Uint8Array(memory.buffer, ptr, len);
console.log('Wasm string:', new TextDecoder().decode(bytes));
},
},
};
Best Practice
- Compila con debug info durante lo sviluppo (
-gflag) e rimuovilo in produzione - Usa wasm-opt prima del deploy per ottimizzare dimensione e velocità
- Profila con dati realistici — i micro-benchmark possono essere fuorvianti
- Monitora la dimensione del bundle — un modulo Wasm grande rallenta il caricamento
- Testa su diversi browser — le performance possono variare tra V8 e SpiderMonkey
- Usa i try/catch attorno alle chiamate Wasm per gestire errori runtime