gdb工具打印函数调用栈

可以使用该脚本打印出当前进程的调用栈,当CPU使用率100%时候,你可以使用此脚本得知应用程序在忙什么,对应用程序进程调试

当然如果你应用程序性能不足,你正无助时,可以多次使用此脚本,你可以大概得知程序调用栈所耗损的地方,找到性能调试的关键点

我曾经遇到过CPU使用率不高,服务端程序性能严重不足情况,我使用了此脚本找到了io处理的一个全局锁,在修改优化此全局锁后,大大提升了服务端程序的性能

调用栈打印脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
[root@localhost ~]# cat pstack.sh
#!/bin/sh

if test $# -ne 1; then
echo "Usage: `basename $0 .sh` <process-id>" 1>&2
exit 1
fi

if test ! -r /proc/$1; then
echo "Process $1 not found." 1>&2
exit 1
fi

# GDB doesn't allow "thread apply all bt" when the process isn't
# threaded; need to peek at the process to determine if that or the
# simpler "bt" should be used.

backtrace="bt"
if test -d /proc/$1/task ; then
# Newer kernel; has a task/ directory.
if test `/bin/ls /proc/$1/task | /usr/bin/wc -l` -gt 1 2>/dev/null ; then
backtrace="thread apply all bt"
fi
elif test -f /proc/$1/maps ; then
# Older kernel; go by it loading libpthread.
if /bin/grep -e libpthread /proc/$1/maps > /dev/null 2>&1 ; then
backtrace="thread apply all bt"
fi
fi

GDB=${GDB:-/usr/bin/gdb}

if $GDB -nx --quiet --batch --readnever > /dev/null 2>&1; then
readnever=--readnever
else
readnever=
fi

# Run GDB, strip out unwanted noise.
$GDB --quiet $readnever -nx /proc/$1/exe $1 <<EOF 2>&1 |
$backtrace
EOF
/bin/sed -n \
-e 's/^(gdb) //' \
-e '/^#/p' \
-e '/^Thread/p'

脚本使用方法

sh pstack.sh \<pid>

使用例子:

1
2
3
4
5
[root@localhost ~]# sh pstack.sh 1471
#0 0x00007f9de5afe190 in __nanosleep_nocancel () from /lib64/libc.so.6
#1 0x00007f9de5afe044 in sleep () from /lib64/libc.so.6
#2 0x0000000000400810 in ha_ha ()
#3 0x0000000000400ae7 in main ()