天天看點

程式調試和性能分析常用技巧

程式調試和性能分析常用技巧

程式調試和性能分析通常需要設計到多種工具,有時甚至需要跨越使用者态和核心态。本文總結了在程式調試和性能分析過程中常碰到三個問題,既是為了友善自己後面溫習,也是為了和碰到同樣問題的朋友一起分享。

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 ,如需轉載請自行聯系原作者

繼續閱讀