4dd9d09819dcb

这段时间,领导一直要我做一个linux下性能分析工具的培训。说实话,我也没用过性能分析工具来分析程序的性能瓶颈问题。现实是,在LTE项目中,遇到了程序性能瓶颈问题。所以培训的目的:一是为部门的业绩考核,二是看是否可以应用这些工具来解决LTE项目中程序性能瓶颈问题。

linux下有两个主要的性能分析工具:oprofile和gprof 。gprof 是GNU工具之一,但了解后,很多文章说它不支持多线程。相比较而言,oprofile的功能更加强大。

在众多介绍oprofile工具的文章中,有一篇文章比较吸引我,故转载在此,并进行了排版整理。

1. 概述

oProfile是用于Linux的若干种评测和性能监控工具中的一种,它可以工作在不同的体系结构上,包括MIPS、ARM、IA32、IA64和AMD。oProfile包含在Linux2.5和更高版本的内核中,也包含在大多数较新的Linux版本中,包括RedHat9。
oProfile是Linux平台上的一个功能强大的性能分析工具,支持两种采样(sampling)方式:基于事件的采样(eventbased)和基于时间的采样(timebased)。

基于事件的采样是oProfile只记录特定事件(比如L2 cache miss)的发生次数,当达到用户设定的定值时oProfile就记录一下(采一个样)。这种方式需要CPU内部有性能计数器(performace counter)。

基于时间的采样是oProfile借助OS时钟中断的机制,每个时钟中断oProfile都会记录一次(采一次样),引入此种采样方式的目的在于提供对没有性能计数器的CPU的支持,其精度相对于基于事件的采样要低。因为要借助OS时钟中断的支持,对禁用中断的代码oProfile不能对其进行分析。

oProfile在Linux上分两部分,一个是内核模块(oprofile.ko),一个为用户空间的守护进程(oprofiled)。前者负责访问性能计数器或者注册基于时间采样的函数(使用register_timer_hook注册之,使时钟中断处理程序最后执行profile_tick时可以访问之),并采样置于内核的缓冲区内。后者在后台运行,负责从内核空间收集数据,写入文件。

2. 注意事项

1) 不建议在虚拟机里利用oProfile来测试性能,因为虚拟机对oProfile的支持并不好,比如在Vmware虚拟机里不支持性能计数器接口模式:http://oprofile.sourceforge.net/faq/,中断模式的设置为:

# modprobe oprofile timer=1

# echo "options oprofile timer=1" >> /etc/modprobe.conf

具体参看:http://oprofile.sourceforge.net/doc/detailed-parameters.html#timer

2) 调式的内核最好是原生内核(Vanilla kernel、香草内核),发行版Linux(比如redhat)自带的内核一般都是经过大量修改的,对oProfile的支持不好。所以,我们最好能从kernel官方网站下载原生源码后自行编译生成新内核,重启机器进行新内核环境后进行性能测试。另外,oProfile需要的是未经压缩的内核镜像,所以/boot目录的vmlinuz-2.x.xx是不能使用的,而需要使用Linux源码编译目录里的未镜像文件,比如/usr/src/linux-2.6.30/vmlinux

3) 内核需打开OPROFILE选项,否则无法运行oProfile:

[root@localhost oprofile-0.9.6]# opcontrol --init
FATAL: Module oprofile not found.
FATAL: Module oprofile not found.
Kernel doesn't support oprofile

需要编辑内核配置文件:

[root@localhost ~]# cd /usr/src/linux-2.6.37.2
[root@localhost linux-2.6.37.2]# vi .config

将其中的# CONFIG_OPROFILE is not set改为CONFIG_OPROFILE=m(或者y)
同时也应确保另外几个配置选项被选中:

CONFIG_PROFILING=y
CONFIG_X86_LOCAL_APIC=y
CONFIG_X86_IO_APIC=y
CONFIG_PCI_IOAPIC=y

然后编译内核重启机器即可。

4) 为了支持新的CPU类型,oProfile的更新会比较频繁,所以在使用oProfile时建议先去http://oprofile.sourceforge.net/news/看看是否有更新版本。

3.系统环境

此文中所有关于oProfile的介绍、测试均在CENTOS 5.4环境下进行,具体如下:

[root@localhost oprofile-0.9.7]# cat /etc/issue
CentOS release 5.4 (Final)
Kernel \r on an \m
[root@localhost oprofile-0.9.7]# uname -a
Linux localhost.localdomain 2.6.37.2 #1 SMP Thu Mar 15 18:32:12 CST 2012 x86_64 x86_64 x86_64 GNU/Linux
[root@localhost oprofile-0.9.7]# gcc --version
gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-46)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
[root@localhost oprofile-0.9.7]# make --version
GNU Make 3.81
Copyright (C) 2006  Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
 
This program built for x86_64-redhat-linux-gnu

4.oProfile的安装

oProfile的安装同普通Linux软件安装没有什么两样,照例是configure、make、make install三板斧。由于oProfile依赖的库比较多,如果系统中没有安装某些库则在configure时会给出错误提示,比如当我输入如下命令敲回车后提示:

