我正在调查 WebAssembly 项目中的缓慢情况,我想知道 SIMD 指令是否以某种方式被模拟。这是一个用于练习一些 SIMD 操作的 Rust 玩具库:
use core::arch::wasm32::*;
#[no_mangle]
pub fn do_something(f: f32) -> f32 {
let f4 = f32x4_splat(f);
let mut a = f4;
for _ in 0..100000 {
a = f32x4_add(a, f4);
}
f32x4_extract_lane::<0>(a)
+ f32x4_extract_lane::<1>(a)
+ f32x4_extract_lane::<2>(a)
+ f32x4_extract_lane::<3>(a)
}
然后我用
cargo build --release --target wasm32-unknown-unknown
构建它。
最后我运行它:
const response = await fetch(WASM_FILE);
const wasmBuffer = await response.arrayBuffer();
const wasmObj = await WebAssembly.instantiate(wasmBuffer, {env:{}});
function do_something() {
wasmObj.instance.exports.do_something(0.00001);
requestAnimationFrame(do_something);
}
requestAnimationFrame(do_something);
我怀疑 SIMD 操作正在被模拟,因为我看到这是 Chrome 性能调用树:
如果 SIMD 操作被降低为单个指令(就像我所期望的那样),我不会期望在配置文件跟踪中看到任何带有
f32x4_add
的内容。
这是一个众所周知的陷阱,如果您没有为 SIMD 函数启用适当的
target_feature
,它们不会内联,从而导致重大开销。 甚至有记录。
解决方案是打开
simd128
目标功能。您可以通过设置 RUSTFLAGS
(例如,.cargo/config.toml
中的 )来完成此操作,并将参数 -C target-feature=+simd128
传递给 rustc。