前言
作为服务器开发人员,对性能应该非常的敏感,在服务器设计和编码时就应该充分考虑到性能问题,但如果写出来的程序,或者已经存在的程序在运行中出现了性能问题,我们又如何下手去找出问题并解决呢?这不仅靠的是经验,还需要借助一些工具来辅助分析。
本文将以一个实例为样本,介绍几款linux下常用的性能分析工具的使用以及各自的优缺点,请注意如无特别说明,本文出现的环境均为linux环境。
Linux下的性能分析工具,最常用的是gprof ,但gprof有它的局限性,本文将介绍valgrind 以及更加强大的oprofile。
Grof简介
Linux下最常用的性能分析工具,相信很多人都用过。
Gprof是GNU profiler工具。可以显示程序运行的“flat profile”,包括每个函数的调用次数,每个函数消耗的处理器时间。也可以显示“调用图”,包括函数的调用关系,每个函数调用花费了多少时间。
使用方法
1、编译、链接时需加上-g -pg选项,链接时也需要加上,否则生成的性能数据会不对。
2、 运行时,需要前台运行,不能使用fork来进行后台运行。如果是长时间运行,可以终端下使用screen来运行。
3、结束时,需正常退出,不能kill强行退出。
结果分析
1)程序正常结束时,会在程序的当前目录下产生gmon.out文件,使用gprof命令将运行数据报告到result.txt文件。
![](/uploads/allimg/140905/1-140Z51959235R.png)
2)查看report.txt文件,相应列的含义如下:
%time |
函数占用的时间比例 |
cumulative seconds |
累计时间,包括本身以及子函数消耗的时间 |
self secnods |
函数本身消耗的时间,不包括子函数的时间 |
calls |
函数调用次数 |
self ms/call |
每次调用函数本身消耗的时间,微秒为单位 |
total ms/call |
总调用函数消耗的时间,微秒为单 |
Name |
函数名 |
3) 图形化报告文件。
为了更加直观的查看性能数据,可以借助工具将文本的报告生成图片来查看。
这里的工具需要安装python和dot两个软件,以及一个python处理脚本gprof2dot.py,gprof2dot.py到网上搜索,可以下载到最新版本的。
使用批处理命令如下:
python gprof2dot.py result.txt | dot -Tpng -o report_gprof.png |
生成图片截图如下:
![](/uploads/allimg/140905/1-140Z519594R23.png)
从上图我们可以看到,耗时较大的函数会以较显眼的颜色标显,并且可以很直观的看到函数的调用关系及各函数下子函数占用的比例。
工具点评
优点:Gprof一般系统自带,不用安装,历史悠久,稳定
缺点:需要重新编译程序,对多线程无法支持(需要打patch),需要程序正常退出(很多服务器程序可能没有正常退出的方法)。
Valgrind简介
Valgrind是一个GPL的软件,用于Linux(For x86, amd64 and ppc32)程序的内存调试、
内存泄漏检测以及
性能分析的
软件开发工具。
下面看看如何使用valgrind来分析性能。
使用方法
1、 Valgrind需要自己安装,去valgrind官网下载源码编译安装就可以了。(最新版本3.6.1有bug,需要打个patch,或者去下个老版本的)
2、 要测试的程序不需要重新编译,直接用valgrind运行。
![](/uploads/allimg/140905/1-140Z520001R24.png)
运行结束后,会自动生成名为callgrind.out.xxx的文件,xxx是进程的pid.
![](/uploads/allimg/140905/1-140Z520003AT.png)
3、valgrind运行程序时,程序不能以daemon的方式运行,如果运行时间很长,可以使用screen来运行。Screen的使用可以google一下,有很多资料。
结果分析
1、 Valgrind的结果可以使用callgrind_annotate命令来查看。
![](/uploads/allimg/140905/1-140Z52001012Q.png)
2、还可以借助上面提到的工具,生成图片来查看,效果更好。
Python gprof2dot.py -f callgrind callgrind.out.26204 | dot -Tpng -o report.png
3、注意:跟gprof数据生成图片的命令相比,稍微有点变化,运行python脚本时需要加上参数-f callgrind, 指明是要分析的数据类型是callgrind数据,否则会默认当作是gprof数据来处理。
![](/uploads/allimg/140905/1-140Z5200145948.png)
工具点评
优点:无需编译程序,使用简单,直接运行就行,支持stl,支持系统库函数。
缺点:valgrind程序本身会占用很多的cpu,导致测试程序本身的并发量上不去。
Oprofile
简介
性能测试的神器。其结果最为准确,为什么呢?请看oprofile的测试原理。
其原理是:现在的很多 CPU都提供一个所谓性能计数器的东西(performance counter),大致的原理就是程序可以注册告诉CPU对什么event感兴趣(比如CPU_CYCLE,CPU经历了一次时钟周期),然后CPU在执 行了相应的操作后,就会在性能计数器上加1,这样程序就可以取出。所以,使用OProfile来定位CPU使用率的问题,就变成了让oprofile收集 程序运行过程中哪个可执行程序(或是so)中的哪个function,消耗的CPU CYCLE最多。
也就是说我们可以通过收集数据知道哪个程序的哪个函数消耗的cpu时间占比。这种测试方法结果更符合实际情况。
使用方法
1、 准备内核:
Oprofile需要内核的支持,2.6的linux内核已经支持了这个功能,可以编译成模块或者直接编译进内核。一般发行版本是没有将此项功能编译进内核的,因此需要手动编译一个内核版本,将cat /boot/config-`uname -r` | grep OPROFILE
应该有这样两行:
CONFIG_HAVE_OPROFILE=y
CONFIG_OPROFILE=m
如果没有则加上,CONFIG_OPROFILE=m表示编译成模块,CONFIG_OPROFILE=y表示直接编译进内核。我一般会选择直接编译进内核。使用重新编译的内核启动机器,如果oprofile编成了模块,需要加载oprofile模块。
2、 安装oprofile工具:
下载oprofile的daemon程序和工具集,直接上http://oprofile.sourceforge.net/download/ 下载最新的oprofile源码包到目标机器上,编译安装。注意:安装时需要root权限。
3、设置oprofile参数。
Oprofile是通过设置cpu事件来进行性能测试的,它有一个daemon的进程来启动和收集相关的性能数据。因此启动oprofile之前需要先设置一些参数,比如收集的事件名字,抽样频率。
Oprofile的设置是通过opcontrol命令来进行的。
![](/uploads/allimg/140905/1-140Z5200214K7.png)
首先,配置 OProfile 是否应该监视内核。这是在启动 OProfile 前唯一所需的配置选项。其它选项都是可选的。
要监视内核,以root用户身份执行以下命令:
opcontrol --vmlinux=/boot/vmlinux-`uname -r` |
要配置 OProfile 不监视内核,以root用户身份执行以下命令:
一般来说,我们做应用程序的性能测试不需要关注内核的性能。另外需要关注cpu的周期事件,因此需要进行如下设置
opcontrol --setup --event=eventname:count:unitmask:kernel:user |
这里解释一下event参数的各个项的意思:
项 |
说明 |
eventname |
要关注的事件名称,常用的事件名称及功能如下:
CPU_CLK_UNHALTED: CPU的执行时间,性能测试时最常用的事件
LLC_MISSES: L2 cache失效情况。
DTLB_MISSES: 数据TLB失效情况。
一般做性能测试时只会用到CPU_CLK_UNHALTED。 |
count |
事件抽样频率,oprofile并不是对每次事件都进行记录,而是进行抽样,每多少次事件进行一次数据收集,如果抽样太低,会导致事件数据的收集占用太多的cpu.因此每个事件,oprofile给了一个最小值,每类事件的最小值可以通过opcontrol --list-events查到。 |
unitmask |
事件的掩码,通过opcontrol --list-events可查看相应事件的掩码意义,这里不细说了。 |
kernel |
是否收集内核的事件。0表示不收集,1表示收集。 |
user |
是否收集用户的事件。0表示不收集,1表示收集。 |
对性能测试时,一般使用的设置参数如下:
opcontrol --setup --event=CPU_CLK_UNHALTED:10000:0:0:1 |
4、编译测试程序,需要打开-g参数。
g++ -g -o perf_test perf_test.cpp |
5、 进行测试。
查看当前设置的状态,确保设置正确
清除上一次收集的数据
启动数据收集。
运行我们要测试的程序
![](/uploads/allimg/140905/1-140Z520024L20.png)
运行完成后,停止oprofile数据的收集。
结果分析
Oprofile的数据有两种查看方式:
1、 使用opreport查看。
![](/uploads/allimg/140905/1-140Z520031A19.png)
查看到的列说明:
Samples |
采样到的次数 |
% |
占的百分比 |
Symbol name |
函数名 |
2、也可以使用工具,生成图片查看。
先用opgprof产生Gprof格式的数据。
在当前目录下会生成gmou.out文件。
再用gprof生成txt数据
gprof ./perf_test gmon.out >result.txt |
把result.txt从服务器上下载下来,在windows下使用前面介绍的python脚本生成 图片
python gprof2dot.py result.txt | dot -Tpng -o report_gprof.png |
生成图片结果:
![](/uploads/allimg/140905/1-140Z52003395P.png)
工具点评
优点:oprofile是对整个系统的性能进行分析,采用的是硬件计数器,效率高,负载低,且结果准确。
缺点:需要更换内核,需要root权限。
Perf
简介
先看下摘自网上的一段介绍:Perf 是用来进行软件性能分析的工具。通过它,应用程序可以利用 PMU,tracepoint 和内核中的特殊计数器来进行性能统计。它不但可以分析指定应用程序的性能问题 (per thread),也可以用来分析内核的性能问题,当然也可以同时分析应用代码和内核,从而全面理解应用程序中的性能瓶颈。
简单来说,perf是一个很强大的软件性能分析工具,比oprofile更强大。
使用方法
1. 安装
安装 perf 非常简单,只要您有 2.6.31 以上的内核源代码,那么进入 tools/perf 目录然后敲入下面两个命令即可:
2. 使用
Perf的使用比oprofile更加简单并且可以对生产系统的进程进行在线分析。
Perf需要root权限,使用例子:
perf record -e cycles -a -g -p pid |
使用ctrl+c中断性能数据采集,在当前目录生成perf.data性能数据文件。
结果分析
同样perf也有两种方式来查看性能数据
1、 使用perf查看,使用例子
如果性能数据文件不在当前目录下,可用 -i 参数指定文件路径
如果需要生成带调用关系的性能分析结果,可在report后加-g参数,但前提是在record时使用了-g参数。
![](/uploads/allimg/140905/1-140Z5200420P9.jpg)
上图是使用perf report显示的结果,第一行显示样本采集的次数,从第二行开始是按消耗排序的函数。第二列是占用的比例,比例越高,说明这个函数消耗cpu越多,第三列是进程名,第四列是模块,告诉你是用户进程还是kernel还是c库,第五列是函数名。
通过上面的数据,基本上可以定位到程序的性能消耗点在哪里了,剩下的就是去修改吧。
2、使用工具,生成图片查看。
先用perf script生成中间数据。
perf script | gprof2dot.py -f perf | dot -Tpng -o report_perf.png |
至于gprof2dot.py dot这两个工具前面已经讲过了,这里不再啰嗦了。
生成的图片示例
![](/uploads/allimg/140905/1-140Z520044Y46.png)
是不是很直观?感谢gprof2dot.py的作者吧
工具点评
Perf是在oprofile的基础之上改进过来的,无论从易用上来说还是功能上,perf都明显优于oprofile, 从目前的发展来看,perf肯定会取代oprofile.
Perf的优点:
性能消耗小,所以可以对有性能问题的生产环境都可以在线进行分析。是不是很诱人?
使用简单。Tlinux原生态就支持了perf,毫无使用成本。并且使用命令也非常简单。
Oprofile有的优点他都有。
还能分析内核的性能。
总结
上面介绍的四种工具,经过实测,如果内核已经支持了perf, 强烈推荐使用perf.
如果内核不好支持,或者支持麻烦,可考虑使用valgrind进行测试,Gprof可以完全被valgrind代替,且valgrind的结果比gprof更准确全面一些。
附录
生成图片工具
Graphviz: dot命令http://www.graphviz.org/Download_windows.php
gprof2dot.py:
http://gprof2dot.jrfonseca.googlecode.com/git/gprof2dot.py