1.valgind 安装
1.1源码安装
获取源码:(也可点击链接下载)
wget http://www.valgrind.org/downloads/valgrind-3.16.0.tar.bz2
解压
tar -jxvf valgrind-3.16.0.tar.bz2
安装
cd valgrind-3.16.0
./configure (./configure --prefix=/home/user1/valgrind 这种方式可以指定安装目录,但是可能需要配置环境才能使用)
make
make install
1.2指令安装(推荐)
sudo apt-get install valgrind
验证是否安装成功
valgrind --help
Ps:valgrind布置valgrind本身(线程安全,内存检查)还有callgrind(函数调用关系分析等)还有其他工具。只要安装valgrind也可以使用其他工具。
1.3基本介绍
包含如下工具:
- memcheck:检查程序中的内存问题,如泄漏、越界、非法指针等。
- callgrind:检测程序代码的运行时间和调用过程,以及分析程序性能。
- cachegrind:分析CPU的cache命中率、丢失率,用于进行代码优化。
- helgrind:用于检查多线程程序的竞态条件。
- massif:堆栈分析器,指示程序中使用了多少堆内存等信息。
2.memcheck工具
例子:
valgrind -v --log-file=valgrind0928.log --tool=memcheck --leak-check=full --show-mismatched-frees=yes ./v2xAlgo
用法:
valgrind [options]prog-and-args [options]:常用选项,适用于所有Valgrind工具。
!!!使用valgrind的时候记得把编译条件的-pg关掉!!!!!!!。
常用选项释义:
- -tool=最常用的选项。运行valgrind中名为toolname的工具。默认memcheck。
- h –help显示帮助信息。
- -version显示valgrind内核的版本,每个工具都有各自的版本。
- q –quiet安静地运行,只打印错误信息。
- v –verbose更详细的信息,增加错误数统计。
- -trace-children=no|yes跟踪子线程? [no]
- -track-fds=no|yes跟踪打开的文件描述?[no]
- -time-stamp=no|yes增加时间戳到LOG信息? [no]
- -log-fd=输出LOG到描述符文件 [2=stderr]
- -log-file=将输出的信息写入到filename.PID的文件里,PID是运行程序的进行ID
- -log-file-exactly=输出LOG信息到 file
- -log-file-qualifier=取得环境变量的值来做为输出信息的文件名。 [none]
- -log-socket=ipaddr:port输出LOG到socket ,ipaddr:port
LOG信息输出
-
-xml=yes将信息以xml格式输出,只有memcheck可用
-
-num-callers= show callersin stack traces [12]
-
-error-limit=no|yes如果太多错误,则停止显示新错误? [yes]
-
-error-exitcode=如果发现错误则返回错误代码 [0=disable]
-
-db-attach=no|yes当出现错误,valgrind会自动启动调试器gdb。[no]
-
-db-command=启动调试器的命令行选项[gdb -nw %f %p]
适用于Memcheck工具的相关选项:
-
-leak-check=no|summary|full要求对leak给出详细信息? [summary]
-
-leak-resolution=low|med|high how much bt merging in leakcheck [low]
-show-reachable=no|yesshow reachable blocks in leak check? [no]
3.callgrind工具
例子:
valgrind --tool=callgrind --separate-threads=yes ./test
其中./test 就是我们要分析的程序。
-separate-threads=yes。这样就会为每个线程额外单独生成一个性能分析文件。
执行完毕后,就会在当前目录下生成一个进程观测文件和几个线程观测文件。
进程观测文件名为“callgrind.out.进程号”。线程观测文件名为“callgrind.out.进程号-01”,“callgrind.out.进程号-02”……。
例如:
callgrind.out.31113 callgrind.out.31113-01 callgrind.out.31113-02 callgrind.out.31113-03 …………
callgrind + dot绘图 用法:
单独查看子线程:
valgrind --tool=callgrind --separate-threads=yes ./test
先用上述方法生成out文件。然后使用gprof2dot生成dot文件:
gprof2dot -f callgrind -s callgrind.out.7339-05 > callgrind05.dot
然后把dot文件生成图片:
dot -Tpng callgrind05.dot -o callgrind05.png 或者dot -Tsvg callgrind05.dot -o callgrind05.svg
其中-T为选择生图片的类型,有的时候png不好使会出现绘图失败的情况,建议换成svg
不单独查看子线程:
valgrind --tool=callgrind ./test
先用上述方法生成out文件。然后使用gprof2dot生成dot文件:
gprof2dot -f callgrind -s callgrind.out.7339 > callgrind.dot
然后把dot文件生成图片:
dot -Tpng callgrind.dot -o callgrind.png 或者dot -Tsvg callgrind.dot -o callgrind.svg
4.callgrind辅助:kcachegrind 安装和使用
4.1定性分析
安装:
sudo apt-get install kcachegrind
使用:
kcachegrind callgrind.out.7339-05
其中,callgrind.out.7339-05为通过callgrind生成的分析文件
左侧为所有函数 及其相关信息
右侧选择call graph选项卡可以看左侧点选的函数的相关调用关系
目的:可以观测到更加精准的函数调用关系,通过gprof2dot 生成的图片是整个生命周期所调用到的函数。所以函数关系可能比较复杂。kcachegrind的callgraph可以帮忙过滤掉不必要的信息。
4.2 定量分析
首先要介绍一下,kcache的相关按键。红框内的relative表示的是切换【该行函数的cpu周期数占比】和【该行函数的具体cpu周期数量】在定性分析时只需关注百分比即可。但是定量分析的时候具体的cpu周期数量就显得尤为重要。
那么如何阅读kcache的表格呢?
首先先要看懂表头的意思。
- function和location分别是函数名和函数所在文件就不多赘述了。
- 蓝框中的incl.是inclusive的简写。表示的是该函数及其内容所有函数的内容所占用的周期数。
- 黄框中的self是exclusive的意味。即该函数中除去其他函数的内容所占用的周期数。
- 绿框中的called是该函数在程序运行中调用的次数。
举例
- main()函数是主函数只运行一次,所以called=1。主函数肯定是包含程序的全部内容所以主函数incl占比无线接近百分百。但是主函数中一般包含别的函数,所以self占比往往非常低。
- 以粉色框为例,该函数运行1005次,总共占用43741422次。那么一次运行大概占用43523.8个cpu周期。
举例
在知道cpu周期数后,如何知道真正运行的时间呢?毕竟时间更加直观。
此处需要补充一些系统原理基本知识。
1个cpu周期=6个状态周期=12个节拍=12个震荡脉冲周期=12/震荡脉冲频率
只要能查到系统的震荡脉冲频率即可,一般机器的震荡脉冲频率有另一个叫法【cpu主频】
linux下可以通过如下指令查到
cat /proc/cpuinfo
我的cpuMhz为3192.079Mhz,那么一个cpu周期【cpu cycle/machine cycle】为3.759纳秒,如此便可以算出粉色框的函数单次运行时长为163.6微秒。与之前通过clock_gettime()函数计算得到的时间相近。
公式为
t
i
m
e
=
I
n
c
l
.
c
p
u
c
y
c
l
e
c
a
l
l
e
d
∗
12
f
r
e
q
c
p
u
.
time= \frac{Incl._{cpu cycle}}{called}*\frac{12}{freq_{cpu}}.
time=calledIncl.cpucycle∗freqcpu12.
4.3kcachegrind补充
在摸索kcachegrind的过程中发现大部分都集中在看函数调用的树图,关于时间的计算和其他内容在百度或CSDN并没有过多描述,为此看了一上午,后来发现大部分内容在官网都是有描述。花费10到20分钟慢慢看一下官网,基本要找的信息全都找到了。
kcachegrind官网
工具是开源的,sourcecode和github上都可以跟踪。
5.其他工具
5.1Cachegrind
Cache分析器,它模拟CPU中的一级缓存和二级缓存,能够精确地指出程序中cache的丢失和命中。如果需要,它还能够为我们提供cache丢失次数,内存引用次数,以及每行代码,每个函数,每个模块,整个程序产生的指令数。这对优化程序有很大的帮助。
但是官网在程序优化中明确有建议程序不要过度优化,一般callgrind足够在代码效率上提供优化空间,所以cachegrind的使用概率较小,除非有明确的使用的场景。
使用方法:
valgrind –tool=cachegrind ./程序名
5.2Helgrind
它主要用来检查多线程程序中出现的竞争问题。Helgrind寻找内存中被多个线程访问,而又没有一贯加锁的区域,这些区域往往是线程之间失去同步的地方,而且会导致难以发觉的错误。Helgrind实现了名为Eraser的竞争检测算法,并做了进一步改进,减少了报告错误的次数。不过,Helgrind仍然处于实验状态。
一般在做内存泄露的时候通常是使用memcheck,memcheck就已经能够覆盖多线程工作的情况,helgrind提供的是线程竞争的检测能力,这个检测不一定代表内存会泄露,但是也会出现程序运行结果不满足预期的问题。由于helgrind还在完善中,所以不是非常推荐使用,遇到多线程结果不满足预期,但也没有内存泄露的情况下,可以考虑进行分析。报告仅供参考,还是需要技术人员进一步自行分析。
或者可以找找看有没有开发比较完善的同类型分析工具。
使用方法:
valgrind --tool=helgrind ./程序名
5.3Massif【亟待补充】
堆栈分析器,它能测量程序在堆栈中使用了多少内存,告诉我们堆块,堆管理块和栈的大小。Massif能帮助我们减少内存的使用,在带有虚拟内存的现代系统中,它还能够加速我们程序的运行,减少程序停留在交换区中的几率。
Massif对内存的分配和释放做profile。程序开发者通过它可以深入了解程序的内存使用行为,从而对内存使用进行优化。这个功能对C++尤其有用,因为C++有很多隐藏的内存分配和释放。
由于目前项目采用c++开发,所以在内存的分配和释放上如果希望更进一步,可以进行使用,同时也提供了一个更加便利的堆栈管理,相比于传统指令查看。
后续最好可以深入研究一下,或者可以找找看有没有开发比较完善的同类型分析工具。
5.4其他
此外,lackey 和 nulgrind 也会提供。Lackey 是小型工具,很少用到;Nulgrind 只是为开发者展示如何创建一个工具。这里就不做介绍了。