0.引言
基于DPDK的發(fā)包工具的性能今天已經(jīng)達到雙向1900Wpps了,比昨天又高了200Wpps,正是得益于oProfile檢測與調(diào)優(yōu)的結(jié)果,而且今天還只是很簡單的用了一下(類似于下面的示例),跟蹤出對幾個結(jié)構(gòu)體字段的訪問比較緩慢,于是對結(jié)構(gòu)體字段進行了仔細(xì)的順序調(diào)整與Cache對齊(之前急于功能實現(xiàn),沒顧及這些字段的排布),結(jié)果性能馬上飆升了200Wpps,開心死我了。后天(明天外出辦理其它事情)到公司再利用oProfile細(xì)細(xì)跟蹤一下,特別是cache命中、
pipeline阻塞、prefetch預(yù)取等,看最終我的發(fā)包工具到底能達到什么性能。oProfile很久以前就使用過,虧今晚請假得空再整理一把以作備忘,好工具要恰時使用才算是適得其所,否則豈不有負(fù)提供如此佳具的大牛&工程師們。
1.概述
oProfile是用于Linux的若干種評測和性能監(jiān)控工具中的一種,它可以工作在不同的體系結(jié)構(gòu)上,包括MIPS、ARM、IA32、IA64和AMD。oProfile包含在Linux2.5和更高版本的內(nèi)核中,也包含在大多數(shù)較新的Linux版本中,包括RedHat9。
oProfile是Linux平臺上的一個功能強大的性能分析工具,支持兩種采樣(sampling)方式:基于事件的采樣(eventbased)和基于時間的采樣(timebased)。
基于事件的采樣是oProfile只記錄特定事件(比如L2
cache miss)的發(fā)生次數(shù),當(dāng)達到用戶設(shè)定的定值時oProfile就記錄一下(采一個樣)。這種方式需要CPU內(nèi)部有性能計數(shù)器(performace
counter)。
基于時間的采樣是oProfile借助OS時鐘中斷的機制,每個時鐘中斷oProfile都會記錄一次(采一次樣),引入此種采樣方式的目的在于提供對沒有性能計數(shù)器的CPU的支持,其精度相對于基于事件的采樣要低。因為要借助OS時鐘中斷的支持,對禁用中斷的代碼oProfile不能對其進行分析。
oProfile在Linux上分兩部分,一個是內(nèi)核模塊(oprofile.ko),一個為用戶空間的守護進程(oprofiled)。前者負(fù)責(zé)訪問性能計數(shù)器或者注冊基于時間采樣的函數(shù)(使用register_timer_hook注冊之,使時鐘中斷處理程序最后執(zhí)行profile_tick時可以訪問之),并采樣置于內(nèi)核的緩沖區(qū)內(nèi)。后者在后臺運行,負(fù)責(zé)從內(nèi)核空間收集數(shù)據(jù),寫入文件。
2.注意事項
1)
不建議在虛擬機里利用oProfile來測試性能,因為虛擬機對oProfile的支持并不好,比如在Vmware虛擬機里不支持性能計數(shù)器接口模式:http://oprofile./faq/,中斷模式的設(shè)置為:
1 |
# modprobe oprofile timer=1 |
或
1 |
# echo "options oprofile timer=1" >> /etc/modprobe.conf |
具體參看:http://oprofile./doc/detailed-parameters.html#timer
2)
調(diào)式的內(nèi)核最好是原生內(nèi)核(Vanilla
kernel、香草內(nèi)核),發(fā)行版Linux(比如redhat)自帶的內(nèi)核一般都是經(jīng)過大量修改的,對oProfile的支持不好。所以,我們最好能從kernel官方網(wǎng)站下載原生源碼后自行編譯生成新內(nèi)核,重啟機器進行新內(nèi)核環(huán)境后進行性能測試。另外,oProfile需要的是未經(jīng)壓縮的內(nèi)核鏡像,所以/boot目錄的vmlinuz-2.x.xx是不能使用的,而需要使用Linux源碼編譯目錄里的未鏡像文件,比如/usr/src/linux-2.6.30/vmlinux
3)
內(nèi)核需打開OPROFILE選項,否則無法運行oProfile:
1 2 3 4 |
[root@localhost oprofile-0.9.6]# opcontrol --init FATAL: Module oprofile not found. FATAL: Module oprofile not found. Kernel doesn't support oprofile |
需要編輯內(nèi)核配置文件:
1 2 |
[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)
同時也應(yīng)確保另外幾個配置選項被選中:
1 2 3 4 |
CONFIG_PROFILING=y CONFIG_X86_LOCAL_APIC=y CONFIG_X86_IO_APIC=y CONFIG_PCI_IOAPIC=y |
然后編譯內(nèi)核重啟機器即可。
4)
為了支持新的CPU類型,oProfile的更新會比較頻繁,所以在使用oProfile時建議先去http://oprofile./news/看看是否有更新版本。
3.系統(tǒng)環(huán)境
此本中所有關(guān)于oProfile的介紹、測試均在CENTOS 5.4環(huán)境下進行,具體如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
[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依賴的庫比較多,如果系統(tǒng)中沒有安裝某些庫則在configure時會給出錯誤提示,比如當(dāng)我輸入如下命令敲回車后提示:
1 2 3 4 5 6 7 |
[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 |
解決該問題的方法是首先從網(wǎng)站http://ftp./gnu/binutils/?C=M;O=D下載binutils包編譯安裝即可(同樣是./configure
、make、make install)。
再configureoProfile:
1 2 3 4 |
[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錯誤:
1 2 3 4 5 6 7 8 9 10 11 |
[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的動態(tài)鏈接庫,需要進入binutils 的bfd目錄編譯獲取libbfd.so文件:
1 2 3 4 5 6 |
[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:
1 2 3 4 5 6 |
[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對先前編譯結(jié)果進行清除,否則生成的libiberty.so不完整,要把so庫拷貝到正確的系統(tǒng)路徑,否則在執(zhí)行oProfile程序時,可能出現(xiàn)“error
while loading shared libraries”的錯誤信息。
最后再對oProfile進行make、make
install即可,以上就是我在Linux
2.6.37.2內(nèi)核上編譯oProfile過程中遇到的問題,雖然摸索清楚后看似不復(fù)雜,其實總個過程也浪費了我不少時間。
5.oProfile工具集
安裝好的oProfile包含有一系列的工具集,這些工具默認(rèn)在路徑/usr/bin之下,它們分別是:
1)
op_help:列出可用的事件,并帶有簡短的描述。
2) opcontrol:控制oProfile的數(shù)據(jù)收集。
3)
opreport:對結(jié)果進行統(tǒng)計輸出。
4)
opannaotate:產(chǎn)生帶注釋的源/匯編文件,源語言級的注釋需要編譯源文件時已加上調(diào)試符號信息的支持。
5)
opgprof:產(chǎn)生如gprof相似的結(jié)果。
6) oparchive:將所有的原始數(shù)據(jù)文件收集打包,從而可以在另一臺機器上進行分析。
7)
opimport:將采樣的數(shù)據(jù)庫文件從另一種abi外部格式轉(zhuǎn)化為本地格式。
6.oProfile使用小示例
下面是一個完整的小示例,其中multiply是測試程序,在進行g(shù)cc編譯時加上了-g參數(shù),便于opannotate分析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
[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反復(fù)使用以及示例結(jié)論
1)
使用oProfile的基本步驟如下所示,其中紅色的步驟是經(jīng)常使用的,前后幾個步驟無需重復(fù)多次:
opcontrol –init
#加載模塊
opcontrol –vmlinux=/usr/src/linux-2.6.37.2/vmlinux
#是否對kernel進行profiling
opcontrol –reset
#清楚當(dāng)前會話中的數(shù)據(jù)
opcontrol –start #開始profiling
./multiply
#運行應(yīng)用程序,oprofile會對它進行profiling
opcontrol –dump #把收集到的數(shù)據(jù)寫入文件
opcontrol
–stop #停止profiling
opcontrol –shutdown #關(guān)閉守護進程oprofiled
opcontrol
–deinit #卸載模塊
2) 對于oProfile收集的統(tǒng)計信息,可以使用opreport、opgprof、opannotate這些工具進行分析并獲取相關(guān)信息,比如從上面的示例中可以看到函數(shù)slow_multiply就相對占用了較多的計算時間。