程式調試和性能分析常用技巧
程式調試和性能分析通常需要設計到多種工具,有時甚至需要跨越使用者态和核心态。本文總結了在程式調試和性能分析過程中常碰到三個問題,既是為了友善自己後面溫習,也是為了和碰到同樣問題的朋友一起分享。
1.如何調試多線程的程式?
多線程程式運作的時候如果出現崩潰或者産生core的時候,最困難的是很難定位到底是哪個線程導緻的問題。為此,可以利用gdb工具中的thread apply指令來指定在某個ID的線程上運作gdb指令,比如下面的指令就是在fuse程序的1至250号線程上運作bt指令,然後把所有線程的”bt”輸出統一定位到fuse.bt檔案當中去。參考下面的指令可以得到所有線程的使用者态的堆棧
gdb -q --batch -ex "thread apply 1-250 bt" attach `pidof fuse` | tee /home/qsia/fuse.bt
2.如何在程式運作的過程中修改某個變量的值?
gdb的attach指令能夠和正在運作的程序相關聯,而''--ex”能夠指定期望運作的gdb指令,再加上 表示屏蔽版本等資訊的-q和表示批處理—batch的參數,就組成了能在程式運作時修改變量的參數組合。比如下面的指令,就在sksmon程序運作時,動态地修改了它的mask的值:
sudo gdb -q --batch --ex "set msk=0" attach `pidofsksmon`
如果這個指令和上面的thread apply指令相結合,我們就能寫出模拟多線程運作多種中間狀态的腳本,這樣能夠極大的友善調試。
3.如何檢視多線程程式的所有核心堆棧?
有時,我們需要檢視多線程的程式的所有核心态堆棧,這時我們就需要充分利用Linux系統/proc檔案系統的特性,進入到/proc下對應程序相關線程的目錄,讀出各自的”stack”資訊。
cd /proc/`pidof yourprgoram_name`;
for i in `find ./ -name "stack"`; do echo $i >> ~/proc_search.log; cat $i >> ~/proc_search.log; done
4.如何分析程式關鍵函數的性能?
分析程式性能的工具很多,包括opprofile/systemtap等。Opprofile能夠從CPU晶片和核心級别,給出系統的性能統計和分析,包括耗費CPU周期、Cache命中率等;而systemtap類似于SUN引入的DTrace,能夠通過符号表生成可自動加載的探測驅動,進而能夠統計系統運作時間、在指定函數插入特定函數。
針對特定業務應用的開發,一般而言,systemtap足夠勝任。
4.1 systemtap的安裝
For Fedora/Centos/Redhat:
yum install systemtap
yum install kernel-devel gcc make
Prepare kernel debug information:
yum install yum-utils
debuginfo-install kernel
For ubuntu,Do it all with apt-get:
apt-get install systemtap
apt-get install linux-headers-generic gcc make
apt-get install linux-image-debug-generic
ln -s /boot/vmlinux-debug-$(uname -r) \
/lib/modules/$(uname -r)/vmlinux
4.2檢查sysstemtap是否安裝成功
運作指令 stap -v -e 'probe vfs.read {printf("read performed\n"); exit()}'
如果輸出正常就沒有問題,否則安裝還有問題。
4.3如何編寫stap監控腳本
和DTrace類似,systemtap運作的時候也需要stap腳本,請參考http://sourceware.org/systemtap/, 裡面有非常完整的介紹。示例代碼如下:
# Show sockets setting options# Return enabled or disabled based on value of optvalfunction getstatus(optval){ if ( optval == 1 ) return "enabling" else return "disabling"}probe begin{ print ("\nChecking for apps setting socket options\n")}# Set a socket optionprobe tcp.setsockopt{ status = getstatus(user_int($optval)) printf (" App '%s' (PID %d) is %s socket option %s... ", execname(), pid(), status, optstr)}# Check setting the socket option workedprobe tcp.setsockopt.return{ if ( ret == 0 ) printf ("success") else printf ("failed") printf ("\n")}probe end{ print ("\nClosing down\n")}
本文轉自存儲之廚51CTO部落格,原文連結:http://blog.51cto.com/xiamachao/1832608 ,如需轉載請自行聯系原作者