目录(?)[+]
OProfile是一个linux 2.2/2.4/2.6系统(支持多CPU架构)上的分析系统,它可以分析一个正在运行的系统的所有部分,从内核(包括模块和中断处理例程)到共享库(shared libraries),再到二进制文件(可执行文件)。它以低开销悄无声息地运行在后台,收集系统信息。这些特点决定了它是一个非常理想的工具来分析整个系统以查找性能瓶颈在哪里。
很多CPU都提供”性能计数器”(performance counters),一种硬件计数器可以用来对事件(event)计数;比方说,缓存未命中(cache misses)或者CPU周期(CPU cycle)。OProfile基于这些事件来提供代码分析的能力:当一定数量(可配置)的事件发生时,PC(程序计数器)就被记录,如此反复进行。这些信息被汇总成对每个二进制文件的分析结果。
一些硬件配置不允许OProfile使用性能计数器,对于这种情况,不可以使用事件来对PC进行计数,这时OProfile只能以timer/RTC模式运行。
OProfile在很多情形下都非常有用,当你有以下需求时可以考虑使用OProfile:
1. 需要低开销
2. 不能使用高内嵌的分析方法(highly intrusive profiling methods)
3. 需要分析中断例程
4. 需要分析一个应用程序和它的共享库
5. 需要分析所支持虚拟机的动态编译代码(JIT code)
6. 需要获取整个系统的性能数据
7. 需要检验硬件能力,比如缓存未命中(cache misses)
8. 需要详细的源代码性能分析(OProfile可以在源代码上标注性能计数)
9. 需要指令级别的分析
10. 需要调用图分析(call-graph)
当然, OProfile也不是解决所有问题的银弹,当你有以下需求时, 光靠OProfile可能不够:
1. 在非linux2.6/x86平台上进行调用图(call graph)分析
2. 在没有root权限的情况下进行分析
3. 需要100%精确指令级别的分析(汇编语言)
4. 需要函数调用计数或者间隙分析API(interstitial profiling API)
5. 任何情况下都不能对系统产生影响(或干扰)
6. 在不支持的虚拟机分析动态编译的代码
OProfile包含了一系列的工具,下面是这些工具的介绍。
ophelp
该工具列出(当前机器)可用的事件及其介绍;
opcontrol
用以OProfile(性能)数据采集,主要的工作模块之一;
agent libraries
被虚拟机用来记录关于动态编译代码(JITed code)的信息;
opreport
用以显示分析数据(结果)的超有用的工具;
opannotate
这个工具可以根据opcontrol采集的数据在源代码上做相应的注释,用以显示每段代码(甚至每行代码)的效率,支持汇编,C/C++或者C/C++混合代码。前提是被分析文件必须在编译的时候包含调试信息(比如g++的-g选项)。
//--------------------------------------------------------
对于做应用级别(相对内核开发)的开发,如果只想快速找到代码性能瓶颈而对OProfile的工作原理不感兴趣,只看该示例应该就足够了。
假如我们的代码文件是/home/leo/oprofile_test/main.cpp,内容是:
这段程序读取一个从命令行传递过来的一个文件,打印出每一行的字符数(这段代码是在64位机器上运行的)。
a) 使用“g++ -g main.cpp”将源代码编译成可执行程序
b) 使用“opcontrol --init”进行分析器初始化(启动分析器驱动模块)
c) 使用“opcontrol --setup --image=/home/leo/oprofile_test/a.out --event=CPU_CLK_UNHALTED:6000:0”和“opcontrol --no-vmlinux”设置分析器,如下图所示:
d) 使用“opcontrol --start”启动分析器
e) 运行程序,比如:“./a.out /var/log/messages.1”
运行完成后,使用下面的命令获取分析结果。
a) 运行“opcontrol --dump”将采样数据送入分析器中
b) 运行“opreport -l”查看函数级的分析结果,如下图所示:
由图中可以看到FileOp::DoWork的采样百分比占到了99.0909%,说明大部分的CPU时间都是在此函数中。
c) 运行“opannotate --source”查看代码级别的分析结果,如下图所示:
上图只是截取了关键的部分输出,从这个输出可以看到strlen这行占到了77%(红色矩形中数字768表示在分析采样过程中改行采样数量为768,即每次设置的事件发生时查看运行所在的代码位置,发现一次就对改行的采样数加1,。77.5758代表改行采样数占所有采样数的77.5758%),说明这段代码的运行效率很低,找到了性能瓶颈,接下来的工作就是找函数替换strlen啦!(strlen的效率实在很低,尤其是当字符串很长的时候)
OK,到此分析结果已经出来了,不过对于工程很大的情况,opreport和opannotate的输出很多,这时候把分析结果导出到文件中就比较容易查看了,对于opreport,可以使用“opreport -l -o ./analysis.log”来讲分析结果输出到文件中,如下图所示:
而对于opannotate来讲,可以使用“opannotate --source --output-dir=/tmp/”来讲分析结果对应到相应的源代码文件中,如下图所示:
上面的命令的意思是将相应的打了标注的源代码文件放在“/tmp/”目录下,在该目录下,会根据源代码的文件结构生成相对应的文件结果,如图,在“/tmp/”目录下生成了“home/leo/oprofile_test”目录,与源代码的目录一致,而“main.cpp”就在该目录下,打开该目录下的“main.cpp”就可以查看每句代码对应的采样数据以及资源占用百分比了。
用完了分析器,使用命令“opcontrol --stop”停止采样,命令“opcontrol --reset”清除当前会话中的采样数据,命令“opcontrol --shutdown”关闭分析器内核模块,“opcontrol --stop” 和命令“opcontrol --reset”是非常有必要的,因为不进行这两步下次在进行分析时就会受到这次结果的影响。