天天看点

Linux 性能诊断 perf使用指南

linux , perf , 性能诊断 , stap , systemtap , strace , dtrace , dwarf , profiler , perf_events

linux在服务端已占据非常大的比例,很多业务很多服务都跑在linux上面。

软件运行在linux下,软件本身、以及linux系统的性能诊断也成为热门的话题。

例如,你要如何回答这些问题

又或者你是一名dba或者开发人员,想知道数据库在跑某些benchmark时,性能瓶颈在哪里,是io,是等待,还是网络,代码瓶颈在哪里?

在linux下诊断的工具比较多,比如systemtap, dtrace, perf。

本文将介绍一下perf的用法,网上很多叫法如perf_events , perf profiler , performance counters for linux。叫法不同,都指perf。

perf是linux 2.6+内核中的一个工具,在内核源码包中的位置 tools/perf。

perf利用linux的trace特性,可以用于实时跟踪,统计event计数(perf stat);或者使用采样(perf record),报告(perf report|script|annotate)的使用方式进行诊断。

perf命令行接口并不能利用所有的linux trace特性,有些trace需要通过ftrace接口得到。

Linux 性能诊断 perf使用指南

这张图大致列出了perf支持的跟踪事件,从kernerl到user space,支持块设备、网络、cpu、文件系统、内存等,同时还支持系统调用,用户库的事件跟踪。

你可以使用perf list输出当前内核perf 支持的预置events

我们看到perf支持这么多的事件和trace,它依赖了很多的接口来干这件事情。

1. symbols

没有符号表,无法将内存地址翻译成函数和变量名。

例如,无符号表的跟踪显示如下

有符号表的跟踪显示如下

如何安装符号表?

对于内核代码的符号表,在编译内核时,使用config_kallsyms=y。 检查如下

对于用户安装软件的符号表,如果是yum安装的,可以安装对应的debuginfo包。

如果是用户自己编译的,例如使用gcc编译时加上-g选项。

2. perf annotate

perf annotate can generate sourcecode level information if the application is compiled with -ggdb.

3. stack traces (使用perf record -g收集stack traces)

要跟踪完整的stack,编译时需要注意几个东西。

3.1 编译perf时包含libunwind和-g dwarf,需要3.9以上的内核版本。

3.2 有些编译优化项会忽略frame pointer,所以编译软件时必须指定 -fno-omit-frame-pointer ,才能跟踪完整的stack trace.

3.3 编译内核时包含 config_frame_pointer=y

总结一下,要愉快的跟踪更完备的信息,就要在编译软件时打开符号表的支持(gcc -g),开启annotate的支持(gcc -ggdb),以及stack trace的支持(gcc -fno-omit-frame-pointer)。

了解了perf event后,我们可以更精细的,有针对性的对事件进行跟踪,采样,报告。

当然,你也可以不指定事件,全面采样。

例如centos你可以使用yum安装,也可以使用源码安装。

perf在内核源码的tools/perf中,所以下载与你的内核大版本一致的内核源码即可

安装依赖库,有一个小窍门可以找到依赖的库

通常依赖 gcc make bison flex elfutils libelf-dev libdw-dev libaudit-dev python-dev binutils-dev

并不是每个开关都需要,但是有些没有就不方便或者功能缺失,例如没有打开符号表的话,看到的是一堆内存地址。

一些开关的用途介绍

1. kernel-level symbols are in the kernel debuginfo package, or when the kernel is compiled with config_kallsyms.

2. the kernel stack traces are incomplete. now a similar profile with config_frame_pointer=y

3. 当我们使用perf record [stack traces (-g)]时,可以跟踪stack,但是如果内核编译时没有指定config_frame_pointer=y,perf report时就会看到缺失的信息。

不包含config_frame_pointer=y时

包含config_frame_pointer=y时 (much better -- the entire path from the write() syscall (__write_nocancel) to iowrite16() can be seen.)

4. 如果要使用动态跟踪,即跟踪任意指定代码,则需要打开这些开关:

for kernel analysis, using config_kprobes=y and config_kprobe_events=y, to enable kernel dynamic tracing. and config_frame_pointer=y, for frame pointer-based kernel stacks.

for user-level analysis, config_uprobes=y and config_uprobe_events=y, for user-level dynamic tracing.

5. 如果打开了config_debug_info,则可以在动态跟踪中打印内核变量的值。

if your kernel has debuginfo (config_debug_info=y), you can fish out kernel variables from functions. this is a simple example of examining a size_t (integer)

