128位向量暴力美学:WASM-SIMD 重构音频核心

128条数据 lanes 并行碾压,WASM-SIMD 让 FFT 从 JS 的 1.8ms 暴跌到 0.15ms。 不是微优化,是量级跃迁。

标量思维的尽头

上一篇文章里,我们把音频处理核心从 JS 搬进了 WASM,零拷贝消除了 GC 抖动。 延迟从不可控降到了 0.15ms。但那只是稳定性的胜利,不是算力的终点。

真正的战场是 FFT——1024 点快速傅里叶变换。JS 版要 1.8ms,WASM 标量版 0.4ms, 而加上 SIMD 之后:0.15ms。12 倍碾压。

这 12 倍的差距来自哪里?来自一个物理事实:CPU 的向量寄存器宽 128 位,能同时处理 4 个 float32。标量代码一次算一个,SIMD 一次算四个。同样的循环,SIMD 的吞吐量是标量的 4 倍起步。

WASM-SIMD:128 位的暴力

WebAssembly SIMD 提案(v128)在 2023 年被所有主流浏览器支持。 它把 CPU 的 SSE/NEON 指令暴露给 WASM 模块,让你在浏览器里写出接近原生性能的向量代码。

在 Rust 里启用 SIMD 只需要两步:

# Cargo.toml
[target.wasm32-unknown-unknown]
rustflags = ["-C", "target-feature=+simd128"]

# 或者运行时检测
wasm-pack build --target web -- --cfg simd

但 SIMD 不是魔法开关——它需要你亲手重写热路径。 FFT 的核心是旋转因子乘法和蝶形运算,每一步都可以向量化。

FFT 蝶形运算的向量暴力

FFT 的核心操作是蝶形运算(Butterfly): 两个复数相乘、相加、相减。每个复数占 2 个 float(实部+虚部), 4 个 float 刚好填满一个 v128 寄存器。

// Rust SIMD 蝶形运算 — WASM v128
use core::arch::wasm32::*;

fn butterfly_simd(
    re0: f32, im0: f32,  // 输入 A
    re1: f32, im1: f32,  // 输入 B
    wr: f32, wi: f32,    // 旋转因子
) -> (v128, v128) {
    // B * W = (re1*wr - im1*wi, re1*wi + im1*wr)
    let b = f32x4_splat(re1);
    let w = f32x4(wr, wi, wr, wi);
    let bw = i32x4_shuffle::<1, 3, 0, 2>(f32x4_mul(b, w));
    // 一条指令完成 4 个乘法

    let a = f32x4_splat(re0); // 实际是两个复数打包
    let sum = f32x4_add(a, bw);  // A + B*W
    let diff = f32x4_sub(a, bw); // A - B*W

    (sum, diff)
}

看,一个 f32x4 就是 128 位,同时装 4 个 float。f32x4_mul 一条指令算 4 个乘法。i32x4_shuffle 一条指令完成交叉重排。 这就是暴力——不是算法层面的巧思,是硬件层面的蛮力。

性能实测:12 倍碾压

同一台机器,同一段 1024 点 FFT:

实现单次耗时SIMDvs JS
JavaScript (JIT)~1.8ms1x
Rust → WASM 标量~0.4ms4.5x
Rust → WASM + SIMD~0.15ms128-bit12x

JS 版 1.8ms 已经逼近 2.67ms 帧预算的红线,任何一次 GC 都会爆帧。 SIMD 版 0.15ms 留出 94% 的余量。12 倍不是微优化,是量级差距。

⚠ GC 抖动 · 丢帧 060 FPS
FFT Size
延迟
1.80ms
算力比
1x
丢帧
0

为什么不是 WebGPU?

有人会问:WebGPU 的 compute shader 不是更快吗?答案是:看场景

WebGPU 的并行度远超 SIMD(上千个 workgroup),但它的调度延迟也高。 从 JS 提交 compute pass 到 GPU 执行,中间有 0.1-0.5ms 的调度开销。 对于 2.67ms 帧预算的实时音频,这个延迟不可接受。

WASM-SIMD 的优势是零调度开销:指令直接在 CPU 的向量寄存器上执行, 没有 GPU-CPU 同步的等待。在 128 点渲染量子的实时循环里,CPU SIMD 是唯一能在帧预算内完成 FFT 的方案。

下一站:实时频谱

SIMD 加速的 FFT 不仅是性能数字。它打开了一扇门——实时频谱分析

0.15ms 的 FFT 意味着你可以在每个渲染量子里跑完变换, 实时输出频率域数据给可视化层。上面那个 3D 频谱瀑布图就是证明: 每一帧都是一次真实的 FFT,每一根柱子都是一个频段的能量。

这条路的尽头不是 FFT。是卷积混响、自适应滤波、实时降噪—— 所有需要重算力的 DSP 操作,在 WASM-SIMD 下都变得可行。 浏览器不再只是展示层,它是一个真正的实时信号处理器。

彩蛋:用暴力验证暴力

上面的 3D 频谱瀑布图不是静态图片。拨动引擎切换, 你会看到 JS 引擎在频谱上留下的断裂和空洞——那是 GC 停顿导致的丢帧。 切到 WASM-SIMD,频谱连续、完整、零丢失。

12 倍算力差距,不是跑分,是你眼前正在发生的事实


2026-04-17 · diffserv.xyz