通常情況下我們開發服務時為了更好的性能往往需要藉助一些工具來輔助優化,發現性能的瓶頸所在。
比如:
- perf 用於分析哪些方法調用cpu比較高、cpu cache 命中率、分支預測等
- valgrind 的helgrind 工具用於分析資源競爭
- gprofile 用於分析一些包括函數調用次數、函數調用耗時等(編譯時需要帶上-pg),原理就是在函數入口、退出地方插入兩個function來進行統計對源碼是侵入式的。原來跟-finstrument-function 類似
- oprofile 用於分析cpu cache命中率等 [關於該工具介紹可以參考:https://www.ibm.com/developerworks/cn/linux/l-oprof/]
我這裡主要是介紹下如何通過systemtap 系統鉤子,來分析耗時比較高的函數(包括用戶態的、系統調用:比如read\\write\\epoll_ctl等)。對應的腳本:(保存名字為first.stp)
probe process("/usr/xxx/a.out").function("*").return {
printf("%s %d,cost:%ld us",probefunc(),pid(), gettimeofday_us() - @entry(gettimeofday_us())
}
probe timer.s(10) {#10秒觸發後將會退出來
exit()
}
假定a.out 的進程id是1123
stap -x 1123 first.stp -v
(第一次時可能會比較慢)
。。。。。
最後輸出結果:
xxxfunc 1123,cost: 10 us
當然system還是統計方法調用次數、打印調用棧、調用方法的參數等,詳細使用可以看附錄中的連接的。
1.systemtap 安裝
yum install systemtap systemtap-runtime
其次運行這個命令檢查一下看需要安裝哪些依賴:
stap-prep
<code>Could not find a package for: kernel-4.9.184-linuxkit.x86_64
No debuginfo packages available to install
package kernel-4.9.184-linuxkit.x86_64 is not installed
package kernel-devel-4.9.184-linuxkit.x86_64 is not installed
package kernel-debuginfo-4.9.184-linuxkit.x86_64 is not installed
problem installing rpm(s) kernel-4.9.184-linuxkit.x86_64
kernel-devel-4.9.184-linuxkit.x86_64
kernel-debuginfo-4.9.184-linuxkit.x86_64
in case of file conflicts, try again after # yum erase kernel-debuginfo/<code>
此時運行測試測試也是無法運行的:
stap -e 'probe begin{printf("hello world");exit();}' -v
Checking "/lib/modules/4.9.184-linuxkit/build/.config failed with error: No such file or directory
2. 系統依賴安裝
1)首先要確認系統版本:uname -r
yum install kernel-devel-`uname -r`
yum install kernel-debuginfo-common-`uname-r`
yum install kernel-debuginfo-`uname -r`
不建議直接採用yum install kernel-devel kernel-debuginfo kernel-debuginfo-common
檢查依賴包是否安裝:stap-prep
這一步對了,一般不會在stap的時候包 ko sysm no found 的問題
注意:如果yum沒法找到對應的包,那麼需要到網上下載對應的rpm包進行離線安裝。
2)stap 報: CONFIG_RETPOLINE=y,but not supported by compiler,Toolchain update recommed 問題
其實這個問題最簡單的解決辦法是直接修改報錯的文件,把對應的Makefile文件報錯的地方註釋掉。
3)stap 時提示:not found compiler-gccx.h
一般是版本不匹配導致,最簡單的辦法是修改文件引用上面1)中安裝的對應版本
find / -name "compile-gcc*.h" 查看有哪些版本可以引用
/usr/src/kernels/`uname -r`/include/linux/compiler-gcc5.h
/usr/src/kernels/`uname -r`/include/linux/compiler-gcc4.h
/usr/src/kernels/`uname -r`/include/linux/compiler-gcc3.h
/usr/src/kernels/`uname -r`/include/linux/compiler-gcc.h
直接修改:/usr/src/kernels/`uname -r`/include/linux/compiler-gcc.h
將:
#define _gcc_header(x) __gcc_header(linux/compiler-gcc##x.h)
修改為:
#define _gcc_header(x) __gcc_header(linux/compiler-gcc5.h) ##注意根據自己上面find找到的版本
4)version 不匹配:ERROR:module version mismatch
<code>$stap -e 'probe begin{printf("hello world");exit();}' -v
....
Pass 3: using .....xxx.c
Pass 4: using ....xxx.ko
ERROR: module version mismatch(#1 SMP Tue Sep 12 10:10:26 CDT 2017 vs #1 SMP Tue Sep 12 22:26:13 UTC 2017), release ..../<code>
把/usr/src/kernels/`uname -r`/include/generated/compile.h 對應的VERSION 值改成
stap 輸出的即可,比如上面的可以修改成:
#define UTS_VERSION "#1 SMP Tue Sep 12 22:26:13 UTC 2017"
然後把上面輸出的xx.c xx.ko 文件刪掉重新編譯即可。
5) 測試:stap-prep
附錄:
[SystemTapLinux 下我萬能的觀測工具] https://max.book118.com/html/2017/0219/92636072.shtm
[systemtap lang] http://sourceware.org/systemtap/langref/
閱讀更多 後臺開發深度探索 的文章