为了测试它的性能,我手写了一个非常简短的asm.js模块,使用32位整数数学和类型化数组(Int32Array)模拟2D波动方程。我有三个版本,尽可能相似:
- 普通的JavaScript(即易读的C风格)
- 与1相同,在其上添加了asm.js注释,使其可以通过Firefox和其他工具的验证器
- 与2相同,但是在顶部没有“use asm”;指令
我在http://jsfiddle.net/jtiscione/xj0x0qk3/上留下了一个演示,让您可以切换模块以查看使用每个模块的效果。所有三个版本都可以正常工作,但速度不同。这是热点(带有asm.js注释):
for (i = 0; ~~i < ~~h; i = (1 + i)|0) {
for (j = 0; ~~j < ~~w; j = (1 + j)|0) {
if (~~i == 0) {
index = (1 + index) | 0;
continue;
}
if (~~(i + 1) == ~~h) {
index = (1 + index) | 0;
continue;
}
if (~~j == 0) {
index = (1 + index) | 0;
continue;
}
if (~~(j + 1) == ~~w) {
index = (1 + index) | 0;
continue;
}
uCen = signedHeap [((u0_offset + index) << 2) >> 2] | 0;
uNorth = signedHeap[((u0_offset + index - w) << 2) >> 2] | 0;
uSouth = signedHeap[((u0_offset + index + w) << 2) >> 2] | 0;
uWest = signedHeap [((u0_offset + index - 1) << 2) >> 2] | 0;
uEast = signedHeap [((u0_offset + index + 1) << 2) >> 2] | 0;
uxx = (((uWest + uEast) >> 1) - uCen) | 0;
uyy = (((uNorth + uSouth) >> 1) - uCen) | 0;
vel = signedHeap[((vel_offset + index) << 2) >> 2] | 0;
vel = vel + (uxx >> 1) | 0;
vel = applyCap(vel) | 0;
vel = vel + (uyy >> 1) | 0;
vel = applyCap(vel) | 0;
force = signedHeap[((force_offset + index) << 2) >> 2] | 0;
signedHeap[((u1_offset + index) << 2) >> 2] = applyCap(((applyCap((uCen + vel) | 0) | 0) + force) | 0) | 0;
force = force - (force >> forceDampingBitShift) | 0;
signedHeap[((force_offset + index) << 2) >> 2] = force;
vel = vel - (vel >> velocityDampingBitShift) | 0;
signedHeap[((vel_offset + index) << 2) >> 2] = vel;
index = (index + 1)|0;
}
}
“普通JavaScript”版本的结构如上所述,但不包括asm.js需要的位运算符(例如“x|0”,“~~x”,“arr[(x<<2)>>2]”等)。
以下是我在使用Firefox(Developer Edition v. 41)和Chrome(版本44)时对所有三个模块的测试结果,以每次迭代的毫秒数计:
- FIREFOX(版本41):20毫秒、35毫秒、60毫秒。
- CHROME(版本44):25毫秒、150毫秒、75毫秒。
因此,在两个浏览器中,“普通JavaScript”都获胜。asm.js所需的注释存在会使性能下降三倍。此外,“use asm”;指令的存在明显有影响-它能帮助Firefox一点,并使Chrome崩溃!
仅仅添加位运算符应该不会引入三倍的性能退化,而且告诉浏览器使用asm.js也只会在Firefox中有轻微的帮助,而在Chrome中完全反效果,这似乎很奇怪。