[root@lenky oprofile-0.9.6]# ./configure --with-kernel-support
…
checking libiberty.h usability... no
checking libiberty.h presence... no
checking for libiberty.h... no
checking for cplus_demangle in -liberty... no
configure: error: liberty library not found

解决该问题的方法是首先从网站http://ftp.gnu.org/gnu/binutils/?C=M;O=D下载binutils包编译安装即可(同样是./configure 、make、make install)。
再configureoProfile:

[root@localhost oprofile-0.9.7]# ./configure --with-kernel-support
…
config.status: executing libtool commands
Warning: QT version 3 was requested but not found. No GUI will be built.

提示没有图形界面,不用管它,直接make编译,我还遇到了这个make错误:

[root@localhost oprofile-0.9.7]# make
…
gcc -shared  .libs/libopagent_la-opagent.o  -lbfd -liberty -ldl -lz  -Wl,--version-script=../libopagent/opagent_symbols.ver -Wl,-soname -Wl,libopagent.so.1 -o .libs/libopagent.so.1.0.0
/usr/local/bin/ld: /usr/local/lib/libbfd.a(archures.o): relocation R_X86_64_32 against `bfd_i386_arch' can not be used when making a shared object; recompile with -fPIC
/usr/local/lib/libbfd.a: could not read symbols: Bad value
collect2: ld returned 1 exit status
make[2]: *** [libopagent.la] Error 1
make[2]: Leaving directory `/home/lenky/oprofile-0.9.6/libopagent'
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/home/lenky/oprofile-0.9.6'
make: *** [all] Error 2

该问题在于没有找到bfd的动态链接库,需要进入binutils 的bfd目录编译获取libbfd.so文件:

[root@localhost bfd]# pwd
/home/lenky/binutils-2.20.1/bfd
[root@localhost bfd]# ./configure --enable-shared
[root@localhost bfd]# make clean
[root@localhost bfd]# make
[root@localhost bfd]# make install

一般,接下来还会遇到libiberty同样的问题,但是libiberty的configure没有提供–enable-shared选项,所以需要我们自己制作so文件,编辑Makefile文件,加上-fPIC编译选项,然后利用make、gcc生成so:

[root@localhost libiberty]# vi Makefile
CFLAGS = -g -O2 -fPIC
[root@localhost libiberty]# make clean
[root@localhost libiberty]# make
[root@localhost libiberty]# gcc -shared *.o -o libiberty.so
[root@localhost bfd]# make install

由于之前编译过,所以注意不要落了make clean对先前编译结果进行清除,否则生成的libiberty.so不完整,要把so库拷贝到正确的系统路径,否则在执行oProfile程序时,可能出现“error while loading shared libraries”的错误信息。
最后再对oProfile进行make、make install即可,以上就是我在Linux 2.6.37.2内核上编译oProfile过程中遇到的问题,虽然摸索清楚后看似不复杂,其实总个过程也浪费了我不少时间。

5.oProfile工具集

安装好的oProfile包含有一系列的工具集,这些工具默认在路径/usr/bin之下,它们分别是:

1) op_help:列出可用的事件,并带有简短的描述。
2) opcontrol:控制oProfile的数据收集。
3) opreport:对结果进行统计输出。
4) opannaotate:产生带注释的源/汇编文件,源语言级的注释需要编译源文件时已加上调试符号信息的支持。
5) opgprof:产生如gprof相似的结果。
6) oparchive:将所有的原始数据文件收集打包,从而可以在另一台机器上进行分析。
7) opimport:将采样的数据库文件从另一种abi外部格式转化为本地格式。

6.oProfile使用小示例

下面是一个完整的小示例,其中multiply是测试程序,在进行gcc编译时加上了-g参数,便于opannotate分析:

[root@localhost test]# cat multiply.c
/**
 * FileName: multiply.c
 * sh# gcc multiply.c -g -o multiply
 */
 
#include <stdio.h>
int fast_multiply(x,  y)
{
    return x * y;
}
 
int slow_multiply(x, y)
{
    int i, j, z;
    for (i = 0, z = 0; i < x; i++)
        z = z + y;
    return z;
}
 
int main(int argc, char *argv[])
{
    int i,j;
    int x,y;
    for (i = 0; i < 200; i ++) {
        for (j = 0; j <  30 ; j++) {
            x = fast_multiply(i, j);
            y = slow_multiply(i, j);
        }
    }
    printf("x=%d, y=%d\n", x, y);
    return 0;
}
[root@localhost test]# gcc multiply.c -g -o multiply
[root@localhost test]# opcontrol --init
[root@localhost test]# opcontrol --vmlinux=/usr/src/linux-2.6.37.2/vmlinux
[root@localhost test]# opcontrol --reset
[root@localhost test]# opcontrol --start
Using default event: CPU_CLK_UNHALTED:100000:0:1:1
Using 2.6+ OProfile kernel interface.
Reading module info.
Using log file /var/lib/oprofile/samples/oprofiled.log
Daemon started.
Profiler running.
[root@localhost test]# ./multiply
x=5771, y=5771
[root@localhost test]# opcontrol --dump
[root@localhost test]# opcontrol --stop
Stopping profiling.
[root@localhost test]# opcontrol --shutdown
Killing daemon.
[root@localhost test]# opcontrol --deinit
Unloading oprofile module
[root@localhost test]# opannotate --source ./multiply
/*
 * Command line: opannotate --source ./multiply
 *
 * Interpretation of command line:
 * Output annotated source file with samples
 * Output all files
 *
 * CPU: Intel Architectural Perfmon, speed 1867 MHz (estimated)
 * Counted CPU_CLK_UNHALTED events (Clock cycles when not halted) with a unit mask of 0x00 (No unit mask) count 100000
 */
