Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第11章 调试技巧

WebAssembly 应用的调试是开发过程中的重要环节。本章将详细介绍各种调试工具、技术和最佳实践,帮助你高效地诊断和解决 WebAssembly 应用中的问题。

11.1 调试环境搭建

11.1.1 浏览器开发者工具

现代浏览器都提供了强大的 WebAssembly 调试支持,Chrome DevTools 是其中最成熟的工具之一。

Chrome DevTools 配置

启用 WebAssembly 调试功能

  1. 打开 Chrome DevTools (F12)
  2. 进入 Settings → Experiments
  3. 启用以下功能:
    • “WebAssembly Debugging: Enable DWARF support”
    • “WebAssembly Debugging: Enable scope inspection”
    • “WebAssembly Debugging: Enable stack inspection”

调试界面说明

// 加载带调试信息的 WASM 模块
async function loadWasmWithDebugInfo() {
  try {
    // 确保 WASM 文件包含调试符号
    const response = await fetch('debug_module.wasm');
    const wasmBytes = await response.arrayBuffer();
    
    // 加载时保留调试信息
    const wasmModule = await WebAssembly.instantiate(wasmBytes, {
      env: {
        debug_log: (value) => {
          console.log('WASM Debug:', value);
          // 在控制台中设置断点便于调试
          debugger;
        }
      }
    });
    
    return wasmModule.instance.exports;
  } catch (error) {
    console.error('WASM 加载失败:', error);
    throw error;
  }
}

// 调试辅助函数
function setupWasmDebugging(wasmExports) {
  // 包装 WASM 函数以添加调试信息
  const originalFunction = wasmExports.compute;
  
  wasmExports.compute = function(...args) {
    console.group('WASM Function Call: compute');
    console.log('Arguments:', args);
    console.time('execution_time');
    
    try {
      const result = originalFunction.apply(this, args);
      console.log('Result:', result);
      return result;
    } catch (error) {
      console.error('WASM Error:', error);
      throw error;
    } finally {
      console.timeEnd('execution_time');
      console.groupEnd();
    }
  };
}

Firefox Developer Edition

Firefox 也提供了出色的 WebAssembly 调试支持:

// Firefox 特定的调试配置
function setupFirefoxWasmDebugging() {
  // 启用 WebAssembly 基线编译器(便于调试)
  if (typeof WebAssembly !== 'undefined') {
    console.log('WebAssembly 支持检测:');
    console.log('- 基础支持:', !!WebAssembly.Module);
    console.log('- 流式编译:', !!WebAssembly.compileStreaming);
    console.log('- 实例化:', !!WebAssembly.instantiateStreaming);
    
    // 检查调试符号支持
    if (WebAssembly.Module.exports) {
      console.log('- 导出函数检查: 支持');
    }
  }
}

// 内存调试辅助
function debugWasmMemory(wasmInstance) {
  const memory = wasmInstance.exports.memory;
  
  return {
    // 查看内存使用情况
    getMemoryInfo() {
      const buffer = memory.buffer;
      return {
        byteLength: buffer.byteLength,
        pages: buffer.byteLength / 65536,
        maxPages: memory.maximum || 'unlimited'
      };
    },
    
    // 内存转储
    dumpMemory(offset = 0, length = 64) {
      const view = new Uint8Array(memory.buffer, offset, length);
      const hex = Array.from(view)
        .map(b => b.toString(16).padStart(2, '0'))
        .join(' ');
      console.log(`Memory dump at ${offset}:`, hex);
      return view;
    },
    
    // 监控内存增长
    watchMemoryGrowth() {
      let lastSize = memory.buffer.byteLength;
      
      const observer = setInterval(() => {
        const currentSize = memory.buffer.byteLength;
        if (currentSize !== lastSize) {
          console.log(`Memory grew: ${lastSize} → ${currentSize} bytes`);
          lastSize = currentSize;
        }
      }, 1000);
      
      return () => clearInterval(observer);
    }
  };
}

11.1.2 源码映射配置

源码映射让你能够在原始源代码级别进行调试,而不是在编译后的 WebAssembly 字节码级别。

DWARF 调试信息

Rust 项目配置

# Cargo.toml
[package]
name = "wasm-debug-demo"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

# 调试配置
[profile.dev]
debug = true           # 启用调试符号
debug-assertions = true
overflow-checks = true
lto = false           # 调试时禁用 LTO
opt-level = 0         # 禁用优化便于调试

[profile.release-with-debug]
inherits = "release"
debug = true          # 发布版本也包含调试信息
strip = false         # 不剥离调试符号

[dependencies]
wasm-bindgen = { version = "0.2", features = ["serde-serialize"] }
console_error_panic_hook = "0.1"
wee_alloc = "0.4"

[dependencies.web-sys]
version = "0.3"
features = [
  "console",
  "Performance",
]

构建脚本配置

#!/bin/bash
# build-debug.sh - 构建带调试信息的 WASM

# 设置 Rust 标志
export RUSTFLAGS="-C debuginfo=2 -C force-frame-pointers=yes"

# 使用 wasm-pack 构建
wasm-pack build \
  --target web \
  --out-dir pkg \
  --dev \
  --scope myorg \
  --debug

# 或者使用 cargo 直接构建
# cargo build --target wasm32-unknown-unknown --profile dev

# 验证调试信息
if command -v wasm-objdump &> /dev/null; then
  echo "检查调试段..."
  wasm-objdump -h pkg/wasm_debug_demo.wasm | grep -E "(debug|name)"
fi

# 生成人类可读的 WAT 文件
if command -v wasm2wat &> /dev/null; then
  echo "生成 WAT 文件..."
  wasm2wat pkg/wasm_debug_demo.wasm -o pkg/wasm_debug_demo.wat
fi

C/C++ 调试配置

Emscripten 调试构建

# 调试版本编译
emcc -O0 -g4 \
     -s WASM=1 \
     -s MODULARIZE=1 \
     -s EXPORT_NAME="DebugModule" \
     -s ASSERTIONS=1 \
     -s SAFE_HEAP=1 \
     -s STACK_OVERFLOW_CHECK=2 \
     -s DEMANGLE_SUPPORT=1 \
     -s EXPORTED_FUNCTIONS='["_main", "_debug_function"]' \
     -s EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]' \
     --source-map-base http://localhost:8080/ \
     input.c -o debug_output.js

# 高级调试选项
emcc -O0 -g4 \
     -s WASM=1 \
     -s ASSERTIONS=2 \
     -s SAFE_HEAP=1 \
     -s STACK_OVERFLOW_CHECK=2 \
     -s RUNTIME_DEBUG=1 \
     -s GL_DEBUG=1 \
     --profiling \
     --profiling-funcs \
     --emit-symbol-map \
     input.c -o advanced_debug.js

源码文件示例

// debug_example.c
#include <stdio.h>
#include <stdlib.h>
#include <emscripten.h>

// 调试宏定义
#ifdef DEBUG
#define DBG_LOG(fmt, ...) printf("[DEBUG] " fmt "\n", ##__VA_ARGS__)
#else
#define DBG_LOG(fmt, ...)
#endif

// 带调试信息的函数
EMSCRIPTEN_KEEPALIVE
int debug_function(int a, int b) {
    DBG_LOG("debug_function called with a=%d, b=%d", a, b);
    
    // 人为添加断点位置
    int result = 0;
    
    if (a > 0) {
        DBG_LOG("a is positive");
        result += a * 2;
    }
    
    if (b > 0) {
        DBG_LOG("b is positive");  
        result += b * 3;
    }
    
    DBG_LOG("result = %d", result);
    return result;
}

// 内存调试辅助函数
EMSCRIPTEN_KEEPALIVE
void debug_memory_info() {
    size_t heap_size = EM_ASM_INT({
        return HEAP8.length;
    });
    
    printf("Heap size: %zu bytes\n", heap_size);
    
    // 显示栈信息
    EM_ASM({
        console.log('Stack pointer:', stackPointer);
        console.log('Stack max:', STACK_MAX);
    });
}

int main() {
    printf("Debug demo initialized\n");
    debug_memory_info();
    return 0;
}

11.1.3 调试工具扩展

VS Code WebAssembly 扩展

安装和配置

// .vscode/settings.json
{
  "wasm.wabt.path": "/usr/local/bin",
  "wasm.showBinaryView": true,
  "wasm.showTextView": true,
  "files.associations": {
    "*.wat": "wasm",
    "*.wast": "wasm"
  },
  "debug.toolBarLocation": "docked",
  "debug.inlineValues": true
}

// .vscode/launch.json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Launch WebAssembly Debug",
      "type": "node",
      "request": "launch",
      "program": "${workspaceFolder}/debug_server.js",
      "console": "integratedTerminal",
      "env": {
        "NODE_ENV": "development"
      }
    },
    {
      "name": "Attach to Chrome",
      "port": 9222,
      "request": "attach",
      "type": "chrome",
      "webRoot": "${workspaceFolder}",
      "urlFilter": "http://localhost:*",
      "sourceMapPathOverrides": {
        "webpack:///./src/*": "${webRoot}/src/*"
      }
    }
  ]
}

