前言
在Ubuntu下调试程序,大部分是启动前使用gdb进行调试,当然也有其他方法,程序在运行中,为了不打断程序正常运行,也有一些工具进行调试。
当前本文章旨在说明不安装其他额外程序或库(除gdb外),并且在程序占用CPU过高想查看那些函数或库导致的,可使用如下方式。
Gstack
查看进程堆栈信息,Java推出jstack可以查看,C++也可以使用名为gstack命令进行查看,在本文作者查找gstack如何在ubuntu安装时遇到问题,只看到有gstack命令使用或介绍,并为搜索到安装命令,但在外网有幸找到,使用起来也挺方便,基本思路如下:
- 自己编写的程序CPU占用较高,程序名为`talker`
- 查看自己程序pid,如当前程序`talker`主进程号为:18666
- 使用Top -Hp 18666查看线程号,锁定占用CPU过高进程,如18677
- 使用gstack 18677,可打印堆栈信息,并得出所在库或函数占用较高问题
代码
关于gstack代码如下,创建名为`gstack`文件,填写内容:
#!/bin/shif test $# -ne 1; thenecho "Usage: `basename $0 .sh` <process-id>" 1>&2exit 1
fiif test ! -r /proc/$1; thenecho "Process $1 not found." 1>&2exit 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 ; thenbacktrace="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 ; thenbacktrace="thread apply all bt"fi
fiGDB=${GDB:-/usr/bin/gdb}if $GDB -nx --quiet --batch --readnever > /dev/null 2>&1; thenreadnever=--readnever
elsereadnever=
fi# Run GDB, strip out unwanted noise.
$GDB --quiet $readnever -nx /proc/$1/exe $1 <<EOF 2>&1 |
set width 0
set height 0
set pagination no
$backtrace
EOF
/bin/sed -n \-e 's/^\((gdb) \)*//' \-e '/^#/p' \-e '/^Thread/p'
#end
保存后,将此文件赋予可执行权限如:
sudo chmod 777 gstack
随后将此文件存放至/usr/bin下
sudo cp gstack /usr/bin/
至此gstack安装完毕
使用
假设,当前程序`talker`程序占用较高,查看pid得出:
test@test:~$ ps -ef | grep talker
test 18666 12982 0 16:07 pts/11 00:00:00 /opt/ros/kinetic/lib/roscpp_tutorials/talker
查看得出当前`talker`占用进程为:18666
查看此程序线程如下:
test@test:~$ top -Hp 18666top - 16:10:40 up 3 days, 7:45, 1 user, load average: 1.28, 1.53, 1.87
Threads: 5 total, 0 running, 5 sleeping, 0 stopped, 0 zombie
%Cpu(s): 24.2 us, 10.0 sy, 1.0 ni, 64.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 16048740 total, 1877016 free, 10243696 used, 3928028 buff/cache
KiB Swap: 999420 total, 356972 free, 642448 used. 4216300 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
18666 test 20 0 334212 10204 9308 S 0.0 0.1 0:00.24 talker
18677 test 20 0 334212 10204 9308 S 0.0 0.1 0:00.06 talker
18678 test 20 0 334212 10204 9308 S 0.0 0.1 0:00.02 talker
18679 test 20 0 334212 10204 9308 S 0.0 0.1 0:00.08 talker
18684 test 20 0 334212 10204 9308 S 0.0 0.1 0:00.03 talker
假设当前线程中`18677`占用CPU较高,可使用gstack查看此线程堆栈:
test@test:~$ sudo gstack 18677
Thread 1 (Thread 0x7f2fc158f700 (LWP 12194)):
#0 0x00007f2fc68c2b13 in epoll_wait () at ../sysdeps/unix/syscall-template.S:84
#1 0x00007f2fc78667e7 in ros::poll_sockets(int, pollfd*, unsigned long, int) () from /opt/ros/kinetic/lib/libroscpp.so
#2 0x00007f2fc78efdb9 in ros::PollSet::update(int) () from /opt/ros/kinetic/lib/libroscpp.so
#3 0x00007f2fc7875825 in ros::PollManager::threadFunc() () from /opt/ros/kinetic/lib/libroscpp.so
#4 0x00007f2fc5f7b5d5 in ?? () from /usr/lib/x86_64-linux-gnu/libboost_thread.so.1.58.0
#5 0x00007f2fc5b4c6ba in start_thread (arg=0x7f2fc158f700) at pthread_create.c:333
#6 0x00007f2fc68c251d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109
查看此线程堆栈可知,CPU占用是由ros::poll_sockets导致,这样就可以根据此信息锁定函数并进行对应修改。
如果有其他方便方式查看运行中程序CPU占用较高进行排查的方法,欢迎分享~