在比较大型的项目中,通常都会使用多线程技术,而且通常是多人合作开发,各方自测OK之后,整合在一起往往会出现一些问题,CPU使用率过高就是其中之一。如何在不熟悉所有模块代码的情况下,快速的定位到具体哪一个线程在消耗CPU,显得很有必要。在X86上,可以借助一些工具进行定位分析,但是在嵌入式系统中,工具就比较匮乏,各命令功能也比较简单,就不好定位。
现介绍一种简单通用的办法:
1.获取各个线程的tid
ps查看进程
root@zihome:/proc/2111# ps | grep ZGateway
2111 root 76112 S {MainThread} /zihome/plugins/zgateway/ZGateway /dev/ttyS2 /dev/ttyS1
2114 root 1520 S {ZGatewayTimerCh} /bin/sh /zihome/plugins/zgateway/ZGatewayTimerCheck.sh /zihome/plugins/zgateway/run.sh
12072 root 1520 S grep ZGateway
然后在proc/$pid/task/下面可以看到所有线程
root@zihome:/proc/2111/task# ls
2111 2139 2670 2697 2730 2733 2743 2748 2781 2790 2793 2803 2806
2133 2140 2695 2698 2731 2741 2744 2779 2788 2791 2794 2804
2135 2669 2696 2728 2732 2742 2746 2780 2789 2792 2802 2805
有37个,但是我们不知道每个线程对应的是代码里面的哪个线程,这就需要我们在代码里面添加线程号tid的获取,在代码里面将线程号和线程名字对应上。
+#include <sys/syscall.h>
+#define gettid() syscall(SYS_gettid)
在代码线程的main函数里面添加gettid进行打印
printf("\n%s Thread id : gettid() == %d\n",__FUNCTION__,gettid());
这样就知道tid对应的线程名称
2.获取线程CPU运行时间
[root@localhost ~]# cat /proc/6873/stat
6873 (a.out) R 6723 6873 6723 34819 6873 8388608 77 0 0 0 41958 31 0 0 25 0 3 0 5882654 1409024 56 4294967295 134512640 134513720 3215579040 0 2097798 0 0 0 0 0 0 0 17 0 0 0 [root@localhost ~]#
每个参数意思为:
参数 解释
pid=6873 进程(包括轻量级进程,即线程)号
comm=a.out 应用程序或命令的名字
task_state=R 任务的状态,R:runnign, S:sleeping (TASK_INTERRUPTIBLE), D:disk sleep (TASK_UNINTERRUPTIBLE), T: stopped, T:tracing stop,Z:zombie, X:dead
ppid=6723 父进程ID
pgid=6873 线程组号
sid=6723 该任务所在的会话组ID
tty_nr=34819(pts/3) 该任务的tty终端的设备号,INT(34817/256)=主设备号,(34817-主设备号)=次设备号
tty_pgrp=6873 终端的进程组号,当前运行在该任务所在终端的前台任务(包括shell 应用程序)的PID。
task->flags=8388608 进程标志位,查看该任务的特性
min_flt=77 该任务不需要从硬盘拷数据而发生的缺页(次缺页)的次数
cmin_flt=0 累计的该任务的所有的waited-for进程曾经发生的次缺页的次数目
maj_flt=0 该任务需要从硬盘拷数据而发生的缺页(主缺页)的次数
cmaj_flt=0 累计的该任务的所有的waited-for进程曾经发生的主缺页的次数目
utime=1587 该任务在用户态运行的时间,单位为jiffies
stime=1 该任务在核心态运行的时间,单位为jiffies
cutime=0 累计的该任务的所有的waited-for进程曾经在用户态运行的时间,单位为jiffies
cstime=0 累计的该任务的所有的waited-for进程曾经在核心态运行的时间,单位为jiffies
priority=25 任务的动态优先级
nice=0 任务的静态优先级
num_threads=3 该任务所在的线程组里线程的个数
it_real_value=0 由于计时间隔导致的下一个 SIGALRM 发送进程的时延,以 jiffy 为单位.
start_time=5882654 该任务启动的时间,单位为jiffies
vsize=1409024(page) 该任务的虚拟地址空间大小
rss=56(page) 该任务当前驻留物理地址空间的大小
Number of pages the process has in real memory,minu 3 for administrative purpose.
这些页可能用于代码,数据和栈。
rlim=4294967295(bytes) 该任务能驻留物理地址空间的最大值
start_code=134512640 该任务在虚拟地址空间的代码段的起始地址
end_code=134513720 该任务在虚拟地址空间的代码段的结束地址
start_stack=3215579040 该任务在虚拟地址空间的栈的结束地址
kstkesp=0 esp(32 位堆栈指针) 的当前值, 与在进程的内核堆栈页得到的一致.
kstkeip=2097798 指向将要执行的指令的指针, EIP(32 位指令指针)的当前值.
pendingsig=0 待处理信号的位图,记录发送给进程的普通信号
block_sig=0 阻塞信号的位图
sigign=0 忽略的信号的位图
sigcatch=082985 被俘获的信号的位图
wchan=0 如果该进程是睡眠状态,该值给出调度的调用点
nswap 被swapped的页数,当前没用
cnswap 所有子进程被swapped的页数的和,当前没用
exit_signal=17 该进程结束时,向父进程所发送的信号
task_cpu(task)=0 运行在哪个CPU上
task_rt_priority=0 实时进程的相对优先级别
task_policy=0 进程的调度策略,0=非实时进程,1=FIFO实时进程;2=RR实时进程
编写获取所有线程tid、用户层CPU使用、内核态CPU使用,数值越高表示消耗CPU资源越多get_tid_cpu.sh
#!/bin/sh
#get /proc/pid/task/tid/stat
#$1 is tid
#$14 is user cpu
#$15 is sys cpu
echo "tid user sys"
for file in /proc/$1/task/*
do
if test -d $file
then
cat $file/stat | awk -F" " '{print $1 " " $14 " " $15}'
fi
done
root@zihome:/zihome/plugins# ./get_tid_cpu.sh 11598
tid user sys
11598 48 187
11621 6 7
11622 109 17
11623 0 0
11624 0 0
11723 1 1
11724 9 0
11742 3 1
11743 0 0
11744 4 1
11745 0 0
11758 2 1
11759 0 0
11760 0 1
11761 1 0
11762 0 0
11764 1 0
11767 0 2
11768 0 0
11770 0 0
11771 0 0
11772 0 0
11787 182 8
11810 0 5
11811 5 0
11812 3 1
11819 1 3
11820 0 0
11821 0 1
11822 0 0
11823 0 0
11824 5 2
11826 0 0
11833 7 6
11834 1 0
11835 0 0
11836 0 2
11837 0 1
tid user sys
11598 71 191
11621 25 53
11622 214 23
11724 21 3
11742 24 8
11744 49 9
11745 7 3
11758 9 13
11787 1410 33
11810 3 12
11811 7 14
11812 4 3
11819 2 4
11820 7 0
11821 18 12
11822 5 7
11824 18 10
11826 3 3
11833 17 49
11834 9 17
11836 10 15
HttpWrapper Thread id : gettid() == 11622
DeviceMultipleService Thread id : gettid() == 11623
MqttManager Thread id : gettid() == 11723
DusunZigbeeController Thread id : gettid() == 11744
handleSendUbusData Thread id : gettid() == 11745
mqttHandlerConnect Thread id : gettid() == 11758
parseUdpBroadcast Thread id : gettid() == 11759
handleSendUartData Thread id : gettid() == 11762
handleUartData Thread id : gettid() == 11761
HaierController Thread id : gettid() == 11826
expireThread Thread id : gettid() == 11834
handleMessage Thread id : gettid() == 11835
定位具体线程,分析什么原因导致cpu使用率高
嵌入式linux下线程CPU占用跟踪: https://blog.csdn.net/wofeile880_jian/article/details/77584842