// .vscode/tasks.json  
{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Build WASM Debug",
      "type": "shell",
      "command": "./build-debug.sh",
      "group": {
        "kind": "build",
        "isDefault": true
      },
      "presentation": {
        "echo": true,
        "reveal": "always",
        "focus": false,
        "panel": "shared"
      },
      "problemMatcher": []
    },
    {
      "label": "Start Debug Server",
      "type": "shell", 
      "command": "node",
      "args": ["debug_server.js"],
      "group": "test",
      "isBackground": true
    }
  ]
}

11.2 断点调试技术

11.2.1 设置和管理断点

源码级别断点

在支持源码映射的环境中,你可以直接在原始代码中设置断点:

#![allow(unused)]
fn main() {
// src/lib.rs - Rust 源码示例
use wasm_bindgen::prelude::*;

// 导入 console.log 用于调试输出
#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(js_namespace = console)]
    fn log(s: &str);
}

// 调试宏
macro_rules! console_log {
    ($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
}

#[wasm_bindgen]
pub struct DebugCounter {
    value: i32,
    step: i32,
}

#[wasm_bindgen]
impl DebugCounter {
    #[wasm_bindgen(constructor)]
    pub fn new(initial: i32, step: i32) -> DebugCounter {
        console_log!("Creating DebugCounter: initial={}, step={}", initial, step);
        
        // 这里可以设置断点
        DebugCounter {
            value: initial,
            step,
        }
    }
    
    #[wasm_bindgen]
    pub fn increment(&mut self) -> i32 {
        console_log!("Before increment: value={}", self.value);
        
        // 断点位置 - 检查状态变化
        self.value += self.step;
        
        console_log!("After increment: value={}", self.value);
        
        // 条件断点示例
        if self.value > 100 {
            console_log!("Warning: value exceeded 100!");
            // 在这里设置条件断点
        }
        
        self.value
    }
    
    #[wasm_bindgen]
    pub fn reset(&mut self) {
        console_log!("Resetting counter from {} to 0", self.value);
        self.value = 0;
    }
    
    #[wasm_bindgen(getter)]
    pub fn value(&self) -> i32 {
        self.value
    }
}

// 复杂计算函数,便于调试
#[wasm_bindgen]
pub fn debug_complex_calculation(input: &[f32]) -> Vec<f32> {
    console_log!("Starting complex calculation with {} elements", input.len());
    
    let mut result = Vec::with_capacity(input.len());
    
    for (i, &value) in input.iter().enumerate() {
        // 逐步调试每个元素的处理
        console_log!("Processing element {}: {}", i, value);
        
        let processed = if value < 0.0 {
            console_log!("Negative value detected: {}", value);
            value.abs()
        } else if value > 1.0 {
            console_log!("Large value detected: {}", value);
            value.sqrt()
        } else {
            value * value
        };
        
        result.push(processed);
        
        // 检查异常值
        if processed.is_nan() || processed.is_infinite() {
            console_log!("WARNING: Invalid result at index {}: {}", i, processed);
        }
    }
    
    console_log!("Calculation completed, {} results", result.len());
    result
}
}

JavaScript 端断点辅助

// debug_helpers.js
class WasmDebugger {
    constructor(wasmInstance) {
        this.instance = wasmInstance;
        this.breakpoints = new Map();
        this.callStack = [];
        this.variableWatches = new Map();
    }
    
    // 函数调用跟踪
    traceFunction(functionName) {
        const originalFunction = this.instance[functionName];
        
        this.instance[functionName] = (...args) => {
            const callId = Date.now();
            
            console.group(`🔍 WASM Call: ${functionName} (${callId})`);
            console.log('Arguments:', args);
            console.time(`execution-${callId}`);
            
            this.callStack.push({
                name: functionName,
                args: args,
                timestamp: callId
            });
            
            try {
                const result = originalFunction.apply(this.instance, args);
                console.log('Result:', result);
                return result;
            } catch (error) {
                console.error('Error:', error);
                throw error;
            } finally {
                console.timeEnd(`execution-${callId}`);
                console.groupEnd();
                this.callStack.pop();
            }
        };
    }
    
    // 内存监控断点
    setMemoryBreakpoint(address, size, type = 'write') {
        const memory = this.instance.memory;
        const id = `mem_${address}_${size}`;
        
        // 创建内存视图
        const originalView = new Uint8Array(memory.buffer, address, size);
        const snapshot = new Uint8Array(originalView);
        
        const checkMemory = () => {
            const currentView = new Uint8Array(memory.buffer, address, size);
            
            for (let i = 0; i < size; i++) {
                if (currentView[i] !== snapshot[i]) {
                    console.log(`🚨 Memory ${type} at address ${address + i}:`);
                    console.log(`  Old value: 0x${snapshot[i].toString(16)}`);
                    console.log(`  New value: 0x${currentView[i].toString(16)}`);
                    
                    // 触发断点
                    debugger;
                    
                    // 更新快照
                    snapshot[i] = currentView[i];
                }
            }
        };
        
        this.breakpoints.set(id, setInterval(checkMemory, 100));
        console.log(`Memory breakpoint set at 0x${address.toString(16)}, size: ${size}`);
        
        return id;
    }
    
    // 变量监控
    watchVariable(getter, name) {
        let lastValue = getter();
        
        const watchId = setInterval(() => {
            const currentValue = getter();
            if (currentValue !== lastValue) {
                console.log(`📊 Variable '${name}' changed:`);
                console.log(`  From: ${lastValue}`);
                console.log(`  To: ${currentValue}`);
                
                // 记录变化历史
                if (!this.variableWatches.has(name)) {
                    this.variableWatches.set(name, []);
                }
                
                this.variableWatches.get(name).push({
                    timestamp: Date.now(),
                    oldValue: lastValue,
                    newValue: currentValue,
                    callStack: [...this.callStack]
                });
                
                lastValue = currentValue;
            }
        }, 50);
        
        return watchId;
    }
    
    // 清除断点
    clearBreakpoint(id) {
        if (this.breakpoints.has(id)) {
            clearInterval(this.breakpoints.get(id));
            this.breakpoints.delete(id);
            console.log(`Breakpoint ${id} cleared`);
        }
    }
    
    // 获取调试报告
    getDebugReport() {
        return {
            activeBreakpoints: Array.from(this.breakpoints.keys()),
            callStack: this.callStack,
            variableHistory: Object.fromEntries(this.variableWatches),
            memoryInfo: this.getMemoryInfo()
        };
    }
    
    getMemoryInfo() {
        if (!this.instance.memory) return null;
        
        const buffer = this.instance.memory.buffer;
        return {
            byteLength: buffer.byteLength,
            pages: buffer.byteLength / 65536,
            detached: buffer.detached || false
        };
    }
}

// 使用示例
async function setupDebugging() {
    const wasmModule = await import('./pkg/wasm_debug_demo.js');
    await wasmModule.default();
    
    const debugger = new WasmDebugger(wasmModule);
    
    // 跟踪特定函数
    debugger.traceFunction('debug_complex_calculation');
    
    // 创建计数器实例
    const counter = new wasmModule.DebugCounter(0, 5);
    
    // 监控计数器值
    const watchId = debugger.watchVariable(
        () => counter.value, 
        'counter.value'
    );
    
    // 设置内存断点(如果知道内存地址)
    // const memBreakpoint = debugger.setMemoryBreakpoint(0x1000, 16);
    
    // 测试代码
    console.log('Starting debug test...');
    
    for (let i = 0; i < 10; i++) {
        counter.increment();
        await new Promise(resolve => setTimeout(resolve, 100));
    }
    
    // 复杂计算测试
    const testData = [0.5, -2.3, 1.8, 0.1, -0.9];
    const result = wasmModule.debug_complex_calculation(new Float32Array(testData));
    
    console.log('Debug test completed');
    console.log('Final report:', debugger.getDebugReport());
    
    return debugger;
}

11.2.2 条件断点和日志点

高级断点技术

