火焰图

    或许你已经听说对于 Node.js,创建火焰图不是非常容易,但是那并不是真的(永远不会)。我们再也不需要 Solaris vms 创建火焰图了!

    火焰图通过 输出,这并不是一个 node 所指定的工具。即便它是把 CPU 耗时可视化的最佳工具,它仍然存在一些问题 —— 如在 Node.js 8 和之后版本中 JavaScript 编码是如何优化的。欲了解详情可以看perf 输出的问题这部分。

    如果你想在本地开始单一输出火焰图,请尝试

    如果你想诊断发布的生产环境,请阅读在生产环境中的 0x

    用系统工具 pref 创建火焰图

    本教程的目的在于给你展示如何创建火焰图的具体步骤,这样让你可以对每一步都有掌控。

    如果你更好地想理解每一个步骤,请仔细看这些步骤,我们将详细阐述。

    现在让我们开始吧:

    1. 尝试运行 perf - 或许会告诉你缺少内核模块,请同样安装他们。

    2. 启用 pref 并运行 node(具体参考 perf 输出的问题以此了解针对不同 Node.js 版本的建议)

    3. 忽略一些警告,除非它告诉你因为缺少必要的安装包而无法运行 pref,你可能会得到一些警告,告诉你不能访问内核模块的样本等。

    4. 如果没有安装 stackvis,请运行 npm i -g stackvis

    5. 最后运行 stackvis perf < perfs.out > flamegraph.htm

    现在你可以使用你最喜爱的浏览器打开火焰图文件,然后观察其燃烧状况。此图是带色编码的,因此你首先应该关注饱和度最深的橘色条。这些最有可能意味着你的 CPU 运行复杂函数消耗的状况。

    值得一提的是:如果你点击火焰图的一个元素,它周围相关的元素将被放大,并将显示在图形的上方。

    使用 perf 对一个运行的进程采样

    对于一个从已经运行、且不想被随意中断的进程中录制火焰图无疑是相当不错的。设想一下现在你有一个非常难重现问题的生产环境上的进程:

    先停一下,这里 sleep 3 是干什么的?它的目的是为了让 pref 持续运行 —— 尽管 -p 参数选项是让你指定一个不同的进程 ID(pid),此命令仍然需要在一个进程上执行,并随着它终止。perf 运行的是传递给它的命令的生存期,不管你是否实际分析该命令。sleep 3 确保此命令运行 3 秒。

    为什么 -F(采样频率)要被设置成 99?这是有默认原因的,当然你如果愿意可以任意设置。-F99 告诉 pref 每秒采样 99 个样本,目的是为了更精确地提高数值。越是低的数值意味着产出越是低的输出,相伴的也就是越是低精度的结果。你需要的精度取决于你的 CPU 运行多长时间的密集型函数。如果你正在寻找一个明显的减速的原因,那么 99 帧每秒应该是足够的。

    当你得到了那 3 秒 pref 生成的记录,请用以上步骤的最后 2 步处理生成火焰图。

    通常你只希望看到你自定义函数的调用性能如何,因此把 Node.js 和 V8 内置函数过滤掉,可以让你的图变得简单又容易看懂。你可以这样做:

    如果你现在读火焰图,就会觉得它看上去很怪 —— 花费了多数时间的主要函数就像丢了什么一样,你可以尝试不使用过滤参数,那么你也许得到一个罕见的情况下 Node.js 自身的问题。

    Node 的分析选项

    --perf-basic-prof:此二者函数对你的 JavaScript 调试有帮助,其余选项则用于分析 Node.js 自身,这已经超出了本章的范畴。

    为什么我需要这些参数?

    当然,如果没有这些参数的话,你照样可以得到火焰图。不过大部分的条状都将被标记为 v8::Function::Call

    Node.js 8.x 及以上版本使用了 V8 引擎,采用了新的优化 JavaScript 编译管道模式。这使得一些函数的名字、引用有时候无法被 perf 捕获到(这也被成为“Turbofan”)。

    导致的结果也就是在火焰图中你无法正确地得到一些函数名字。

    你或许会注意到 ByteCodeHandler:,在那儿可以得到你期盼得到的函数名字。

    0x 有一些对于此类情况的内置缓解措施。

    欲知详情,请了解以下内容:

    Node.js 10+

    Node.js 10.x 使用 --interpreted-frames-native-stack 标志解决了“Turbofan”的问题。

    运行 ,你就可以在火焰图中得到函数的名字,无论过去 V8 引擎使用那个管道编译你的 JavaScript。

    火焰图中受损的标签

    如果你看到诸如以下的标签:

    这意味着你正在运行的 Linux 的 perf 没有用 demangle 支持方法编译,请以 https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1396654 作为示例参考。

    请通过来练习捕获你的火焰图吧!