【问题标题】:Thread Utilization profiling on linuxlinux上的线程利用率分析
【发布时间】:2017-12-28 07:17:16
【问题描述】:

Linux perf-tools 非常适合在 CPU 周期中查找热点并优化这些热点。但是,一旦某些部分被并行化,就很难发现顺序部分,因为它们占用了大量的时间,但不一定需要很多 CPU 周期(并行部分已经在消耗这些时间)。

为了避免 XY 问题:我的基本动机是在多线程代码中找到顺序瓶颈。即使由于amdahl's law,顺序阶段在墙上时间中占主导地位,并行阶段也可以轻松主导总体 CPU 周期统计数据。

对于 java 应用程序,这很容易通过具有线程利用时间线的 visualvm 或 yourkit 实现。

请注意,它会显示选定范围或时间点的线程状态(可运行、等待、阻塞)和堆栈样本。

如何在 Linux 上实现与 perf 或其他本机分析器相当的功能?它不一定是 GUI 可视化,只是一种查找顺序瓶颈和与之相关的 CPU 样本的方法。

另请参阅,更窄的followup question 专注于perf

【问题讨论】:

  • 带有时间线的屏幕截图来自跟踪工具,而不是来自分析工具。检查 kernelshark+trace-cmd 或 LTTng 跟踪器以获取 the same。 perf 是通用的,即使在默认模式下(使用 perf 脚本打印),它也可能在 perf.data 中包含一些信息;但有关线程调度的确切信息,它还应该跟踪 sched_* 事件。并且 perf 通常只分析在 CPU 上运行的线程(尤其是当您不在 AWS 或其他虚拟化上并且可能使用硬件计数器“周期”时),而不是墙时间。
  • @osgx 好吧,当线程脱离 CPU 时,我可以不用样本。原则上,我只想弄清楚它在单个线程上花费时间(〜=获取样本)期间的作用。这可能是一个 XY 问题。我的目标是找到单线程瓶颈。对我来说最明显的方法是在每个线程的基础上可视化堆栈样本。
  • perf 的默认模式是 CPU 采样分析。尝试交互式perf report 文本用户界面或“关注”某些线程的选项:perf record -g -F 99 -s ./your_program; perf report -Tperf report -T --tid=$TID 其中 $TID 是一个线程的 pid 或逗号分隔列表。我没有测试 -s/-T 选项来拆分线程统计信息,但它们已记录在案:man7.org/linux/man-pages/man1/perf-record.1.htmlman7.org/linux/man-pages/man1/perf-report.1.html;每个线程是默认模式:perf.wiki.kernel.org/index.php/Tutorial#Collecting_samples
  • @osgx 除非我遗漏了一些没有帮助的东西,因为它们只提供汇总统计信息。我感兴趣的不是聚合,而是只有一个线程处于活动状态的样本子集。基本上,我对代码已经并发的时间不感兴趣,但那些在报告中占主导地位的时间,即使它们可能不会主导墙壁时间。这就是 java 中的那些线程时间线视图所提供的(它们还显示特定时间片的线程堆栈 - 未在屏幕截图中显示 - 但对于弄清楚一切很重要)
  • 英特尔 VTune 支持这种类型的可视化。但它只对学生和教育工作者免费。

标签: linux multithreading performance profiling perf


【解决方案1】:

Oracle's Developer Studio Performance Analyzer 可能完全符合您的要求。 (如果您在 Solaris 上运行,我知道它完全符合您的要求,但我从未在 Linux 上使用过它,而且我现在无法访问 Linux 系统适合试穿)。

这是在 x86 Solaris 11 系统上运行的多线程 IO 测试程序的屏幕截图:

请注意,您可以看到每个线程的调用堆栈以及线程如何交互 - 在发布的示例中,您可以看到实际执行 IO 的线程从哪里开始,并且您可以将每个线程视为他们表演。

这是一个准确显示线程 2 在突出显示时刻的位置的视图:

此视图启用了同步事件视图,显示线程 2 在突出显示的时间段内卡在 sem_wait 调用中。注意额外的图形数据行,显示同步事件(sem_wait()pthread_cond_wait()pthread_mutex_lock() 等):

其他视图包括调用树:

线程概述(只有少数线程时不是很有用,但如果您有数百个或更多线程可能非常有用

以及显示函数 CPU 利用率的视图

而且你可以看到每一行代码花费了多少时间:

不出所料,写入大文件以测试 IO 性能的进程几乎将所有时间都花在了 write() 函数中。

完整的 Oracle 简介位于 https://www.oracle.com/technetwork/server-storage/solarisstudio/documentation/o11-151-perf-analyzer-brief-1405338.pdf

快速使用概览:

【讨论】:

  • 其他视图似乎不受时间线的限制,或者是吗?如果不是,那么它们就不能用于向下钻取到单线程的时间范围。
  • @the8472 好吧,您可以在时间轴视图上查看线程之间发生的情况。我添加了一个可见同步事件的视图。您可以看到突出显示的线程在 sem_wait() 中等待。不确定您所说的“按时间线划分”是什么意思。您是否正在寻找诸如基于时间线选择使用了多少 CPU 时间之类的数据?
  • 那种。我真正想要的是查看应用程序未完全并行化的运行线程的堆栈示例。瓶颈。当其他人在时间轴上空闲时寻找一个活动线程,然后选择该范围并获取该范围的聚合统计信息将是我使用我熟悉的 java 工具执行此操作的方式。进行过滤的其他方法也可以,或者实际上更好,因为选择一次只会给我带来一个瓶颈,而不是整体统计数据。
  • 我认为我添加的示例 - screenshot - 显示了这一点。这显示线程 2 在sem_wait() 中被阻塞,甚至显示了确切的代码行。根据我的经验,这是查找非并行瓶颈的最佳方法 - 您查看时间线视图,您只需查看几乎每个线程都阻塞的时间范围。
  • got it to work 经过一些障碍。它想要一个古老的 java 版本并挂在带有 jemalloc 的应用程序上,我不得不用 glibc malloc 重新编译。
【解决方案2】:

您可以使用我们用来分析 Off-CPU 分析的出色工具获得您想要的结果 - Off-CPU Flame GraphsFlame Graphs 的一部分

我用Off-CPU analysis

Off-CPU 分析是一种性能方法,其中测量和研究非 CPU 时间以及堆栈跟踪等上下文。它与 CPU 分析不同,后者仅检查在 CPU 上执行的线程。

此工具基于您提到的首选工具 - perf、bcctools,但是,它提供了一个非常易于使用的输出,称为火焰图,交互式 SVG 文件类似于 SVG Off-CPU Time Flame Graph

宽度与代码路径中的总时间成正比,因此首先寻找最宽的塔以了解最大的延迟来源。从左到右的排序没有意义,y轴为栈深度。

作为 Off-CPU Flame Graphs 一部分的另外两个有用的分析也可以帮助您 - 就我个人而言,我没有尝试过。

Wakeup

这让我们能够解决比单独跟踪 CPU 更多的问题,因为唤醒信息可以解释阻塞的真正原因。

还有Chain Graph

链图是一种实验性可视化,将 CPU 外堆栈与其唤醒堆栈相关联

还有一个实验可视化,结合了 CPU 和 Off-CPU 火焰图Hot/Cold Flame Graphs

这会在一张图表中显示所有线程时间,并允许在 CPU 上和 CPU 外的代码路径持续时间之间进行直接比较。

阅读有关此分析工具并了解其概念需要一点时间,但是,使用它非常简单,并且它的输出比您上面提到的其他工具更容易分析。

祝你好运!

【讨论】:

  • 这不是我想要的。我不希望线程样本被取消调度,这通常只会显示 IO 等待或具有空工作队列的线程池堆栈。我想要 CPU 上的样本,但前提是它运行的线程少于 N 个。或按空闲核心数加权的样本。基本上它必须回答“我必须加快或消除哪些代表单线程的调用堆栈才能恢复并行执行”的问题。即使是唤醒器部分也只显示了唤醒的直接堆栈,而不是之前必须完成的所有计算。
  • @the8472:在超线程 Intel CPU 上,cpu_clk_unhalted.one_thread_active 有一个性能计数器,当线程有自己的核心时,它会计时。这可以帮助找到在使用少于最大内核数时运行的代码。还有针对cstate_core/c3-residency/ 和c6、c7 的Linux perf 事件,因此您可以计算整个内核空闲一段时间的时间。 (但我不认为这可以帮助您找到 正在在其他内核上运行的代码。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-08
  • 1970-01-01
  • 2011-01-30
相关资源
最近更新 更多