#![allow(unused)]
fn main() {
// 带条件的调试代码
#[wasm_bindgen]
pub struct AdvancedDebugger {
    debug_enabled: bool,
    log_level: u32,
    breakpoint_conditions: std::collections::HashMap<String, bool>,
}

#[wasm_bindgen]
impl AdvancedDebugger {
    #[wasm_bindgen(constructor)]
    pub fn new(debug_enabled: bool) -> AdvancedDebugger {
        AdvancedDebugger {
            debug_enabled,
            log_level: 1,
            breakpoint_conditions: std::collections::HashMap::new(),
        }
    }
    
    // 条件调试日志
    fn debug_log(&self, level: u32, message: &str) {
        if self.debug_enabled && level >= self.log_level {
            let level_str = match level {
                0 => "TRACE",
                1 => "DEBUG", 
                2 => "INFO",
                3 => "WARN",
                4 => "ERROR",
                _ => "UNKNOWN",
            };
            console_log!("[{}] {}", level_str, message);
        }
    }
    
    // 条件断点辅助
    fn should_break(&self, condition_name: &str) -> bool {
        if !self.debug_enabled {
            return false;
        }
        
        // 检查断点条件
        self.breakpoint_conditions.get(condition_name)
            .copied()
            .unwrap_or(false)
    }
    
    #[wasm_bindgen]
    pub fn process_array(&mut self, data: &[i32]) -> Vec<i32> {
        self.debug_log(1, &format!("Processing array of {} elements", data.len()));
        
        let mut result = Vec::new();
        let mut error_count = 0;
        
        for (index, &value) in data.iter().enumerate() {
            self.debug_log(0, &format!("Processing element {}: {}", index, value));
            
            let processed = match value {
                v if v < 0 => {
                    self.debug_log(2, &format!("Negative value: {}", v));
                    
                    // 条件断点:遇到负数时
                    if self.should_break("negative_value") {
                        console_log!("🛑 Breakpoint: Negative value encountered at index {}", index);
                        // 这里会在浏览器中触发断点
                    }
                    
                    -v
                },
                v if v > 1000 => {
                    error_count += 1;
                    self.debug_log(3, &format!("Large value warning: {}", v));
                    
                    // 条件断点:错误计数达到阈值
                    if error_count > 3 && self.should_break("error_threshold") {
                        console_log!("🛑 Breakpoint: Error count exceeded threshold");
                    }
                    
                    1000
                },
                v => {
                    self.debug_log(0, &format!("Normal value: {}", v));
                    v * 2
                }
            };
            
            result.push(processed);
            
            // 性能监控断点
            if index % 100 == 0 && index > 0 {
                self.debug_log(1, &format!("Progress: {} elements processed", index));
                
                if self.should_break("progress_check") {
                    console_log!("🛑 Breakpoint: Progress checkpoint at {}", index);
                }
            }
        }
        
        self.debug_log(1, &format!("Array processing completed. {} errors encountered", error_count));
        result
    }
    
    #[wasm_bindgen]
    pub fn set_breakpoint_condition(&mut self, name: String, enabled: bool) {
        self.breakpoint_conditions.insert(name, enabled);
    }
    
    #[wasm_bindgen]
    pub fn set_log_level(&mut self, level: u32) {
        self.log_level = level;
        self.debug_log(1, &format!("Log level set to {}", level));
    }
}
}

JavaScript 条件断点管理

// 条件断点管理器
class ConditionalBreakpointManager {
    constructor() {
        this.conditions = new Map();
        this.logPoints = new Map();
        this.hitCounts = new Map();
    }
    
    // 设置条件断点
    setConditionalBreakpoint(name, condition, options = {}) {
        const config = {
            condition: condition,
            hitCountTarget: options.hitCountTarget || null,
            enabled: options.enabled !== false,
            logMessage: options.logMessage || null,
            onHit: options.onHit || (() => debugger)
        };
        
        this.conditions.set(name, config);
        this.hitCounts.set(name, 0);
        
        console.log(`Conditional breakpoint '${name}' set:`, config);
    }
    
    // 检查断点条件
    checkBreakpoint(name, context = {}) {
        const config = this.conditions.get(name);
        if (!config || !config.enabled) return false;
        
        // 增加命中次数
        const hitCount = this.hitCounts.get(name) + 1;
        this.hitCounts.set(name, hitCount);
        
        // 检查命中次数条件
        if (config.hitCountTarget && hitCount !== config.hitCountTarget) {
            return false;
        }
        
        // 检查条件表达式
        let conditionMet = true;
        if (config.condition) {
            try {
                // 安全地评估条件
                conditionMet = this.evaluateCondition(config.condition, context);
            } catch (error) {
                console.error(`Breakpoint condition error for '${name}':`, error);
                return false;
            }
        }
        
        if (conditionMet) {
            // 记录日志信息
            if (config.logMessage) {
                console.log(`🔍 Breakpoint '${name}' hit:`, 
                    this.interpolateLogMessage(config.logMessage, context));
            }
            
            // 执行命中处理
            config.onHit(context, hitCount);
            return true;
        }
        
        return false;
    }
    
    // 安全的条件评估
    evaluateCondition(condition, context) {
        // 创建安全的评估环境
        const safeContext = {
            ...context,
            // 添加常用的辅助函数
            Math: Math,
            console: console,
            Date: Date
        };
        
        // 简单的条件解析(生产环境应使用更安全的方式)
        const func = new Function(...Object.keys(safeContext), `return ${condition}`);
        return func(...Object.values(safeContext));
    }
    
    // 日志消息插值
    interpolateLogMessage(message, context) {
        return message.replace(/\{(\w+)\}/g, (match, key) => {
            return context[key] !== undefined ? context[key] : match;
        });
    }
    
    // 设置日志点(不中断执行)
    setLogPoint(name, message, condition = null) {
        this.logPoints.set(name, {
            message: message,
            condition: condition,
            enabled: true
        });
    }
    
    // 检查日志点
    checkLogPoint(name, context = {}) {
        const logPoint = this.logPoints.get(name);
        if (!logPoint || !logPoint.enabled) return;
        
        let shouldLog = true;
        if (logPoint.condition) {
            try {
                shouldLog = this.evaluateCondition(logPoint.condition, context);
            } catch (error) {
                console.error(`Log point condition error for '${name}':`, error);
                return;
            }
        }
        
        if (shouldLog) {
            console.log(`📝 LogPoint '${name}':`, 
                this.interpolateLogMessage(logPoint.message, context));
        }
    }
    
    // 获取断点统计
    getStatistics() {
        const stats = {
            breakpoints: {},
            logPoints: {},
            totalHits: 0
        };
        
        for (const [name, hitCount] of this.hitCounts) {
            stats.breakpoints[name] = {
                hitCount: hitCount,
                enabled: this.conditions.get(name)?.enabled || false
            };
            stats.totalHits += hitCount;
        }
        
        for (const [name, config] of this.logPoints) {
            stats.logPoints[name] = {
                enabled: config.enabled,
                message: config.message
            };
        }
        
        return stats;
    }
    
    // 清除所有断点
    clearAll() {
        this.conditions.clear();
        this.logPoints.clear();
        this.hitCounts.clear();
        console.log('All breakpoints and log points cleared');
    }
}

// 集成示例
async function demonstrateConditionalDebugging() {
    const breakpointManager = new ConditionalBreakpointManager();
    
    // 设置各种条件断点
    breakpointManager.setConditionalBreakpoint('negative_numbers', 'value < 0', {
        logMessage: 'Negative number detected: {value} at index {index}',
        onHit: (context) => {
            console.warn('Processing negative number:', context);
            debugger; // 实际断点
        }
    });
    
    breakpointManager.setConditionalBreakpoint('every_10th', 'index % 10 === 0 && index > 0', {
        hitCountTarget: 3, // 只在第3次命中时停止
        logMessage: 'Every 10th element checkpoint: index {index}'
    });
    
    breakpointManager.setLogPoint('processing_log', 
        'Processing element {index}: {value} -> {result}');
    
    // 模拟数据处理
    const testData = [-5, 3, -8, 12, 7, -1, 9, 15, -3, 6, 8, -2];
    
    for (let index = 0; index < testData.length; index++) {
        const value = testData[index];
        const result = Math.abs(value) * 2;
        
        const context = { index, value, result };
        
        // 检查断点
        breakpointManager.checkBreakpoint('negative_numbers', context);
        breakpointManager.checkBreakpoint('every_10th', context);
        
        // 检查日志点
        breakpointManager.checkLogPoint('processing_log', context);
        
        // 模拟处理延迟
        await new Promise(resolve => setTimeout(resolve, 100));
    }
    
    console.log('Final statistics:', breakpointManager.getStatistics());
}

11.3 内存调试技术

11.3.1 内存泄漏检测

内存泄漏是 WebAssembly 应用中常见的问题,特别是在处理大量数据或长时间运行的应用中。

内存使用监控

