使用 perf 进行性能分析

来自 PostgreSQL Wiki
跳转到导航跳转到搜索

perf是添加到 Linux 内核 2.6.31 的一组实用工具。一个快速示例展示了 perf 输出的样子,位于 使用性能计数器进行 Linux 性能分析

如何进行性能分析

perf提供了两种主要模式:先记录后报告,或实时“top”模式。这两种模式在不同的情况下都很有用。

提示:在许多系统中,下面显示的 -g 可能需要写成 --call-graph dwarf 才能获得有效的堆栈跟踪。

先记录后报告

记录数据

要对系统进行特定时间段的性能分析,例如 60 秒

 perf record -a -g -s sleep 60

要对系统进行一个命令的持续时间的性能分析

 perf record -a -g -s -- pg_ctl -D pgdata start

要对系统进行性能分析,直到被取消,只需要省略任何命令

 perf record -a -g

默认情况下perf record将在当前工作目录中生成一个 perf.data 文件。

请参见“分析什么”以了解如何缩小记录范围。

报告

默认情况下perf report将在当前工作目录中查找 perf.data。

 perf report -n

如果已捕获,你可以使用以下命令包含调用图输出:

 perf report -g

perf report --call-graph

许多选项可用于对输出进行排序、过滤和聚合;请参见 perf 文档。

实时模式

 perf top

要对系统进行系统范围的实时性能分析

 perf top -z

要对系统进行实时性能分析,不累积统计信息,即瞬时性能分析你可以在perf top中使用常用的目标选择选项,但它最常用于系统范围的性能分析,使用.

perf top -a

故障排除许多系统在使用-g时,将生成不完整的调用图,只包含最顶层的堆栈条目,如果 PostgreSQL 二进制文件是用-fomit-frame-pointer编译的。这是 x64 上的默认设置。要解决此问题,你可以在支持 libunwind 的较新版本的上使用perf--call-graph dwarf。否则,你需要用.

-fno-omit-frame-pointer

perf重新编译 PostgreSQL。

 -a          whole system, all CPUs
 -p pid      one process ID
 -u user     processes for one user, e.g. "postgres"
 

分析什么perf record允许你用各种方式选择要分析的内容,其中最有用的是你可以在.

你可以将这些命令与

perf一起使用。编译的。这是 x64 上的默认设置。要解决此问题,你可以在支持 libunwind 的较新版本的包含用户空间堆栈perf record较新的许多系统在使用包含用户空间堆栈perf report版本支持捕获整个用户空间调用堆栈,而不仅仅是堆栈顶部的函数。这使它能够提供非常有用的调用图。使用

选项来启用此功能,并使用来显示结果。在 x64 主机上,你必须用perf./configure CFLAGS="-fno-omit-frame-pointer -ggdb" ...重新编译 PostgreSQL,或者使用用libunwind

支持构建的版本。

更多细节请参见 使用 perf 跟踪 PostgreSQL

跟踪点

perf 不限于 CPU 调用采样。它还可以跟踪系统调用、动态用户空间探测等。请参见sudo perf list

以查看事件并查找跟踪点事件。

 syscalls:sys_enter_fsync                           [Tracepoint event]

你可以通过此接口观察内核块层活动。例如,此事件

 perf top -e syscalls:sys_enter_fsync
 perf record -e syscalls:sys_enter_fsync -u postgres
 perf record -e syscalls:sys_enter_fsync -p $SOME_PID

可用于跟踪 fsync,例如

等等。

你可以在事件中使用通配符,并且可以使用多个以逗号分隔的事件或单独的 -e 参数。

PostgreSQL 预定义的跟踪点事件

 sdt_postgresql:buffer__sync__done                  [SDT event]
 sdt_postgresql:buffer__sync__start                 [SDT event]
 ...
 sdt_postgresql:checkpoint__done                    [SDT event]
 sdt_postgresql:checkpoint__start                   [SDT event]

PostgreSQL 通过 SDT(静态定义跟踪点)接口预定义了一些方便的 perf 事件,类似于 dtrace。这使你能够看到重要的 PostgreSQL 性能内部信息,例如如果你在perf listperf中没有看到这些事件,请参见 静态探测点 (gdb)perf-buildid-cache。启用探测点的确切步骤因版本而异。如果你看到关于perf sdt-cache

的提及,那么你正在阅读一些过时内容。此外:PostgreSQL 在内部使用 systemtap 在 Linux 上生成这些事件,因此你必须在构建时安装 systemtap 并将--enable-dtrace传递给configure

才能获得这些跟踪点。它们在 PGDG 二进制构建中默认启用。你必须使用perf probe

 # perf probe sdt_postgresql:query__execute__start
 Added new events:
   sdt_postgresql:query__execute__start (on %query__execute__start in /usr/pgsql-9.5/bin/postgres)
   sdt_postgresql:query__execute__start_1 (on %query__execute__start in /usr/pgsql-9.5/bin/postgres)
 
 You can now use it in all perf tools, such as:
 
 	perf record -e sdt_postgresql:query__execute__start_1 -aR sleep 1
 
 # perf record -e sdt_postgresql:query__execute__start,sdt_postgresql:query__execute__start_1 -a
 ^C[ perf record: Woken up 1 times to write data ]
 [ perf record: Captured and wrote 2.211 MB perf.data (2 samples) ]
 
 # perf script
       postgres 19995 [000] 430223.752970: sdt_postgresql:query__execute__start_1: (6c42e7)
       postgres 20003 [002] 430227.276924: sdt_postgresql:query__execute__start_1: (6c42e7)
 #

初始化 sdt 事件,然后再使用它们。perf probe 可能会报告多个事件名称,如以下示例所示。

添加新的跟踪点