例如

通过以下命令可以查看linux的config

先了解一下概貌

perf 命令用法还是挺简单的,根据功能区分了command,每个command有各自的用法。

用得比较多的有list, record, report, script, stat, top。

要得到每个command的用法也蛮简单,可以使用perf help command得到。

跟踪时可以指定事件,cpu,以及是否跟踪stack trace。

输出如下

输入 ? 可以得到top的帮助介绍

输入e全部展开,展开后可以得到stack trace的结果, 如果发现有地址的信息,但是没有符号表的信息,可能是软件编译时没有指定-g,如果stack信息不完整,则软件编译时需要加-fno-omit-frame-pointer(参考前面章节的介绍)。

输入c全部收起

symbol列[]中字符代表的含义如下,通常是k或者.表示kernel和user space事件。

perf record用来收集统计信息,通常的用法包括

1. 使用record收集统计信息,可以收集全局的,指定pid或者线程id的,指定cpu的,指定user id的。

2. 收集间隔,可以指定采样的频率,采样的event数,采样时间。

3. 采集的详细程度,可以指定event,使用cpu实时调度策略的进程(可以参考rhel 讲cgroup cpu部分的文章),是否跟踪stack chain,

例子

解读前面收集到的perf.data.

常用的开关如下,--tui是交互式的文本显示窗口,--stdio是文本显示窗口。

交互式显示例子,看概貌挺方便的 (常用的交互命令: e扩展,c收敛,q退出)

文本显示例子,看细节挺方便

首先显示了一些异常,如果你发现少了符号表或者什么的,可以根据提示安装debuginfo,或者重新编译内核或软件。

报告的细节如下

一条条打印perf.data内的数据,输出的是perf record收集到的原始数据。

生成热力图、火焰图也需要perf script的输出,从最原始的信息中提取数据,生成svg。

解读前面收集到的perf.data,辅以汇编指令显示。

用来测试系统的一些常见指标的性能(如ipc, message or pipe, memcpy)。

测试进程或线程通信性能

从测试来看,线程, pipe()通信效率是最高的。

测试pipe()

测试所有,包括memcpy

perf 除了可以采样(使用perf record)(包括call stack trace),还可以用于event计数。

perf stat就是用于event计数的,可以跟踪指定命令的event计数。

如果你想跟踪postgresql数据库,可以把数据库的所有进程塞到cgroup里,然后使用perf stat -g cgname统计整个cgroup。

perf stat还支持-e指定事件,事件支持通配符。

使用instruction:modifier可以指定要跟踪的instruction在哪里?在kernel space或user space,又或者在虚拟机,虚拟机os,宿主机os等。

modifier用法如下,写在event:后面。

modifiers

description

example

u

monitor at priv level 3, 2, 1 (user)

event:u

k

monitor at priv level 0 (kernel)

event:k

h

monitor hypervisor events on a virtualization environment

event:h

monitor host machine on a virtualization environment

g

monitor guest machine on a virtualization environment

event:g

例子 -e instructions:u

perf probe可以实现动态跟踪,指哪打哪。静态跟踪是预置的,而动态跟踪是补充预置不足的。

Linux 性能诊断 perf使用指南

比如你想跟踪kernel的某个function, 甚至某一行代码,某些变量的值。

或者你想跟踪用户软件的某个function,甚至某一行代码,某些变量的值。

首先要添加需要动态跟踪的对象(function, var, ...)

然后record,和report分析,这和前面的用法是一样的。

跟踪某行代码

跟踪用户软件的指定function

event中的一种类型,实际上是一些比较常见的系统调用。

不在里面的可以使用前面介绍的动态跟踪的方式进行跟踪。

支持哪些tracepoint

主要包含以下tracepoint subtype

使用perf report -tui或者-stdio输出的文本不够直观的话,使用火焰图可以很直观的表现出哪些代码是瓶颈所在。

生成火焰图

Linux 性能诊断 perf使用指南

生成热力图

Linux 性能诊断 perf使用指南

要完备的跟踪和打印跟踪(符号表、call stack trace、汇编指令)信息,建议内核编译时加上

编译perf时需要支持libunwind, 并加上

软件编译时加上

如果是yum安装的软件,可以安装对应的debuginfo包。

5. 火焰图

<a href="https://github.com/brendangregg/flamegraph">https://github.com/brendangregg/flamegraph</a>

6. 热力图

<a href="https://github.com/brendangregg/heatmap">https://github.com/brendangregg/heatmap</a>