#![allow(unused)]
fn main() {
// 内存监控和泄漏检测
use std::collections::HashMap;
use std::sync::atomic::{AtomicUsize, Ordering};

static ALLOCATION_COUNT: AtomicUsize = AtomicUsize::new(0);
static TOTAL_ALLOCATED: AtomicUsize = AtomicUsize::new(0);
static TOTAL_FREED: AtomicUsize = AtomicUsize::new(0);

#[wasm_bindgen]
pub struct MemoryLeakDetector {
    allocations: HashMap<usize, AllocationInfo>,
    next_id: usize,
    threshold_bytes: usize,
    monitoring_enabled: bool,
}

#[derive(Clone)]
struct AllocationInfo {
    size: usize,
    timestamp: f64,
    stack_trace: String,
}

#[wasm_bindgen]
impl MemoryLeakDetector {
    #[wasm_bindgen(constructor)]
    pub fn new(threshold_bytes: usize) -> MemoryLeakDetector {
        console_log!("Memory leak detector initialized with threshold: {} bytes", threshold_bytes);
        
        MemoryLeakDetector {
            allocations: HashMap::new(),
            next_id: 1,
            threshold_bytes,
            monitoring_enabled: true,
        }
    }
    
    // 记录内存分配
    #[wasm_bindgen]
    pub fn track_allocation(&mut self, size: usize) -> usize {
        if !self.monitoring_enabled {
            return 0;
        }
        
        let id = self.next_id;
        self.next_id += 1;
        
        let timestamp = js_sys::Date::now();
        let stack_trace = self.get_stack_trace();
        
        self.allocations.insert(id, AllocationInfo {
            size,
            timestamp,
            stack_trace,
        });
        
        ALLOCATION_COUNT.fetch_add(1, Ordering::Relaxed);
        TOTAL_ALLOCATED.fetch_add(size, Ordering::Relaxed);
        
        console_log!("Allocation tracked: ID={}, size={} bytes", id, size);
        
        // 检查是否超过阈值
        if self.get_current_usage() > self.threshold_bytes {
            console_log!("⚠️  Memory usage exceeded threshold: {} bytes", self.get_current_usage());
        }
        
        id
    }
    
    // 记录内存释放
    #[wasm_bindgen]
    pub fn track_deallocation(&mut self, id: usize) -> bool {
        if let Some(info) = self.allocations.remove(&id) {
            TOTAL_FREED.fetch_add(info.size, Ordering::Relaxed);
            console_log!("Deallocation tracked: ID={}, size={} bytes", id, info.size);
            true
        } else {
            console_log!("⚠️  Invalid deallocation attempt: ID={}", id);
            false
        }
    }
    
    // 获取当前内存使用量
    #[wasm_bindgen]
    pub fn get_current_usage(&self) -> usize {
        self.allocations.values().map(|info| info.size).sum()
    }
    
    // 检测潜在的内存泄漏
    #[wasm_bindgen]
    pub fn detect_leaks(&self, max_age_ms: f64) -> String {
        let current_time = js_sys::Date::now();
        let mut leak_report = String::new();
        let mut total_leaked = 0;
        let mut leak_count = 0;
        
        leak_report.push_str("🔍 Memory Leak Detection Report\n");
        leak_report.push_str(&format!("Current usage: {} bytes\n", self.get_current_usage()));
        leak_report.push_str(&format!("Total allocations: {}\n", ALLOCATION_COUNT.load(Ordering::Relaxed)));
        leak_report.push_str(&format!("Total allocated: {} bytes\n", TOTAL_ALLOCATED.load(Ordering::Relaxed)));
        leak_report.push_str(&format!("Total freed: {} bytes\n", TOTAL_FREED.load(Ordering::Relaxed)));
        leak_report.push_str("\n");
        
        for (id, info) in &self.allocations {
            let age = current_time - info.timestamp;
            if age > max_age_ms {
                leak_report.push_str(&format!(
                    "🚨 Potential leak - ID: {}, Size: {} bytes, Age: {:.1}s\n",
                    id, info.size, age / 1000.0
                ));
                leak_report.push_str(&format!("   Stack trace: {}\n", info.stack_trace));
                total_leaked += info.size;
                leak_count += 1;
            }
        }
        
        if leak_count > 0 {
            leak_report.push_str(&format!("\n💥 {} potential leaks found, {} bytes total\n", leak_count, total_leaked));
        } else {
            leak_report.push_str("\n✅ No memory leaks detected\n");
        }
        
        leak_report
    }
    
    // 获取内存使用统计
    #[wasm_bindgen]
    pub fn get_statistics(&self) -> String {
        let current_usage = self.get_current_usage();
        let allocation_count = self.allocations.len();
        
        // 按大小分组统计
        let mut size_buckets = HashMap::new();
        for info in self.allocations.values() {
            let bucket = match info.size {
                0..=1024 => "< 1KB",
                1025..=10240 => "1-10KB", 
                10241..=102400 => "10-100KB",
                _ => "> 100KB",
            };
            *size_buckets.entry(bucket).or_insert(0) += 1;
        }
        
        let mut stats = String::new();
        stats.push_str("📊 Memory Usage Statistics\n");
        stats.push_str(&format!("Active allocations: {}\n", allocation_count));
        stats.push_str(&format!("Current usage: {} bytes ({:.2} MB)\n", 
            current_usage, current_usage as f64 / 1024.0 / 1024.0));
        stats.push_str("\nSize distribution:\n");
        
        for (bucket, count) in size_buckets {
            stats.push_str(&format!("  {}: {} allocations\n", bucket, count));
        }
        
        stats
    }
    
    // 强制垃圾收集
    #[wasm_bindgen]
    pub fn force_cleanup(&mut self) {
        let before_count = self.allocations.len();
        let before_size = self.get_current_usage();
        
        // 移除所有分配记录(仅用于测试)
        self.allocations.clear();
        
        console_log!("Forced cleanup: {} allocations removed, {} bytes freed", 
            before_count, before_size);
    }
    
    fn get_stack_trace(&self) -> String {
        // 在真实应用中,这里会获取实际的调用栈
        // JavaScript 端可以提供更详细的栈跟踪
        format!("stack_trace_{}", js_sys::Date::now() as u64)
    }
    
    #[wasm_bindgen]
    pub fn enable_monitoring(&mut self, enabled: bool) {
        self.monitoring_enabled = enabled;
        console_log!("Memory monitoring {}", if enabled { "enabled" } else { "disabled" });
    }
}
}

JavaScript 端内存监控

// 内存监控工具
class WasmMemoryProfiler {
    constructor(wasmInstance) {
        this.instance = wasmInstance;
        this.samples = [];
        this.isMonitoring = false;
        this.sampleInterval = null;
        this.leakDetector = null;
        
        // 初始化内存泄漏检测器
        if (wasmInstance.MemoryLeakDetector) {
            this.leakDetector = new wasmInstance.MemoryLeakDetector(10 * 1024 * 1024); // 10MB 阈值
        }
    }
    
    // 开始内存监控
    startMonitoring(intervalMs = 1000) {
        if (this.isMonitoring) {
            console.warn('Memory monitoring already active');
            return;
        }
        
        this.isMonitoring = true;
        this.samples = [];
        
        console.log('🔍 Starting memory monitoring...');
        
        this.sampleInterval = setInterval(() => {
            this.takeSample();
        }, intervalMs);
        
        // 立即取一个样本
        this.takeSample();
    }
    
    // 停止内存监控
    stopMonitoring() {
        if (!this.isMonitoring) return;
        
        this.isMonitoring = false;
        
        if (this.sampleInterval) {
            clearInterval(this.sampleInterval);
            this.sampleInterval = null;
        }
        
        console.log('🛑 Memory monitoring stopped');
        console.log('Total samples collected:', this.samples.length);
    }
    
    // 获取内存样本
    takeSample() {
        const timestamp = performance.now();
        
        // JavaScript 堆信息
        const jsMemory = this.getJSMemoryInfo();
        
        // WebAssembly 内存信息
        const wasmMemory = this.getWasmMemoryInfo();
        
        // 系统内存信息(如果可用)
        const systemMemory = this.getSystemMemoryInfo();
        
        const sample = {
            timestamp,
            jsMemory,
            wasmMemory,
            systemMemory
        };
        
        this.samples.push(sample);
        
        // 检测内存泄漏
        this.checkForLeaks(sample);
        
        return sample;
    }
    
    // 获取 JavaScript 内存信息
    getJSMemoryInfo() {
        if (!performance.memory) {
            return null;
        }
        
        return {
            used: performance.memory.usedJSHeapSize,
            total: performance.memory.totalJSHeapSize,
            limit: performance.memory.jsHeapSizeLimit
        };
    }
    
    // 获取 WebAssembly 内存信息
    getWasmMemoryInfo() {
        if (!this.instance.memory) {
            return null;
        }
        
        const buffer = this.instance.memory.buffer;
        const pages = buffer.byteLength / 65536;
        
        return {
            byteLength: buffer.byteLength,
            pages: pages,
            maxPages: this.instance.memory.maximum || null,
            detached: buffer.detached || false
        };
    }
    
    // 获取系统内存信息
    getSystemMemoryInfo() {
        // 使用 Performance Observer API(如果可用)
        if ('memory' in navigator) {
            return {
                deviceMemory: navigator.deviceMemory, // GB
                available: navigator.deviceMemory * 1024 * 1024 * 1024 // 转换为字节
            };
        }
        
        return null;
    }
    
    // 内存泄漏检测
    checkForLeaks(currentSample) {
        if (this.samples.length < 10) return; // 需要足够的样本
        
        const recentSamples = this.samples.slice(-10);
        const growthRate = this.calculateGrowthRate(recentSamples);
        
        // 检测 JavaScript 内存增长
        if (currentSample.jsMemory && growthRate.js > 0.1) { // 10% 增长率阈值
            console.warn('🚨 Potential JS memory leak detected:', {
                growthRate: growthRate.js,
                currentUsage: currentSample.jsMemory.used
            });
        }
        
        // 检测 WebAssembly 内存增长
        if (currentSample.wasmMemory && growthRate.wasm > 0.1) {
            console.warn('🚨 Potential WASM memory leak detected:', {
                growthRate: growthRate.wasm,
                currentUsage: currentSample.wasmMemory.byteLength
            });
        }
    }
    
