首页 > 解决方案 > 为什么 Node 比 Chrome 慢 10 倍?

问题描述

我正在 Chrome 和 Node.js 中运行我的Z80 模拟器。我在 Chrome 中的性能大约是在 Node.js 中的 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这个源文件。我没有在我的代码中使用承诺、、async或。await我的测试只是一个 100k 模拟 Z80 指令的紧密循环,没有 I/O 或任何东西。

我在网上找到了其他人使用该--prof标志,但没有人在他们的结果中找到这一点。这是分析的副作用吗?我是否在循环中以某种方式触发了承诺?有什么理由 Node 应该比 Chrome 慢这么多?

详细信息:节点 v12.13.1,Chrome 79.0.3945.88。

标签: node.js

解决方案


好的,这个令人惊讶的相似问题有一个很好的答案,Esailija 将我指向V8 源代码中的这一行。它将 switch 语句的优化限制在一定大小以下。我的模拟器做的第一件事是为操作码分配 256 个入口的开关。在我的测试中,我只通过了 0 (NOP),因此注释掉大量案例是安全的。事实证明,如果我注释掉 13 个案例,性能会提高 25 倍!如果我只注释掉 12 个案例,那么我会得到缓慢的性能。

上面 V8 源代码的链接很旧(2013 年),所以我试图找到现代的等价物。我没有找到硬性限制,但发现了几种在表查找和树(二进制搜索)查找(ia32x86)之间做出决定的启发式方法。当我插入我的数字时,我并没有完全找到找到它的临界案例,所以我不确定这是实际原因,或者是否有其他优化没有在其他地方触发。

至于与 Chrome 的区别,他们决定优化开关的时间和方式可能存在一些细微差别。

我不确定这里最好的解决方案是什么,但显然我需要避免使用大的 switch 语句。我要么有一系列较小的 switch 语句,要么用一组函数替换整个东西。

更新:我使用了一系列函数,我的整个程序加速了 25 倍。


推荐阅读