[td][/td]
[td]GCC (-O2)[/td]
[td]PWART (fixed memory)[/td]
[td]PWART (dynamic memory)[/td]
[td]TinyCC[/td]
[td]V8(Chrome v113)[/td]
Windows10 x86_64
2823ms
3622ms
2720ms
6330ms
2618ms
Linux aarch64
1561ms
1997ms
2079ms
7681ms
1465ms
32 位 arm 的也稍测了下,PWART 耗时大约在 GCC -O2 的两倍,tinycc 是 GCC -O2 的三倍。32 位 x86 PWART 耗时大概在 GCC -O2 的 1.5 倍左右。
WebAssembly 里需要一段线性地址空间作为内存,PWART 就在进入函数时,将线性内存的基地址保存到局部变量,最开始因为局部变量较多,内存基址被挤到内存栈上了,每次 WASM 访问内存,都要从内存栈取出值加上偏移,此时耗时只有 2900ms 左右,后来我把内存基址固定放到寄存器中,耗时居然就增加到 3622ms ,让人十分摸不着头脑,不过在 32 位 arm 上测试这样是有 8%左右性能提升的。还有上表中,dynamic memory 模式需要每次函数返回时更新内存基址,按理来说是额外消耗,结果在 x86_64 上耗时竟然缩短了,不知道 x86 上究竟是有什么黑魔法。
虽然能理解,但我还是对 WebAssembly 不出指针类型耿耿于怀,在 JIT 实现和 API 设计上都能简单很多,虽然有 ref 特性,但感觉目前 ref 的设计比起指针还是麻烦不少,目前也不存在指向内存空间的 ref 。
性能优化还是挺难做的,有很多细节要考虑,而且不知道怎么分析性能关键点,有大佬有相关经验可以分享一下。