./configure的时候,
1.缺少popt库-->源码安装popt-1.14.tar.gz
2.缺少liberty库--> liberty其实是binutil-dev里的一个库,sudo apt-get install binutil-dev即可。
0.引言
基于DPDK的发包工具的性能今天已经达到双向1900Wpps了,比昨天又高了200Wpps,正是得益于oProfile检测与调优的结果,而且今天还只是很简单的用了一下(类似于下面的示例),跟踪出对几个结构体字段的访问比较缓慢,于是对结构体字段进行了仔细的顺序调整与Cache对齐(之前急于功能实现,没顾及这些字段的排布),结果性能马上飙升了200Wpps,开心死我了。后天(明天外出办理其它事情)到公司再利用oProfile细细跟踪一下,特别是cache命中、 pipeline阻塞、prefetch预取等,看最终我的发包工具到底能达到什么性能。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/,中断模式的设置为:
1
# modprobe oprofile timer=1
或
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就相对占用了较多的计算时间。