    // 计算内存增长率
    calculateGrowthRate(samples) {
        if (samples.length < 2) return { js: 0, wasm: 0 };
        
        const first = samples[0];
        const last = samples[samples.length - 1];
        const timeSpan = last.timestamp - first.timestamp;
        
        if (timeSpan <= 0) return { js: 0, wasm: 0 };
        
        let jsGrowthRate = 0;
        let wasmGrowthRate = 0;
        
        if (first.jsMemory && last.jsMemory) {
            const jsGrowth = last.jsMemory.used - first.jsMemory.used;
            jsGrowthRate = jsGrowth / first.jsMemory.used;
        }
        
        if (first.wasmMemory && last.wasmMemory) {
            const wasmGrowth = last.wasmMemory.byteLength - first.wasmMemory.byteLength;
            wasmGrowthRate = wasmGrowth / first.wasmMemory.byteLength;
        }
        
        return { js: jsGrowthRate, wasm: wasmGrowthRate };
    }
    
    // 生成内存报告
    generateReport() {
        if (this.samples.length === 0) {
            return 'No memory samples collected';
        }
        
        const report = {
            summary: this.generateSummary(),
            trends: this.analyzeTrends(),
            leaks: this.detectLeaks(),
            recommendations: this.generateRecommendations()
        };
        
        return report;
    }
    
    generateSummary() {
        const first = this.samples[0];
        const last = this.samples[this.samples.length - 1];
        const duration = (last.timestamp - first.timestamp) / 1000; // 秒
        
        return {
            duration: `${duration.toFixed(1)}s`,
            samples: this.samples.length,
            jsMemoryChange: this.calculateMemoryChange(first.jsMemory, last.jsMemory),
            wasmMemoryChange: this.calculateMemoryChange(first.wasmMemory, last.wasmMemory)
        };
    }
    
    calculateMemoryChange(first, last) {
        if (!first || !last) return null;
        
        const change = {
            absolute: last.used - first.used || last.byteLength - first.byteLength,
            percentage: ((last.used || last.byteLength) / (first.used || first.byteLength) - 1) * 100
        };
        
        return change;
    }
    
    analyzeTrends() {
        // 分析内存使用趋势
        const jsUsage = this.samples.map(s => s.jsMemory?.used || 0);
        const wasmUsage = this.samples.map(s => s.wasmMemory?.byteLength || 0);
        
        return {
            jsMemory: {
                min: Math.min(...jsUsage),
                max: Math.max(...jsUsage),
                avg: jsUsage.reduce((a, b) => a + b, 0) / jsUsage.length,
                trend: this.calculateTrend(jsUsage)
            },
            wasmMemory: {
                min: Math.min(...wasmUsage),
                max: Math.max(...wasmUsage),
                avg: wasmUsage.reduce((a, b) => a + b, 0) / wasmUsage.length,
                trend: this.calculateTrend(wasmUsage)
            }
        };
    }
    
    calculateTrend(values) {
        if (values.length < 2) return 'insufficient_data';
        
        const first = values[0];
        const last = values[values.length - 1];
        const change = (last - first) / first;
        
        if (change > 0.1) return 'increasing';
        if (change < -0.1) return 'decreasing';
        return 'stable';
    }
    
    detectLeaks() {
        // 使用 WASM 泄漏检测器
        if (this.leakDetector) {
            return this.leakDetector.detect_leaks(30000); // 30秒阈值
        }
        
        return 'Leak detector not available';
    }
    
    generateRecommendations() {
        const recommendations = [];
        const trends = this.analyzeTrends();
        
        if (trends.jsMemory.trend === 'increasing') {
            recommendations.push('Consider implementing object pooling for JavaScript objects');
            recommendations.push('Review event listener cleanup and closure usage');
        }
        
        if (trends.wasmMemory.trend === 'increasing') {
            recommendations.push('Check for memory leaks in WASM allocation/deallocation');
            recommendations.push('Consider implementing custom memory management');
        }
        
        const lastSample = this.samples[this.samples.length - 1];
        if (lastSample.jsMemory && lastSample.jsMemory.used / lastSample.jsMemory.limit > 0.8) {
            recommendations.push('JavaScript memory usage is approaching limit');
        }
        
        if (recommendations.length === 0) {
            recommendations.push('Memory usage appears healthy');
        }
        
        return recommendations;
    }
    
    // 导出数据为 CSV
    exportToCsv() {
        const headers = ['timestamp', 'js_used', 'js_total', 'wasm_bytes', 'wasm_pages'];
        const rows = [headers.join(',')];
        
        this.samples.forEach(sample => {
            const row = [
                sample.timestamp,
                sample.jsMemory?.used || 0,
                sample.jsMemory?.total || 0,
                sample.wasmMemory?.byteLength || 0,
                sample.wasmMemory?.pages || 0
            ];
            rows.push(row.join(','));
        });
        
        return rows.join('\n');
    }
}

// 使用示例
async function demonstrateMemoryProfiling() {
    const wasmModule = await import('./pkg/wasm_debug_demo.js');
    await wasmModule.default();
    
    const profiler = new WasmMemoryProfiler(wasmModule);
    
    // 开始监控
    profiler.startMonitoring(500); // 每500ms采样一次
    
    // 模拟内存使用
    const arrays = [];
    
    for (let i = 0; i < 20; i++) {
        // 创建大数组模拟内存分配
        const size = 100000 + Math.random() * 50000;
        const array = new Float32Array(size);
        array.fill(Math.random());
        
        arrays.push(array);
        
        console.log(`Created array ${i + 1} with ${size} elements`);
        
        // 偶尔释放一些数组
        if (i > 10 && Math.random() > 0.7) {
            arrays.splice(0, 1);
            console.log('Released an array');
        }
        
        await new Promise(resolve => setTimeout(resolve, 1000));
    }
    
    // 停止监控并生成报告
    setTimeout(() => {
        profiler.stopMonitoring();
        
        const report = profiler.generateReport();
        console.log('📊 Memory Profiling Report:', report);
        
        // 导出 CSV 数据
        const csvData = profiler.exportToCsv();
        console.log('📄 CSV Export:', csvData);
        
    }, 25000);
}

11.3.2 堆栈溢出检测

#![allow(unused)]
fn main() {
// 堆栈监控和溢出检测
#[wasm_bindgen]
pub struct StackMonitor {
    max_depth: u32,
    current_depth: u32,
    max_observed_depth: u32,
    stack_traces: Vec<String>,
    overflow_threshold: u32,
}

#[wasm_bindgen]
impl StackMonitor {
    #[wasm_bindgen(constructor)]
    pub fn new(max_depth: u32) -> StackMonitor {
        StackMonitor {
            max_depth,
            current_depth: 0,
            max_observed_depth: 0,
            stack_traces: Vec::new(),
            overflow_threshold: (max_depth as f32 * 0.9) as u32, // 90% 阈值
        }
    }
    
    // 进入函数时调用
    #[wasm_bindgen]
    pub fn enter_function(&mut self, function_name: &str) -> bool {
        self.current_depth += 1;
        
        if self.current_depth > self.max_observed_depth {
            self.max_observed_depth = self.current_depth;
        }
        
        // 记录函数调用
        self.stack_traces.push(function_name.to_string());
        
        // 检查是否接近溢出
        if self.current_depth >= self.overflow_threshold {
            console_log!("⚠️  Stack depth warning: {} (threshold: {})", 
                self.current_depth, self.overflow_threshold);
            
            if self.current_depth >= self.max_depth {
                console_log!("🚨 Stack overflow detected at depth: {}", self.current_depth);
                self.print_stack_trace();
                return false; // 表示应该停止递归
            }
        }
        
        true
    }
    
    // 退出函数时调用
    #[wasm_bindgen]
    pub fn exit_function(&mut self) {
        if self.current_depth > 0 {
            self.current_depth -= 1;
            self.stack_traces.pop();
        }
    }
    
    // 打印堆栈跟踪
    #[wasm_bindgen]
    pub fn print_stack_trace(&self) {
        console_log!("📋 Stack trace (depth: {}):", self.current_depth);
        for (i, func_name) in self.stack_traces.iter().enumerate() {
            console_log!("  {}: {}", i + 1, func_name);
        }
    }
    
    // 获取堆栈统计信息
    #[wasm_bindgen]
    pub fn get_stack_stats(&self) -> String {
        format!(
            "Current depth: {}, Max observed: {}, Max allowed: {}, Threshold: {}",
            self.current_depth, self.max_observed_depth, self.max_depth, self.overflow_threshold
        )
    }
    
    // 重置监控状态
    #[wasm_bindgen]
    pub fn reset(&mut self) {
        self.current_depth = 0;
        self.max_observed_depth = 0;
        self.stack_traces.clear();
    }
}

// 递归函数示例(带堆栈监控)
#[wasm_bindgen]
pub fn monitored_fibonacci(n: u32, monitor: &mut StackMonitor) -> u64 {
    if !monitor.enter_function(&format!("fibonacci({})", n)) {
        console_log!("🛑 Stopping recursion due to stack overflow risk");
        return 0; // 错误值
    }
    
    let result = if n <= 1 {
        n as u64
    } else {
        let a = monitored_fibonacci(n - 1, monitor);
        let b = monitored_fibonacci(n - 2, monitor);
        a + b
    };
    
    monitor.exit_function();
    result
}

// 栈使用优化示例
#[wasm_bindgen]
pub fn iterative_fibonacci(n: u32) -> u64 {
    if n <= 1 {
        return n as u64;
    }
    
    let mut a = 0u64;
    let mut b = 1u64;
    
    for _ in 2..=n {
        let temp = a + b;
        a = b;
        b = temp;
    }
    
    b
}

// 尾递归优化示例
#[wasm_bindgen]
pub fn tail_recursive_factorial(n: u64, accumulator: u64, monitor: &mut StackMonitor) -> u64 {
    if !monitor.enter_function(&format!("factorial({}, acc={})", n, accumulator)) {
        return accumulator; // 返回当前累积值
    }
    
    let result = if n <= 1 {
        accumulator
    } else {
        tail_recursive_factorial(n - 1, n * accumulator, monitor)
    };
    
    monitor.exit_function();
    result
}
}