在自己的构建中添加新的跟踪点非常简单。你只需编辑src/backend/utils/probes.d以添加跟踪点名称,然后添加宏以在希望它触发的任何位置调用它。跟踪点名称在probes.d中必须为小写,所有下划线都要加倍,并且没有前导的TRACE_POSTGRESQL_中必须为小写,所有下划线都要加倍,并且没有前导的。跟踪点调用是大写,单个下划线,并且以以添加跟踪点名称,然后添加宏以在希望它触发的任何位置调用它。跟踪点名称在TRACE_POSTGRESQL_

   probe transaction__start(LocalTransactionId);

开头。例如,包含,它在StartTransaction中被调用,位于

   TRACE_POSTGRESQL_TRANSACTION_START(vxid.localTransactionId);

src/backend/access/transam/xact.c以添加跟踪点名称,然后添加宏以在希望它触发的任何位置调用它。跟踪点名称在中,如下所示:

请注意,你不能使用 PostgreSQL 头文件提供的类型定义;该文件列出了自己的类型定义。

如果你认为它普遍有用,请向 pgsql-hackers 邮件列表提交补丁。如果不能用动态用户空间探测轻松实现相同的功能,并且它涉及到可能与更广泛的用户群相关的内容,那么跟踪点可能很有用。即使探测可以用动态跟踪点轻松完成,但如果它们可以作为文档来说明如何查找和跟踪许多人感兴趣的某些事件,那么它们仍然有用。

动态跟踪点

通常没有适合你的特定需求的 SDT 事件。但这没关系。如果你有调试符号和一个大致最近的 perf(已测试:Linux 4.4),你可以在需要的地方注入动态跟踪点,甚至可以捕获函数参数!例如,如果你想查看查询执行的速率,你可以在:

 perf probe -x /usr/lib/postgresql/10/bin/postgres standard_ExecutorStart

standard_ExecutorStart中注入一个跟踪点。这将作为 perf 事件perf record可用于跟踪 fsync,例如

probe_postgres:standard_ExecutorStart

可用,用于

 perf probe -x /usr/lib/postgresql/10/lib/pglogical.so pg_decode_change 'change->lsn'
 perf record -e probe_pglogical:pg_decode_change -aR -o - | perf script -i - -F event,trace | awk 'NR%100==0' -

探测扩展

扩展也是有效的探测目标。只需将其指定为可执行文件即可,例如,要查看 pglogical 的逻辑解码输出插件在检查每个第 100 次更改时处理的 lsn,你可以执行以下操作:

 perf annotate -l -P

不太常见的报告

 perf script -L

带注释的源代码,来自记录的会话

 perf timechart record
 perf timechart

跟踪输出,来自记录的会话

时间图表基准测试和统计如果你对特定的跟踪点或统计信息感兴趣,perf stat允许你用各种方式选择要分析的内容,其中最有用的是命令也很有用。例如,以下命令将统计fsync

 sudo perf stat -e block:block_rq_*,syscalls:sys_enter_write,syscalls:sys_enter_fsync -a -r 5 -- psql -q -U postgres postgres -c "drop table if exists x; create table x as select a FROM generate_series(1,1000000) a;";

write

调用,以及一个命令期间的块设备活动。它将运行该命令五次并汇总结果。perf

要了解有关使用 perf 进行跟踪的更多信息,请参见 使用 perf 跟踪 PostgreSQL

  • perf 的可用性perfperf 工具在最新的 Linux 发行版中可用,例如
  • RedHat Linux Enterprise 6

Debian Squeeze:添加linux-tools包。它可能从 Linux 源代码中的perftools/perf


子目录中构建和安装。你必须使用与运行的内核版本匹配的

高级:查看和捕获函数参数假设你想收集有关运行的查询类型的相关信息。你可以捕获CmdType operation字段,它在例如,如果你想查看查询执行的速率,你可以在QueryDesc中传递给,使用

 perf probe -x /usr/lib/postgresql/10/bin/postgres standard_ExecutorStart 'queryDesc->operation'

perf!。无需修补 postgres,无需使用 gdb。你可以捕获多个参数。要将字符串作为 C 字符串而不是指针值捕获,请在参数定义后追加

 perf probe -x /usr/lib/postgresql/10/bin/postgres standard_ExecutorStart 'queryDesc->operation' 'queryDesc->sourceText:string'

:stringperf。例如:

perf report在探测中捕获参数会大大增加的开销和跟踪的大小,因此只有在需要时才这样做。目前似乎没有对捕获的跟踪点参数执行任何操作,但

perf script

 perf record -e probe_postgres:standard_ExecutorStart -u postgres -o - | perf script -i -

可以显示它们,你可以通过其 Perl/Python 解释器(如果已启用)或通过管道连接到另一个工具/脚本过滤结果。

例如,如果你想查看实时运行的每个计划查询,你可以设置上面的跟踪点,然后执行以下操作:

       postgres 19499 [002] 429675.072758: probe_postgres:standard_ExecutorStart: (5bd2c0) operation=0x1 sourceText="SELECT 1;"
       postgres 19499 [002] 429675.399764: probe_postgres:standard_ExecutorStart: (5bd2c0) operation=0x1 sourceText="SELECT 2;"

(某些 perf 版本似乎与 stdio 不兼容,在这种情况下,你可能需要使用单独的记录和脚本步骤。如果得到空输出,请尝试一下。)


你应该看到类似以下的结果:

  • 当然,这只是一个有点愚蠢的例子,因为你只需要启用查询日志记录,而且它忽略了未计划的查询(实用程序语句),但它说明了使用探测捕获数据的必要方法。
  • 资源
  • 新的 Linux 'perf' 工具 (pdf)
  • Linux 性能计数器 Wiki
非官方 Linux Perf 事件网页