之前写了一个 WebAssembly 的轻量运行时 PWART( https://github.com/partic2/pwart , https://gitee.com/partic/pwart ),感觉 Bug 应该修差不多了,就在前两天做了一次简单的性能测试。在这次性能测试中,发现一些有趣的地方,先放测试结果。
GCC (-O2) | PWART (fixed memory) | PWART (dynamic memory) | TinyCC | V8(Chrome v113) | |
---|---|---|---|---|---|
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 。
性能优化还是挺难做的,有很多细节要考虑,而且不知道怎么分析性能关键点,有大佬有相关经验可以分享一下。