11.4 性能调试和分析

11.4.1 性能瓶颈识别

性能问题往往是最难调试的问题类型。我们需要专门的工具和技术来识别和解决性能瓶颈。

性能测量工具

#![allow(unused)]
fn main() {
// 性能分析器
use std::collections::HashMap;
use std::time::Instant;

#[wasm_bindgen]
pub struct PerformanceProfiler {
    timers: HashMap<String, f64>,
    counters: HashMap<String, u64>,
    measurements: HashMap<String, Vec<f64>>,
    memory_snapshots: Vec<MemorySnapshot>,
    profiling_enabled: bool,
}

#[derive(Clone)]
struct MemorySnapshot {
    timestamp: f64,
    heap_size: usize,
    stack_usage: usize,
}

#[wasm_bindgen]
impl PerformanceProfiler {
    #[wasm_bindgen(constructor)]
    pub fn new() -> PerformanceProfiler {
        PerformanceProfiler {
            timers: HashMap::new(),
            counters: HashMap::new(),
            measurements: HashMap::new(),
            memory_snapshots: Vec::new(),
            profiling_enabled: true,
        }
    }
    
    // 开始计时
    #[wasm_bindgen]
    pub fn start_timer(&mut self, name: &str) {
        if !self.profiling_enabled { return; }
        
        let timestamp = js_sys::Date::now();
        self.timers.insert(name.to_string(), timestamp);
    }
    
    // 结束计时并记录
    #[wasm_bindgen]
    pub fn end_timer(&mut self, name: &str) -> f64 {
        if !self.profiling_enabled { return 0.0; }
        
        let end_time = js_sys::Date::now();
        if let Some(&start_time) = self.timers.get(name) {
            let duration = end_time - start_time;
            
            // 记录测量结果
            self.measurements
                .entry(name.to_string())
                .or_insert_with(Vec::new)
                .push(duration);
            
            self.timers.remove(name);
            duration
        } else {
            console_log!("⚠️  Timer '{}' was not started", name);
            0.0
        }
    }
    
    // 增加计数器
    #[wasm_bindgen]
    pub fn increment_counter(&mut self, name: &str, value: u64) {
        if !self.profiling_enabled { return; }
        
        *self.counters.entry(name.to_string()).or_insert(0) += value;
    }
    
    // 记录内存快照
    #[wasm_bindgen]
    pub fn take_memory_snapshot(&mut self, heap_size: usize, stack_usage: usize) {
        if !self.profiling_enabled { return; }
        
        let snapshot = MemorySnapshot {
            timestamp: js_sys::Date::now(),
            heap_size,
            stack_usage,
        };
        
        self.memory_snapshots.push(snapshot);
    }
    
    // 生成性能报告
    #[wasm_bindgen]
    pub fn generate_report(&self) -> String {
        let mut report = String::new();
        
        report.push_str("🔬 Performance Analysis Report\n");
        report.push_str("================================\n\n");
        
        // 计时器统计
        if !self.measurements.is_empty() {
            report.push_str("⏱️  Timing Statistics:\n");
            for (name, measurements) in &self.measurements {
                if !measurements.is_empty() {
                    let count = measurements.len();
                    let total: f64 = measurements.iter().sum();
                    let avg = total / count as f64;
                    let min = measurements.iter().fold(f64::INFINITY, |a, &b| a.min(b));
                    let max = measurements.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b));
                    
                    // 计算百分位数
                    let mut sorted = measurements.clone();
                    sorted.sort_by(|a, b| a.partial_cmp(b).unwrap());
                    let p50 = sorted[count / 2];
                    let p95 = sorted[(count as f64 * 0.95) as usize];
                    let p99 = sorted[(count as f64 * 0.99) as usize];
                    
                    report.push_str(&format!(
                        "  {}: {} samples, avg: {:.2}ms, min: {:.2}ms, max: {:.2}ms, p50: {:.2}ms, p95: {:.2}ms, p99: {:.2}ms\n",
                        name, count, avg, min, max, p50, p95, p99
                    ));
                }
            }
            report.push_str("\n");
        }
        
        // 计数器统计
        if !self.counters.is_empty() {
            report.push_str("📊 Counter Statistics:\n");
            for (name, count) in &self.counters {
                report.push_str(&format!("  {}: {}\n", name, count));
            }
            report.push_str("\n");
        }
        
        // 内存使用分析
        if !self.memory_snapshots.is_empty() {
            report.push_str("💾 Memory Usage Analysis:\n");
            let heap_sizes: Vec<usize> = self.memory_snapshots.iter().map(|s| s.heap_size).collect();
            let stack_usages: Vec<usize> = self.memory_snapshots.iter().map(|s| s.stack_usage).collect();
            
            let heap_min = *heap_sizes.iter().min().unwrap();
            let heap_max = *heap_sizes.iter().max().unwrap();
            let heap_avg = heap_sizes.iter().sum::<usize>() / heap_sizes.len();
            
            let stack_min = *stack_usages.iter().min().unwrap();
            let stack_max = *stack_usages.iter().max().unwrap();
            let stack_avg = stack_usages.iter().sum::<usize>() / stack_usages.len();
            
            report.push_str(&format!(
                "  Heap: min: {} bytes, max: {} bytes, avg: {} bytes\n",
                heap_min, heap_max, heap_avg
            ));
            report.push_str(&format!(
                "  Stack: min: {} bytes, max: {} bytes, avg: {} bytes\n",
                stack_min, stack_max, stack_avg
            ));
            report.push_str("\n");
        }
        
        // 性能建议
        report.push_str("💡 Performance Recommendations:\n");
        report.push_str(&self.generate_recommendations());
        
        report
    }
    
    fn generate_recommendations(&self) -> String {
        let mut recommendations = String::new();
        
        // 分析计时数据给出建议
        for (name, measurements) in &self.measurements {
            if measurements.is_empty() { continue; }
            
            let avg = measurements.iter().sum::<f64>() / measurements.len() as f64;
            let mut sorted = measurements.clone();
            sorted.sort_by(|a, b| a.partial_cmp(b).unwrap());
            let p95 = sorted[(measurements.len() as f64 * 0.95) as usize];
            
            if avg > 100.0 {
                recommendations.push_str(&format!(
                    "  - '{}' has high average execution time ({:.2}ms). Consider optimization.\n",
                    name, avg
                ));
            }
            
            if p95 > avg * 2.0 {
                recommendations.push_str(&format!(
                    "  - '{}' shows high variance (P95: {:.2}ms vs Avg: {:.2}ms). Check for edge cases.\n",
                    name, p95, avg
                ));
            }
        }
        
        // 内存建议
        if !self.memory_snapshots.is_empty() {
            let heap_sizes: Vec<usize> = self.memory_snapshots.iter().map(|s| s.heap_size).collect();
            let first_heap = heap_sizes[0];
            let last_heap = heap_sizes[heap_sizes.len() - 1];
            
            if last_heap > first_heap * 2 {
                recommendations.push_str("  - Memory usage doubled during profiling. Check for memory leaks.\n");
            }
        }
        
        if recommendations.is_empty() {
            recommendations.push_str("  - No obvious performance issues detected.\n");
        }
        
        recommendations
    }
    
    // 清除所有数据
    #[wasm_bindgen]
    pub fn clear(&mut self) {
        self.timers.clear();
        self.counters.clear();
        self.measurements.clear();
        self.memory_snapshots.clear();
    }
    
    // 启用/禁用分析
    #[wasm_bindgen]
    pub fn set_enabled(&mut self, enabled: bool) {
        self.profiling_enabled = enabled;
    }
}

// 性能测试示例函数
#[wasm_bindgen]
pub fn performance_test_suite(profiler: &mut PerformanceProfiler) {
    // 测试1: 简单循环
    profiler.start_timer("simple_loop");
    let mut sum = 0;
    for i in 0..1000000 {
        sum += i;
    }
    profiler.end_timer("simple_loop");
    profiler.increment_counter("loop_iterations", 1000000);
    
    // 测试2: 内存分配
    profiler.start_timer("memory_allocation");
    let mut vectors = Vec::new();
    for _ in 0..1000 {
        vectors.push(vec![0; 1000]);
    }
    profiler.end_timer("memory_allocation");
    profiler.increment_counter("allocations", 1000);
    
    // 测试3: 数学计算
    profiler.start_timer("math_operations");
    let mut result = 1.0;
    for i in 1..10000 {
        result = (result * i as f64).sqrt();
    }
    profiler.end_timer("math_operations");
    profiler.increment_counter("math_ops", 10000);
    
    console_log!("Performance test completed. Sum: {}, Result: {:.6}", sum, result);
}
}