/*
 * Total samples for file : "/home/lenky/test/multiply.c"
 *
 *     39 100.000
 */
 
               :#include <stdio.h>
               :
               :int fast_multiply(x,  y)
               :{
               :        return x * y;
               :}
               :int slow_multiply(x, y)
               :{ /* slow_multiply total:     36 92.3077 */
               :        int i, j, z;
    27 69.2308 :        for (i = 0, z = 0; i < x; i++)
     8 20.5128 :                z = z + y;
     1  2.5641 :        return z;
               :}
               :int main()
               :{ /* main total:      3  7.6923 */
               :        int i,j;
               :        int x,y;
               :        for (i = 0; i < 200; i ++) {
     2  5.1282 :                for (j = 0; j <  30 ; j++) {
     1  2.5641 :                        x = fast_multiply(i, j);
               :                        y = slow_multiply(i, j);
               :                }
               :        }
               :    printf("x=%d, y=%d\n", x, y);
               :        return 0;
               :}
               :
[root@localhost test]# opreport -l ./multiply
CPU: Intel Architectural Perfmon, speed 1867 MHz (estimated)
Counted CPU_CLK_UNHALTED events (Clock cycles when not halted) with a unit mask of 0x00 (No unit mask) count 100000
samples  %        symbol name
36       92.3077  slow_multiply
3         7.6923  main
[root@localhost test]# opreport
CPU: Intel Architectural Perfmon, speed 1867 MHz (estimated)
Counted CPU_CLK_UNHALTED events (Clock cycles when not halted) with a unit mask of 0x00 (No unit mask) count 100000
CPU_CLK_UNHALT...|
  samples|      %|
------------------
   438541 99.4447 vmlinux
      921  0.2088 oprofiled
      630  0.1429 libc-2.5.so
      355  0.0805 bash
      342  0.0776 oprofile
       55  0.0125 ld-2.5.so
       39  0.0088 multiply
       21  0.0048 igb
       16  0.0036 ixgbe
       12  0.0027 libpthread-2.5.so
        9  0.0020 irqbalance
        7  0.0016 gawk
        7  0.0016 libglib-2.0.so.0.1200.3
        7  0.0016 libpython2.4.so.1.0
        6  0.0014 sshd
        4 9.1e-04 libcrypto.so.0.9.8e
        3 6.8e-04 grep
        3 6.8e-04 libusb-0.1.so.4.4.4
        2 4.5e-04 ls
        2 4.5e-04 sendmail.sendmail
        1 2.3e-04 cat
        1 2.3e-04 libdbus-1.so.3.4.0
        1 2.3e-04 libgthread-2.0.so.0.1200.3
        1 2.3e-04 libselinux.so.1
        1 2.3e-04 init
        1 2.3e-04 libpopt.so.0.0.0
        1 2.3e-04 _gobject.so
        1 2.3e-04 nmbd
[root@localhost test]#

7.oProfile反复使用以及示例结论

1) 使用oProfile的基本步骤如下所示,其中中间的步骤是经常使用的,前后几个步骤无需重复多次:

opcontrol --init   #加载模块
opcontrol --vmlinux=/usr/src/linux-2.6.37.2/vmlinux  #是否对kernel进行profiling
opcontrol --reset  #清楚当前会话中的数据
opcontrol --start  #开始profiling
./multiply   #运行应用程序,oprofile会对它进行profiling
opcontrol --dump  #把收集到的数据写入文件
opcontrol --stop  #停止profiling
opcontrol --shutdown  #关闭守护进程oprofiled
opcontrol --deinit  #卸载模块

2) 对于oProfile收集的统计信息,可以使用opreport、opgprof、opannotate这些工具进行分析并获取相关信息,比如从上面的示例中可以看到函数slow_multiply就相对占用了较多的计算时间。

注:本文转载自:http://lenky.info/archives/2012/03/1371

» 文章出处: reille博客—http://velep.com , 如果没有特别声明,文章均为reille博客原创作品
» 郑重声明: 原创作品未经允许不得转载,如需转载请联系reille#qq.com(#换成@)
分享到:

 Leave a Reply

(必须)

(我会替您保密的)(必须)


*

   
© 2012 velep.com | reille blog | 管理| 粤ICP备12094833号-2| 谷歌地图| 百度地图| Suffusion theme|Sayontan Sinha

无觅相关文章插件,快速提升流量