我正在运行我的Z80模拟器 https://github.com/lkesteloot/z80-emulator在 Chrome 和 Node 中。我在 Chrome 中获得的性能大约是 Node 中的 10 倍。 (100k Z80 指令在 Chrome 中需要 6 毫秒,在 Node 中需要 60 毫秒。)我已经运行了分析器:
% node --prof index.js
% node --prof-process isolate-0x108000000-25550-v8.log
它说 95% 的时间花在 C++ 上:
[Summary]:
ticks total nonlib name
103 3.8% 3.8% JavaScript
2604 95.2% 95.8% C++
6 0.2% 0.2% GC
17 0.6% Shared libraries
12 0.4% Unaccounted
C++ 的细分是:
[C++ entry points]:
ticks cpp total name
2127 98.3% 77.7% T __ZN2v88internal40Builtin_CallSitePrototypeGetPromiseIndexEiPmPNS0_7IsolateE
32 1.5% 1.2% T __ZN2v88internal21Builtin_HandleApiCallEiPmPNS0_7IsolateE
我已经追踪到CallSitePrototypeGetPromiseIndex
to 这个源文件 https://github.com/nodejs/node/blob/master/deps/v8/src/builtins/builtins-callsite.cc。我没有使用承诺,async
, or await
在我的代码中。我的测试只是 100k 模拟 Z80 指令的紧密循环,没有 I/O 或任何东西。
我在网上找到了其他人使用--prof
旗,但没有人在他们的结果中发现这一点。这是分析的副作用吗?我是否在循环内以某种方式触发了承诺? Node 为何比 Chrome 慢这么多?
详细信息:节点 v12.13.1、Chrome 79.0.3945.88。
Okay 这个惊人相似的问题 https://stackoverflow.com/questions/18830626/should-i-use-big-switch-statements-in-javascript-without-performance-problemsEsailija 给了我一个很好的答案这条线 https://github.com/v8/v8/blob/596d0ce7b7a3900c529025aaa77e5fc39162c8c5/src/hydrogen.cc#L3350在V8源代码中。它将 switch 语句的优化限制在特定大小以下。我的模拟器做的第一件事是为操作码分配 256 个条目的开关。在我的测试中,我只通过了 0 (NOP),因此可以安全地注释掉大量案例。事实证明,如果我注释掉其中 13 个案例,性能就会提升 25 倍!如果我只注释掉其中 12 个案例,那么性能就会很慢。
上面的 V8 源代码链接相当古老(2013 年),所以我试图找到现代的等效链接。我没有找到硬性限制,但发现了几种在表查找和树(二分搜索)查找之间做出决定的启发式(ia32 https://github.com/v8/v8/blob/master/src/compiler/backend/ia32/instruction-selector-ia32.cc#L1575, x86 https://github.com/v8/v8/blob/master/src/compiler/backend/x64/instruction-selector-x64.cc#L2211)。当我插入我的数字时,我不太清楚找到它的边界情况,所以我不确定这是实际原因,或者是否有其他优化没有在其他地方触发。
至于与 Chrome 的区别,他们决定优化开关的时间和方式可能存在一些细微的差异。
我不确定这里最好的解决方案是什么,但显然我需要避免大型 switch 语句。我要么拥有一系列较小的 switch 语句,要么用一组函数替换整个内容。
更新:我使用了一系列函数,整个程序的速度提高了 25 倍。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)