Hotspot:用于性能分析的 Linux `perf` GUI
KDAB/hotspot
用于性能分析的 Linux perf
GUI。
这个项目是 KDAB 的一项研发工作,旨在创建一个独立的 GUI 用于性能数据分析。首要目标是提供一个类似于 KCachegrind 的用户界面,围绕 Linux perf
构建。展望未来,我们计划支持各种其他性能数据格式。
目录
截图
以下是一些截图,展示了 Hotspot 最重要的功能:
可视化数据
Hotspot 的主要功能是对 perf.data
文件进行图形化可视化。
注意:内联函数具有比非内联函数更深的边框颜色。
时间线
时间线允许按时间、进程或线程过滤结果。数据视图将相应更新。
记录数据
您还可以从 Hotspot 启动 perf
,以分析新启动的应用程序或附加到已在运行的进程。但请注意下面的警告。
获取 Hotspot
注意:Hotspot 尚未在所有 Linux 发行版上打包。在这种情况下,或者如果您想使用最新版本,请使用 AppImage,它可以在任何最新的 Linux 发行版上正常工作。
ArchLinux
Hotspot 在 AUR 中可用 (https://aur.archlinux.org/packages/hotspot)。
Debian / Ubuntu
Hotspot 在 Debian (https://packages.debian.org/hotspot) 和 Ubuntu (https://packages.ubuntu.com/hotspot) 中可用。
Gentoo
Hotspot 的 ebuilds 可从我们的 overlay (https://github.com/KDAB/kdab-overlay) 获得。
Fedora
Hotspot 在 Fedora (https://packages.fedoraproject.org/pkgs/hotspot/hotspot/) 中可用。
适用于任何 Linux 发行版: AppImage
您可以前往最新的 current release 或 continuous build。在这两种情况下,您都可以在“Assets”下找到可以下载的 AppImage。解压 AppImage 文件(如果是最新版本),然后使其可执行,然后运行它。
请使用最新的构建版本以获取最新版本。如果它不起作用,请报告一个错误并测试最新的稳定版本。
注意:您的系统库或首选项未被更改。如果您想再次删除 Hotspot,只需删除下载的文件。了解更多关于 AppImage 的信息这里。
要了解如何调试 AppImage,请参阅 HACKING。
构建 Hotspot
从源代码构建 Hotspot 可以让您获得最新版本,但您必须确保所有依赖项都可用。大多数用户应该从发行版包管理器安装 Hotspot或作为 AppImage。
对于每个想要为 Hotspot 做出贡献或使用最新版本而无需 AppImage 的人,可以在 HACKING 中找到详细说明。
使用
General
首先,使用 perf
记录一些数据。要获取回溯,您需要启用 dwarf callgraph 模式:
perf record --call-graph dwarf <your application>
...
[ perf record: Woken up 58 times to write data ]
[ perf record: Captured and wrote 14.874 MB perf.data (1865 samples) ]
现在,如果您的同一台机器上安装了 Hotspot,您只需启动它即可。它将自动打开当前目录中的 perf.data
文件(类似于 perf report
)。
或者,您可以在控制台上指定数据文件的路径:
hotspot /path/to/perf.data
命令行选项
根据您的需求,您可能需要将其他命令行选项传递给 Hotspot。这允许一次性设置在 GUI 的“设置”下找到的配置选项,并且还允许将 Linux perf 数据文件转换为更小且可移植的 perfdata 格式(有关详细信息,请参阅 Import / Export)。所有命令行选项都显示为 --help
:
Usage: hotspot [options] [files...]
Linux perf GUI for performance analysis.
Options:
-h, --help Displays help on commandline options.
--help-all Displays help including Qt specific options.
-v, --version Displays version information.
--sysroot <path> Path to sysroot which is used to find libraries.
--kallsyms <path> Path to kallsyms file which is used to resolve
kernel symbols.
--debugPaths <paths> Colon separated list of paths that contain debug
information. These paths are relative to the
executable and not to the current working directory.
--extraLibPaths <paths> Colon separated list of extra paths to find
libraries.
--appPath <path> Path to folder containing the application executable
and libraries.
--sourcePaths <paths> Colon separated list of search paths for the source
code.
--arch <path> Architecture to use for unwinding.
--exportTo <path> Path to .perfparser output file to which the input
data should be exported. A single input file has to
be given too.
--perf-binary <path> Path to the perf binary.
--objdump-binary <path> Path to the objdump binary.
Arguments:
files Optional input files to open on startup, i.e.
perf.data files.
Off-CPU Profiling
Hotspot 支持一种非常强大的等待时间分析方法,即 off-CPU profiling。此分析基于 linux 调度器中的内核 tracepoints。通过记录这些数据,我们可以找到线程未在 CPU 上运行的时间间隔,而是处于 off-CPU 状态。造成这种情况的原因有很多,所有这些都可以使用此技术找到:
- 同步 I/O,例如通过
read()
或write()
- 页面错误,例如在访问
mmap()
'ed 文件数据时 - 调用
nanosleep()
或yield()
- 通过
futex()
等的锁争用 - 抢占
- 可能还有更多
通过利用调度器中的内核 trace points,开销非常可控,并且我们仅在进程实际切换出去时才付出代价。最值得注意的是,当例如 mutex 锁操作可以在用户空间中直接处理时,我们不会付出代价。
要使用 Hotspot 进行 off-CPU 分析,您需要使用非常特定的命令记录数据:
perf record \
-e cycles \ # on-CPU profiling
-e sched:sched_switch --switch-events \ # off-CPU profiling
--sample-cpu \ # track on which core code is executed
-m 8M \ # reduce chance of event loss
--aio -z \ # reduce disk-I/O overhead and data size
--call-graph dwarf \ # we definitely want backtraces
<your application>
或者,您可以使用 Hotspot 集成记录页面中的 off-CPU 复选框。
在分析期间,您可以在用于 on-CPU 数据的“cycles”成本视图与用于等待时间分析的“off-CPU time”成本视图之间切换。通常,您希望在两者之间切换,例如,在代码中找到可能需要进一步并行化的位置(另请参见 [Amdahl's law](https://github.com/KDAB/</https:/en.wikipedia.org/wiki/Amdahl%27s_law>)。
“sched:sched_switch”成本也会显示给您。但在我看来,这不太有用,因为它仅指示调度器切换的数量。两者之间的时间长度通常更有趣 - 这就是在“off-CPU time”指标中向您显示的内容。
嵌入式系统
如果您在嵌入式系统上进行录制,您可能希望在您的开发机器上使用 Hotspot 分析数据。为此,请确保您的 sysroot 包含 unwinding 所需的调试信息(见下文)。然后在您的嵌入式系统上记录数据:
embedded$ perf record --call-graph dwarf <your application>
...
[ perf record: Woken up 58 times to write data ]
[ perf record: Captured and wrote 14.874 MB perf.data (1865 samples) ]
embedded$ cp /proc/kallsyms /tmp/kallsyms # make pseudo-file a real file
如果您的嵌入式机器使用与主机不同的平台也没关系。在您的主机上,执行以下步骤来分析数据:
host$ scp embedded:perf.data embedded:/tmp/kallsyms .
host$ hotspot --sysroot /path/to/sysroot --kallsyms kallsyms \
perf.data
如果您从 sysroot 外部的路径手动部署了应用程序,请改为执行以下操作:
host$ hotspot --sysroot /path/to/sysroot --kallsyms kallsyms --appPath /path/to/app \
perf.data
如果您的应用程序也使用 sysroot 和 appPath 之外的库,请执行以下操作:
host$ hotspot --sysroot /path/to/sysroot --kallsyms kallsyms --appPath /path/to/app \
--extraLibPaths /path/to/lib1:/path/to/lib2:... \
perf.data
最坏的情况是,如果您还在非标准位置使用拆分调试文件,请执行以下操作:
host$ hotspot --sysroot /path/to/sysroot --kallsyms kallsyms --appPath /path/to/app \
--extraLibPaths /path/to/lib1:/path/to/lib2:... \
--debugPaths /path/to/debug1:/path/to/debug2:... \
perf.data
导入导出
perf.data
文件格式不是自包含的。要分析它,您需要访问已分析进程的可执行文件和库,以及调试符号。这使得在机器之间共享此类文件变得笨拙,例如,从同事那里获得帮助来调查性能问题或用于错误报告目的。
Hotspot 允许您导出已分析的数据,该数据是完全自包含的。此功能可通过“文件 > 另存为”菜单操作访问。然后,数据以自包含的 *.perfparser
文件保存。要再次将数据导入到 Hotspot 中,只需直接打开该文件,而不是原始的 perf.data
文件。
作为替代方案,您也可以从命令行执行导出(没有 GUI,因此也可用于自动构建),使用 --exportTo
选项。
注意: 文件格式_尚未_稳定。这意味着由一个版本的 Hotspot 导出的数据只能由同一版本读回。这个问题将在将来解决,因为时间允许。
tracepoints
Hotspot 目前仅在时间线中显示 tracepoints 的名称。
反汇编器
Hotspot 包括一个反汇编器,可以显示每个指令的成本。反汇编器使用颜色来指示哪些汇编行对应于哪些源代码行。为了更易于导航,您可以简单地单击一行,另一个视图将跳转到它。您可以通过双击来跟踪函数调用。在源代码视图中,您可以按 ctrl+f 或按搜索图标来打开搜索窗口。
如果您在不同的目录中有源文件,您可以使用 --sourcePaths
或设置来告诉反汇编器在那里搜索源代码。
已知问题
如果在上述任何一项中断并且输出不如 perf report
可用,请在 GitHub 上报告问题。也就是说,人们可能会遇到一些已知问题:
损坏的回溯
展开堆栈以生成回溯是一门黑魔法,并且可能会以多种方式出错。Hotspot 依赖于 perfparser
(见下文),后者又依赖于 elfutils 中的 libdw
来展开堆栈。这在大多数情况下效果很好,但仍然可能会出错。最值得注意的是,当:
-
perf.data
文件引用的 ELF 文件(即可执行文件或库)丢失时,unwinding 将失败。- 要解决此问题,请尝试使用以下 CLI 参数之一,让 Hotspot 知道在哪里查找 ELF 文件:
--debugPaths <paths>
:当您在非标准位置有拆分调试文件时使用此选项。--extraLibPaths <paths>
:当您自录制以来已将库移动到其他位置时使用此选项。--appPath <paths>
:这是上述两个字段的一种组合。该路径被递归遍历,查找调试文件和库。--sysroot <path>
:当您尝试检查在嵌入式平台上录制的数据文件时使用此选项。
- 要解决此问题,请尝试使用以下 CLI 参数之一,让 Hotspot 知道在哪里查找 ELF 文件:
-
ELF 文件缺少调试信息
- 要解决此问题,请从您的发行版安装调试包。
- 或者在“release with debug”模式下编译代码,即确保您的编译器使用类似
-O2 -g
的选项调用。您必须重复perf record
步骤。 - 潜在地,上述两种方法都不是您的选择,例如,当库是闭源的并且由第三方供应商提供时。如果是这种情况,您可能会很幸运,并且该库包含帧指针。如果是这样,请尝试从当前的 git master 构建 elfutils(您需要提交 a55df2c1,它应该是 0.170 的一部分)。此版本的 elfutils 将尝试回退到帧指针进行 unwinding,当调试信息丢失时。
-
您的调用堆栈太深
- 默认情况下,
perf record
仅将堆栈的一部分复制到数据文件。这可能会导致非常深的调用堆栈出现问题,这些调用堆栈将在某个点被截断。此问题将破坏 Hotspot 中的自上而下的调用树,如 Top-Down 视图或火焰图中所示。要解决此问题,您可以尝试增加堆栈转储大小,即:
perf record --call-graph dwarf,32768
请注意,这会显着增加
perf.data
文件的大小 - 请谨慎使用。另请查看man perf record
。- 对于某些场景,递归函数调用只是无法 unwind。另请参见 #93。
- 默认情况下,
debuginfod
Hotspot 支持通过 debuginfod 下载调试符号。可以通过在设置中添加下载 URL 或在环境中定义 DEBUGINFOD_URLS
来启动 Hotspot 来启用此功能。
缺失的功能
与 perf report
相比,Hotspot 缺少很多功能。其中一些计划在将来解决。其他可能永远不会实现。但请注意,以下功能目前在 Hotspot 中_不可用_:
- 表中的列目前是硬编码的,而用户可能希望更改此设置以显示例如每个进程或线程的成本等等。添加了基本的分组功能,但目前没有计划进行更灵活的列安排(如 WPA)。
- 许多更高级的功能,例如
--itrace
、--mem-mode
、--branch-stack
和--branch-history
都不受支持。
在没有超级用户权限的情况下使用 perf 记录
使用 sudo
或作为 root
用户启动 Hotspot 不是一个好主意。有关此问题的文章,请参见例如以 Root 身份编辑文件。问题 #83 也与此联系相关。
但是,如果没有超级用户权限,您在使用 Hotspot 的记录功能时可能会看到如下错误消息:
You may not have permission to collect stats.
Consider tweaking /proc/sys/kernel/perf_event_paranoid:
-1 - Not paranoid at all
0 - Disallow raw tracepoint access for unpriv
1 - Disallow cpu events for unpriv
2 - Disallow kernel profiling for unpriv
为了解决此限制,Hotspot 可以使用提升的权限运行 perf 本身。
导出文件格式
当前的数据导出仅限于可以由相同版本的 Hotspot 读回的格式。这使得与其他可视化工具的互操作几乎不可能。这是已知的,并且将在将来得到改进。最值得注意的是,计划但尚未实现对导出到 Web 查看器(如 perfetto 或 Mozilla profiler)的支持。欢迎补丁!
Qt Creator
此项目利用了由 The Qt Company 为其 Qt Creator IDE 创建的出色的 perfparser
实用程序。如果您已经在使用 Qt Creator,请考虑利用其集成的 CPU 使用率分析器。
许可证
Hotspot 在 GPL v2+ 下获得许可。有关更多信息,请参见 LICENSE.GPL.txt,或者如果此许可的任何条件对您不清楚,请联系 info@kdab.com。