程序調試和性能分析經常使用技巧linux
程序調試和性能分析一般須要設計到多種工具,有時甚至須要跨越用戶態和內核態。本文總結了在程序調試和性能分析過程當中常碰到三個問題,既是爲了方便本身後面溫習,也是爲了和碰到一樣問題的朋友一塊兒分享。ubuntu
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.btapp
2.如何在程序運行的過程當中修改某個變量的值?socket
gdb的attach命令可以和正在運行的進程相關聯,而''--ex」可以指按期望運行的gdb命令,再加上 表示屏蔽版本等信息的-q和表示批處理—batch的參數,就組成了能在程序運行時修改變量的參數組合。好比下面的命令,就在sksmon進程運行時,動態地修改了它的mask的值:tcp
sudo gdb -q --batch --ex "set msk=0" attach `pidofsksmon` ide
若是這個命令和上面的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
Prepare kernel debug information:
apt-get install linux-p_w_picpath-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")}