在 node.js --prof 输出中,这个名字奇怪的 C++ 函数在做啥?

Posted

技术标签:

【中文标题】在 node.js --prof 输出中,这个名字奇怪的 C++ 函数在做啥?【英文标题】:In node.js --prof output, what is this strangely-named C++ function doing?在 node.js --prof 输出中,这个名字奇怪的 C++ 函数在做什么? 【发布时间】:2020-02-25 05:10:38 【问题描述】:

我正在分析一个经过大量修改的 JS Interpreter 分支,在 node.js v12.12.0 上运行,使用 --prof,同时它运行一个简短的综合基准测试。在 `node --prof-process 的输出中,我看到 63% 的程序运行时花费在 C++ 中:

 [Summary]:
   ticks  total  nonlib   name
   1503   35.6%   35.9%  javascript
   2658   63.0%   63.4%  C++
    119    2.8%    2.8%  GC
     30    0.7%          Shared libraries
     29    0.7%          Unaccounted

特别是,有一个 C++ 函数占整个运行时的 59%:

 [C++]:
   ticks  total  nonlib   name
   2504   59.3%   59.8%  t __ZN4node9inspector8protocol11NodeRuntime14DispatcherImplD1Ev
     27    0.6%    0.6%  T node::native_module::NativeModuleEnv::CompileFunction(v8::FunctionCallbackInfo<v8::Value> const&)
     23    0.5%    0.5%  T _proc_set_dirty
     16    0.4%    0.4%  T __kernelrpc_vm_remap
      9    0.2%    0.2%  t __malloc_initialize
      9    0.2%    0.2%  T _thread_get_state
      8    0.2%    0.2%  T node::contextify::ContextifyContext::CompileFunction(v8::FunctionCallbackInfo<v8::Value> const&)
  ...

不幸的是,我不太清楚__ZN4node9inspector8protocol11NodeRuntime14DispatcherImplD1Ev 可能在做什么。

顾名思义,它与检查器协议有关,但我没有使用--inspect 命令行标志,也没有尝试使用检查器附加到正在运行的进程。

李>

我似乎在 node.js 源代码中找不到任何同时包含字符串“NodeRuntime”和“DispatcherImpl”的文件。

它似乎是从几个不同的地方调用的,最常见的是从自身递归调用(列表被修剪以主要显示***条目),但命名的 JavaScript 函数没有任何明显的共性:

 [Bottom up (heavy) profile]:
  Note: percentage shows a share of a particular caller in the total
  amount of its parent calls.
  Callers occupying less than 1.0% are not shown.

   ticks parent  name
   2504   59.3%  t __ZN4node9inspector8protocol11NodeRuntime14DispatcherImplD1Ev
   1287   51.4%    t __ZN4node9inspector8protocol11NodeRuntime14DispatcherImplD1Ev
    785   61.0%      LazyCompile: *intrp.Object.defineProperty /Users/cpcallen/src/CodeCity/server/interpreter.js:4477:51
    226   17.6%      LazyCompile: *intrp.UserFunction.instantiateDeclarations /Users/cpcallen/src/CodeCity/server/interpreter.js:4840:66
     67    5.2%      LazyCompile: *intrp.Object.getOwnPropertyDescriptor /Users/cpcallen/src/CodeCity/server/interpreter.js:4455:61
     34    2.6%      t __ZN4node9inspector8protocol11NodeRuntime14DispatcherImplD1Ev
     22    1.7%      LazyCompile: *stepFuncs_.MemberExpression /Users/cpcallen/src/CodeCity/server/interpreter.js:6582:42
    278   11.1%    LazyCompile: *Interpreter.run /Users/cpcallen/src/CodeCity/server/interpreter.js:290:37
    140    5.6%    LazyCompile: *stepFuncs_.Identifier /Users/cpcallen/src/CodeCity/server/interpreter.js:6494:36
    121    4.8%    LazyCompile: *intrp.UserFunction.instantiateDeclarations /Users/cpcallen/src/CodeCity/server/interpreter.js:4840:66
     91    3.6%    LazyCompile: ~runBench /Users/cpcallen/src/CodeCity/server/tests/interpreter_bench.js:37:18
     79    3.2%    LazyCompile: *intrp.UserFunction.call /Users/cpcallen/src/CodeCity/server/interpreter.js:4782:47
     65    2.6%    LazyCompile: *Interpreter.getBoundNames_ /Users/cpcallen/src/CodeCity/server/interpreter.js:2907:48
     62    2.5%    LazyCompile: *stepFuncs_.CallExpression /Users/cpcallen/src/CodeCity/server/interpreter.js:6039:40

我想知道它是否真的是垃圾收集器,但使用 --trace-gc 表明 GC 占用的运行时间不到总运行时间的 10%。

我怎样才能知道这个 C++ 函数在做什么?

【问题讨论】:

【参考方案1】:

找到DispatcherImpl 并不难:https://github.com/nodejs/node/search?q=dispatcherimpl&unscoped_q=dispatcherimpl 直接指向https://github.com/nodejs/node/blob/5aaa7fee2e4a075d9123b885f9e8cda3de2a780a/tools/inspector_protocol/templates/TypeBuilder_cpp.template#L218。但这可能不是你真正想要的......

在一段时间内,--prof 系统中存在一个错误,C++ 滴答声会归因于错误的函数——看起来您可能会遇到这种情况。一直是fixed in V8 recently,但该修复尚未发布到 Node 版本中。

作为一种解决方法,在 Linux 上,您可以使用 perf 来分析 C++ 代码 [1],同时仍将 --prof 用于 JavaScript; --prof 的输出中的 JavaScript 滴答声以及 C++/JavaScript 分布应该是可靠正确的。在其他平台上应该有等效的通用分析技术。

[1] 有关详细信息,请阅读手册页。我通常使用类似的东西:

perf record -e cycles -F 10000 <executable and arguments>
perf report -M intel

【讨论】:

这非常有帮助,谢谢。我碰巧在 macOS 上,但看起来它也受到了影响,尽管提交描述的问题是“--prof/linux-tick-processor 中的错误”。 不幸的是,perf report 的输出信息量不是很大;列出的顶部函数是Builtins_LoadIC_Megamorphic,仅占样本的 6.75%。也许这是正确的——这比单个 C++ 函数占用 60% 以上的 CPU 更有意义——但它并没有为主要的性能提升提供任何明显的途径。

以上是关于在 node.js --prof 输出中,这个名字奇怪的 C++ 函数在做啥?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 java -prof 选项获取在 Tomcat 上运行的 java 程序的分析输出?

没有 v8-profiler 的 Node.js 内存泄漏搜索

通过火焰图分析 Node.js 性能(Mac 上)

Mac升级node/npm

在Node.js中使用ejsexcel输出EXCEL文件

Mac 升级node与npm