JavaScript 性能分析集成

// JavaScript 端性能分析
class WasmPerformanceAnalyzer {
    constructor(wasmModule) {
        this.wasmModule = wasmModule;
        this.profiler = null;
        this.observer = null;
        this.marks = new Map();
        this.isRecording = false;
    }
    
    // 初始化分析器
    async initialize() {
        if (this.wasmModule.PerformanceProfiler) {
            this.profiler = new this.wasmModule.PerformanceProfiler();
        }
        
        // 设置 Performance Observer
        if ('PerformanceObserver' in window) {
            this.observer = new PerformanceObserver((list) => {
                this.handlePerformanceEntries(list.getEntries());
            });
            
            this.observer.observe({ entryTypes: ['measure', 'navigation', 'paint'] });
        }
        
        console.log('🔬 Performance analyzer initialized');
    }
    
    // 开始性能记录
    startRecording() {
        this.isRecording = true;
        this.marks.clear();
        
        if (this.profiler) {
            this.profiler.clear();
        }
        
        // 标记开始
        performance.mark('wasm-analysis-start');
        console.log('🎬 Performance recording started');
    }
    
    // 停止性能记录
    stopRecording() {
        if (!this.isRecording) return;
        
        this.isRecording = false;
        performance.mark('wasm-analysis-end');
        performance.measure('total-analysis', 'wasm-analysis-start', 'wasm-analysis-end');
        
        console.log('🛑 Performance recording stopped');
    }
    
    // 处理性能条目
    handlePerformanceEntries(entries) {
        entries.forEach(entry => {
            if (entry.name.startsWith('wasm-')) {
                console.log(`📊 Performance entry: ${entry.name} - ${entry.duration}ms`);
            }
        });
    }
    
    // 包装函数进行性能测量
    wrapFunction(obj, funcName, category = 'general') {
        const originalFunc = obj[funcName];
        const analyzer = this;
        
        obj[funcName] = function(...args) {
            if (!analyzer.isRecording) {
                return originalFunc.apply(this, args);
            }
            
            const markName = `${category}-${funcName}`;
            const startMark = `${markName}-start`;
            const endMark = `${markName}-end`;
            
            // Performance API 标记
            performance.mark(startMark);
            
            // WASM 分析器计时
            if (analyzer.profiler) {
                analyzer.profiler.start_timer(markName);
            }
            
            try {
                const result = originalFunc.apply(this, args);
                
                // 如果是 Promise,等待完成
                if (result && typeof result.then === 'function') {
                    return result.finally(() => {
                        analyzer.endMeasurement(markName, startMark, endMark);
                    });
                } else {
                    analyzer.endMeasurement(markName, startMark, endMark);
                    return result;
                }
            } catch (error) {
                analyzer.endMeasurement(markName, startMark, endMark);
                throw error;
            }
        };
    }
    
    endMeasurement(markName, startMark, endMark) {
        performance.mark(endMark);
        performance.measure(markName, startMark, endMark);
        
        if (this.profiler) {
            this.profiler.end_timer(markName);
        }
    }
    
    // 自动包装所有导出函数
    wrapAllExports() {
        const exports = Object.keys(this.wasmModule);
        
        exports.forEach(exportName => {
            const exportValue = this.wasmModule[exportName];
            
            if (typeof exportValue === 'function') {
                this.wrapFunction(this.wasmModule, exportName, 'export');
                console.log(`🔧 Wrapped function: ${exportName}`);
            }
        });
    }
    
    // 运行性能基准测试
    async runBenchmark(testName, testFunction, iterations = 100) {
        console.log(`🏃 Running benchmark: ${testName} (${iterations} iterations)`);
        
        const results = [];
        
        for (let i = 0; i < iterations; i++) {
            const startTime = performance.now();
            
            try {
                await testFunction();
            } catch (error) {
                console.error(`Benchmark error in iteration ${i}:`, error);
                continue;
            }
            
            const endTime = performance.now();
            const duration = endTime - startTime;
            results.push(duration);
            
            // 每10次迭代记录一次进度
            if ((i + 1) % 10 === 0) {
                console.log(`Progress: ${i + 1}/${iterations} iterations completed`);
            }
        }
        
        // 计算统计信息
        const stats = this.calculateStats(results);
        console.log(`📈 Benchmark '${testName}' completed:`, stats);
        
        return stats;
    }
    
    calculateStats(values) {
        if (values.length === 0) return null;
        
        const sorted = [...values].sort((a, b) => a - b);
        const sum = values.reduce((a, b) => a + b, 0);
        
        return {
            count: values.length,
            min: sorted[0],
            max: sorted[sorted.length - 1],
            mean: sum / values.length,
            median: sorted[Math.floor(sorted.length / 2)],
            p95: sorted[Math.floor(sorted.length * 0.95)],
            p99: sorted[Math.floor(sorted.length * 0.99)],
            stdDev: this.calculateStdDev(values, sum / values.length)
        };
    }
    
    calculateStdDev(values, mean) {
        const squaredDiffs = values.map(value => Math.pow(value - mean, 2));
        const avgSquaredDiff = squaredDiffs.reduce((a, b) => a + b, 0) / values.length;
        return Math.sqrt(avgSquaredDiff);
    }
    
    // 生成综合性能报告
    generateReport() {
        const report = {
            timestamp: new Date().toISOString(),
            wasmReport: null,
            browserMetrics: this.getBrowserMetrics(),
            performanceEntries: this.getPerformanceEntries()
        };
        
        // 获取 WASM 性能报告
        if (this.profiler) {
            report.wasmReport = this.profiler.generate_report();
        }
        
        return report;
    }
    
    getBrowserMetrics() {
        const metrics = {};
        
        // 内存信息
        if (performance.memory) {
            metrics.memory = {
                used: performance.memory.usedJSHeapSize,
                total: performance.memory.totalJSHeapSize,
                limit: performance.memory.jsHeapSizeLimit
            };
        }
        
        // 导航时机
        if (performance.timing) {
            const timing = performance.timing;
            metrics.navigation = {
                domContentLoaded: timing.domContentLoadedEventEnd - timing.navigationStart,
                loadComplete: timing.loadEventEnd - timing.navigationStart,
                domInteractive: timing.domInteractive - timing.navigationStart
            };
        }
        
        return metrics;
    }
    
    getPerformanceEntries() {
        const entries = performance.getEntriesByType('measure')
            .filter(entry => entry.name.includes('wasm') || entry.name.includes('test'))
            .map(entry => ({
                name: entry.name,
                duration: entry.duration,
                startTime: entry.startTime
            }));
        
        return entries;
    }
    
    // 清理资源
    cleanup() {
        if (this.observer) {
            this.observer.disconnect();
        }
        
        if (this.profiler) {
            this.profiler.clear();
        }
        
        performance.clearMarks();
        performance.clearMeasures();
        
        console.log('🧹 Performance analyzer cleaned up');
    }
}

// 使用示例
async function demonstratePerformanceAnalysis() {
    const wasmModule = await import('./pkg/wasm_debug_demo.js');
    await wasmModule.default();
    
    const analyzer = new WasmPerformanceAnalyzer(wasmModule);
    await analyzer.initialize();
    
    // 包装所有导出函数
    analyzer.wrapAllExports();
    
    // 开始记录
    analyzer.startRecording();
    
    // 运行性能测试套件
    if (wasmModule.PerformanceProfiler) {
        const profiler = new wasmModule.PerformanceProfiler();
        wasmModule.performance_test_suite(profiler);
    }
    
    // 运行自定义基准测试
    await analyzer.runBenchmark('array_processing', async () => {
        const data = new Float32Array(1000);
        for (let i = 0; i < data.length; i++) {
            data[i] = Math.random();
        }
        
        if (wasmModule.debug_complex_calculation) {
            wasmModule.debug_complex_calculation(data);
        }
    }, 50);
    
    // 停止记录并生成报告
    analyzer.stopRecording();
    
    setTimeout(() => {
        const report = analyzer.generateReport();
        console.log('📊 Final Performance Report:', report);
        
        analyzer.cleanup();
    }, 1000);
}

11.4.2 热点分析

热点分析帮助我们找到程序中最消耗时间的部分,从而针对性地进行优化。

