nodejs / v8 flamegraph中使用perf_events的未知事件

我试着用Brendan Gregg 在这里描述的使用Linux perf_event进行nodejs分析。

工作stream程如下:

  1. 使用--perf-basic-prof运行节点> 0.11.13,它会创build/tmp/perf-(PID).map JavaScript符号映射的/tmp/perf-(PID).map文件。
  2. 使用perf record -F 99 -p `pgrep -n node` -g -- sleep 30捕获堆栈perf record -F 99 -p `pgrep -n node` -g -- sleep 30
  3. 使用此库中的stackcollapse-perf.pl脚本折叠堆栈
  4. 使用flamegraph.pl脚本生成svg火焰图

我得到以下结果(开头看起来非常好): 在这里输入图像描述

问题是有很多[unknown]元素,我想应该是我的nodejs函数调用。 我假设整个过程在第3点失败,其中perf数据应该使用由--perf-basic-prof执行的node / v8生成的映射来折叠。 创build/tmp/perf-PID.map文件,并在节点执行过程中向其写入一些映射。

如何解决这个问题?

我正在使用CentOS 6.5 x64,并且已经尝试使用节点0.11.13,0.11.14(包括预构build和编译),但都没有成功。

首先,“[unknown]”是指采样器无法弄清函数的名称,因为它是一个系统或库函数。 如果是这样,那就没问题 – 你不在乎,因为你正在寻找代码中的时间,而不是系统代码。

实际上,我认为这是XY问题之一 。 即使你直接回答你提出的问题,也可能没什么用处。 原因如下:

1. CPU分析在I / O绑定程序中几乎没有用处

火焰图中左边的两个塔正在做I / O,所以他们可能比右边的那个大的墙要花费更多的时间。 如果这个火焰图来源于墙壁时间样本,而不是CPU时间样本,它可能看起来更像下面的第二张图,它告诉你实际时间在哪里:

在这里输入图像描述

右边一大堆多汁的东西已经缩小了,所以远不及那么重要。 另一方面,I / O塔非常宽。 如果在你的代码中,那么这些宽的橙色条纹中的任何一个,如果能够避免一些I / O,就可以节省很多时间。

2.程序是CPU还是I / O限制,加速机会可以很容易地隐藏火焰图

假设Foo有一些function确实在做一些浪费,如果你知道这个function,你可以修复。 假设在火焰图中,它是深红色的。 假设它是从代码中的很多地方调用的,所以它并不是全部收集在火焰图中的一个点上。 而是出现在这里用黑色轮廓显示的多个小地方:

在这里输入图像描述

注意,如果所有这些矩形都被收集起来了,你可以看到它占了11%的时间,这意味着值得一看。 如果你能把时间缩短一半,总体上可以节省5.5%。 如果实际上完全可以避免这样做,那么总共可以节省11%。 这些小矩形中的每一个都会缩小到什么程度,并将其余部分拉到右边。

现在我会告诉你我使用的方法 。 我采取适量的随机堆栈样本,并检查每个可能加速的例程。 这相当于在火焰图中采样,如下所示:

在这里输入图像描述

纤细的垂直线代表20个随机时间堆栈样本。 正如你所看到的,其中三个是用X标记的。 那些是通过Foo 。 这就是正确的数字,因为20%的11%是2.2。

(困惑了,好吧,这里有一点可能性,如果你掷硬币20次,有11%的几率上来,你会得到多less头?从技术上讲,这是一个二项式分布。会得到是2,接下来最有可能的数字是1和3.(如果你只得到1,你继续前进,直到你得到2)。这是分配:)

在这里输入图像描述

(两次看Foo的平均样本数是2 / 0.11 = 18.2个样本。)

看这20个样本可能看起来有点令人生畏,因为它们的深度在20到50之间。 但是,基本上可以忽略所有不属于你的代码 。 只要检查他们的代码 。 你会清楚地看到你如何花时间,你会有一个非常粗略的测量多less。 深度堆栈既是坏消息,也是好消息 – 它们意味着代码可能有很多的加速空间, 而且它们会告诉你这些是什么。

任何你看到你可以加速的东西, 如果你看到一个以上的样本 ,会给你一个健康的加速,保证。 你需要在一个以上的样本上看到它的原因是,如果你只在一个样本上看到它,你只知道它的时间不是零。 如果你看到一个以上的样本,你仍然不知道需要多less时间,但是你知道这个数目不算less。 这里是统计。

一般来说,不同意主题专家是一个不好的主意,但我们在这里(最大的尊重),我们走!

所以SO敦促答复做以下事情:

“请务必回答这个问题,提供详细信息并分享您的研究成果!”

所以问题是,至less我的解释是,为什么在脚本输出中有[未知]帧(以及如何将这些[未知]帧转换为有意义的名称)? 这个问题可能是关于“如何提高我的系统的性能?” 但在这种情况下我不这么看。 这里有一个真正的问题,关于如何后处理的性能logging数据。

问题的答案是,尽pipe设置的先决条件是正确的:正确的节点版本,正确的参数是为了生成函数名称(–perf-basic-prof)而存在的, 生成的perf映射文件必须由root用于执行脚本以产生预期的输出。

而已!

今天写一些新的脚本,我打了这个指导我这个问题。

这里有几个额外的参考:

https://yunong.io/2015/11/23/generating-node-js-flame-graphs/

https://github.com/jrudolph/perf-map-agent/blob/d8bb58676d3d15eeaaf3ab3f201067e321c77560/bin/create-java-perf-map.sh#L22

[非根文件有时可能被迫] http://www.spinics.net/lists/linux-perf-users/msg02588.html