程序调试和性能分析经常使用技巧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")}