#![allow(unused)]
fn main() {
// 热点分析工具
#[wasm_bindgen]
pub struct HotspotAnalyzer {
    function_calls: std::collections::HashMap<String, FunctionStats>,
    call_stack: Vec<String>,
    sampling_rate: u32,
    sample_count: u32,
}

#[derive(Clone)]
struct FunctionStats {
    call_count: u64,
    total_time: f64,
    self_time: f64,
    child_time: f64,
    min_time: f64,
    max_time: f64,
}

impl FunctionStats {
    fn new() -> Self {
        FunctionStats {
            call_count: 0,
            total_time: 0.0,
            self_time: 0.0,
            child_time: 0.0,
            min_time: f64::INFINITY,
            max_time: 0.0,
        }
    }
}

#[wasm_bindgen]
impl HotspotAnalyzer {
    #[wasm_bindgen(constructor)]
    pub fn new(sampling_rate: u32) -> HotspotAnalyzer {
        HotspotAnalyzer {
            function_calls: std::collections::HashMap::new(),
            call_stack: Vec::new(),
            sampling_rate,
            sample_count: 0,
        }
    }
    
    // 进入函数
    #[wasm_bindgen]
    pub fn enter_function(&mut self, function_name: &str) -> f64 {
        self.call_stack.push(function_name.to_string());
        
        // 更新函数统计
        let stats = self.function_calls
            .entry(function_name.to_string())
            .or_insert_with(FunctionStats::new);
        stats.call_count += 1;
        
        js_sys::Date::now()
    }
    
    // 退出函数
    #[wasm_bindgen]
    pub fn exit_function(&mut self, function_name: &str, start_time: f64) {
        let end_time = js_sys::Date::now();
        let duration = end_time - start_time;
        
        if let Some(popped) = self.call_stack.pop() {
            if popped != function_name {
                console_log!("⚠️  Function stack mismatch: expected {}, got {}", function_name, popped);
            }
        }
        
        // 更新统计信息
        if let Some(stats) = self.function_calls.get_mut(function_name) {
            stats.total_time += duration;
            stats.min_time = stats.min_time.min(duration);
            stats.max_time = stats.max_time.max(duration);
            
            // 计算自身时间(不包括子函数调用)
            stats.self_time += duration;
        }
        
        // 从父函数的自身时间中减去这次调用的时间
        if let Some(parent_name) = self.call_stack.last() {
            if let Some(parent_stats) = self.function_calls.get_mut(parent_name) {
                parent_stats.self_time -= duration;
                parent_stats.child_time += duration;
            }
        }
        
        // 采样记录
        self.sample_count += 1;
        if self.sample_count % self.sampling_rate == 0 {
            self.record_sample();
        }
    }
    
    fn record_sample(&self) {
        if !self.call_stack.is_empty() {
            console_log!("📊 Sample #{}: Stack depth: {}, Top function: {}", 
                self.sample_count, self.call_stack.len(), self.call_stack.last().unwrap());
        }
    }
    
    // 生成热点报告
    #[wasm_bindgen]
    pub fn generate_hotspot_report(&self) -> String {
        let mut report = String::new();
        
        report.push_str("🔥 Hotspot Analysis Report\n");
        report.push_str("==========================\n\n");
        
        // 按总时间排序
        let mut sorted_functions: Vec<_> = self.function_calls.iter().collect();
        sorted_functions.sort_by(|a, b| b.1.total_time.partial_cmp(&a.1.total_time).unwrap());
        
        report.push_str("📈 Functions by Total Time:\n");
        report.push_str("Function Name                | Calls    | Total Time | Self Time  | Avg Time   | Min Time   | Max Time\n");
        report.push_str("----------------------------|----------|------------|------------|------------|------------|----------\n");
        
        for (name, stats) in &sorted_functions[..10.min(sorted_functions.len())] {
            let avg_time = stats.total_time / stats.call_count as f64;
            report.push_str(&format!(
                "{:<27} | {:>8} | {:>9.2}ms | {:>9.2}ms | {:>9.2}ms | {:>9.2}ms | {:>9.2}ms\n",
                name, stats.call_count, stats.total_time, stats.self_time, 
                avg_time, stats.min_time, stats.max_time
            ));
        }
        
        // 按调用次数排序
        sorted_functions.sort_by(|a, b| b.1.call_count.cmp(&a.1.call_count));
        
        report.push_str("\n📞 Functions by Call Count:\n");
        for (name, stats) in &sorted_functions[..5.min(sorted_functions.len())] {
            report.push_str(&format!(
                "  {}: {} calls, {:.2}ms total\n",
                name, stats.call_count, stats.total_time
            ));
        }
        
        // 按平均时间排序
        sorted_functions.sort_by(|a, b| {
            let avg_a = a.1.total_time / a.1.call_count as f64;
            let avg_b = b.1.total_time / b.1.call_count as f64;
            avg_b.partial_cmp(&avg_a).unwrap()
        });
        
        report.push_str("\n⏱️  Functions by Average Time:\n");
        for (name, stats) in &sorted_functions[..5.min(sorted_functions.len())] {
            let avg_time = stats.total_time / stats.call_count as f64;
            report.push_str(&format!(
                "  {}: {:.2}ms avg ({} calls)\n",
                name, avg_time, stats.call_count
            ));
        }
        
        // 优化建议
        report.push_str("\n💡 Optimization Suggestions:\n");
        report.push_str(&self.generate_optimization_suggestions());
        
        report
    }
    
    fn generate_optimization_suggestions(&self) -> String {
        let mut suggestions = String::new();
        
        // 找出总时间最长的函数
        if let Some((hottest_func, hottest_stats)) = self.function_calls.iter()
            .max_by(|a, b| a.1.total_time.partial_cmp(&b.1.total_time).unwrap()) {
            
            suggestions.push_str(&format!(
                "  1. '{}' consumes {:.1}% of total execution time. Consider optimizing this function.\n",
                hottest_func, 
                (hottest_stats.total_time / self.get_total_execution_time()) * 100.0
            ));
        }
        
        // 找出调用次数过多的函数
        if let Some((most_called_func, most_called_stats)) = self.function_calls.iter()
            .max_by(|a, b| a.1.call_count.cmp(&b.1.call_count)) {
            
            if most_called_stats.call_count > 10000 {
                suggestions.push_str(&format!(
                    "  2. '{}' is called {} times. Consider caching or reducing call frequency.\n",
                    most_called_func, most_called_stats.call_count
                ));
            }
        }
        
        // 找出平均时间过长的函数
        for (name, stats) in &self.function_calls {
            let avg_time = stats.total_time / stats.call_count as f64;
            if avg_time > 10.0 && stats.call_count > 10 {
                suggestions.push_str(&format!(
                    "  3. '{}' has high average execution time ({:.2}ms). Consider algorithmic optimization.\n",
                    name, avg_time
                ));
            }
        }
        
        if suggestions.is_empty() {
            suggestions.push_str("  - No obvious optimization opportunities detected.\n");
        }
        
        suggestions
    }
    
    fn get_total_execution_time(&self) -> f64 {
        self.function_calls.values().map(|stats| stats.self_time).sum()
    }
    
    // 重置统计
    #[wasm_bindgen]
    pub fn reset(&mut self) {
        self.function_calls.clear();
        self.call_stack.clear();
        self.sample_count = 0;
    }
    
    // 获取当前调用栈
    #[wasm_bindgen]
    pub fn get_call_stack(&self) -> String {
        self.call_stack.join(" -> ")
    }
}

// 宏:自动添加函数调用跟踪
macro_rules! profile_function {
    ($analyzer:expr, $func_name:expr, $block:block) => {
        {
            let start_time = $analyzer.enter_function($func_name);
            let result = $block;
            $analyzer.exit_function($func_name, start_time);
            result
        }
    };
}

// 热点分析示例函数
#[wasm_bindgen]
pub fn hotspot_test_suite(analyzer: &mut HotspotAnalyzer) {
    // 模拟不同性能特征的函数
    
    // 高频率调用的快速函数
    for i in 0..1000 {
        profile_function!(analyzer, "fast_function", {
            let mut sum = 0;
            for j in 0..10 {
                sum += i + j;
            }
            sum
        });
    }
    
    // 低频率调用的慢速函数
    for _i in 0..5 {
        profile_function!(analyzer, "slow_function", {
            let mut result = 1.0;
            for j in 0..100000 {
                result = (result + j as f64).sqrt();
            }
            result
        });
    }
    
    // 递归函数测试
    fn recursive_test(analyzer: &mut HotspotAnalyzer, n: u32) -> u32 {
        profile_function!(analyzer, "recursive_function", {
            if n <= 1 {
                n
            } else {
                recursive_test(analyzer, n - 1) + recursive_test(analyzer, n - 2)
            }
        })
    }
    
    recursive_test(analyzer, 10);
    
    // 嵌套函数调用测试
    profile_function!(analyzer, "outer_function", {
        for _i in 0..100 {
            profile_function!(analyzer, "inner_function_a", {
                let mut temp = 0;
                for j in 0..50 {
                    temp += j;
                }
                temp
            });
            
            profile_function!(analyzer, "inner_function_b", {
                let mut temp = 1.0;
                for j in 1..20 {
                    temp *= j as f64;
                }
                temp
            });
        }
    });
}
}

通过本章的学习,你现在掌握了 WebAssembly 应用调试的全套技术:

  1. 调试环境搭建:配置浏览器开发者工具、源码映射和调试扩展
  2. 断点调试:设置各种类型的断点,包括条件断点和日志点
  3. 内存调试:检测内存泄漏、监控内存使用和堆栈溢出
  4. 性能调试:识别性能瓶颈、进行热点分析和性能优化

这些调试技术将帮助你:

  • 快速定位和修复 WebAssembly 应用中的错误
  • 优化应用性能,提升用户体验
  • 建立健壮的调试和监控体系
  • 提高开发效率和代码质量

在下一章中,我们将把所学的知识应用到实际项目中,通过构建完整的 WebAssembly 应用来巩固和深化理解。