oProfile的安裝與使用

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/,中斷模式的設置爲:

# 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  #卸載模塊

opreport -l -m cpu,lib,tgid -t 0.1 顯示佔用cpu情況顯示佔用cpu超過0.1的函數 

2) 對於oProfile收集的統計信息,可以使用opreport、opgprof、opannotate這些工具進行分析並獲取相關信息,比如從上面的示例中可以看到函數slow_multiply就相對佔用了較多的計算時間。

轉載請保留地址:http://www.lenky.info/archives/2012/03/1371http://lenky.info/?p=1371

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章