完善的调试方式和监控管理

调试方式(完善的调试方式和监控管理)
一、监控管理(监控进程)
1、内存检测

每个10秒检测内存,若可用内存小于15%,进行释放系统缓存,提高内存的利用率,并记录日志。
利用sysinfo获取内存大小,或者free命令获取

struct sysinfo s_info;
sysinfo(&s_info);

系统缓存释放

nret = system("sync;sync");//先同步,防止数据丢失
nret = system("echo 3 > /proc/sys/vm/drop_caches");
nret = system("echo 1 > /proc/sys/vm/overcommit_memory");
nret = system("free");

2、CPU检测
每10分钟检测一次CPU状态,发现连续3次超过80%,记录日志
CPU的计算公式
首先从/proc/stat中获取 t1时刻系统总体的user、nice、system、idle、iowait、irq、softirq的值,得到此时Total CPU time since boot(记为total1)和 Total CPU idle time since boot(记为idle1)。
其次,从/proc/stat中获取t2时刻系统总的Total CPU time since boot(记为total2)和Total CPU idle time since boot(记为idle2)。(方法同上一步)
最后,计算t2与t1之间系统总的CPU使用情况。也就是:
CPU percentage between t1 and t2 = ((total2-total1)-(idle2-idle1))/(total2-total1)* 100%

3、检测指定线程是否存在

ps -T|grep thread_name|grep -v grep|grep app$|wc -l

thread_name为指定线程的名字,结果为在app进程内计算线程thread_name的个数,为1,则代表存在,反之,不存在。

4、线程卡死状态监测
进程或者线程切换分为自愿切换(Voluntary)和强制切换(Involuntary),如果他们切换的次数不变,说明进程或者线程已经卡住,以此来检测线程是否卡死状态。

pid为进程的pid,以下命令可以打印出该进程的所有线程名称、线程的pid、自愿切换的次数、强制切换的次数。

for file in /proc/pid/task/* ;do oneline=`grep -w -E 'Name|Pid|voluntary_ctxt_switches|nonvoluntary_ctxt_switches' $file/status` ;echo $oneline|awk '{print $2,$4,$6,$8}';done

另外,如果一个进程的自愿切换占多数,意味着它对CPU资源的需求不高。如果一个进程的强制切换占多数,意味着对它来说CPU资源可能是个瓶颈,这里需要排除进程频繁调用sched_yield()导致强制切换的情况。

5、业务相关的检测
例如IPC业务,可以检测vi中断 和 venc 帧率是否正常

二、完善的调试方式
1、背景描述
一个完整项目或多或少会出现一些bug,而且有些bug是隐式的,有些是低概率性的,不好被发现,所以预防的措施就显得很重要。程序中常见的bug有概率性程序崩溃或段错误、程序出现死锁、内存泄露、文件句柄泄露等。
(1)概率性程序崩溃或段错误的排查
coredump定位

backtrace栈回溯

交叉栈回溯

GDB工具调试

以上介绍了四种处理段错误的方法,其中gdb工具是最好的段错误调试工具,打印信息齐全,但只适合于调试阶段,不适合于发布阶段。栈回溯backtrace适用于调试和发布阶段,但打印信息比gdb差,无法打印行号。在内存和flash特别小的时候也不适用。交叉栈回溯与栈回溯backtrace基本一样,比栈回溯backtrace好在可以适用于flash和内存比较小的程序,当同样也不能打印行号。
(2)内存泄露、文件句柄泄露的预防
在开发中,经常会使用malloc,free分配释放堆内存,使用open、close或者fopen、fclose来打开、关闭文件,使用socket、close创建、关闭套接字等
当这些使用不配对时,就会导致内存泄漏的问题,进而可能会导致设备异常重启或死机现象。
这里可通过二次封装的方法来来预防内存泄漏,以malloc、free为例,主要表现是分别记录不同地方调用malloc、free的次数,来判断malloc、free是否配对使用,如果不配对使用,可以帮助定位到哪个地方是不配对使用的,以此达到内存泄漏定位的效果。
内存泄露、文件句柄泄露的预防

(3)程序出现死锁排查
进程或者线程出现死锁,就会卡住。前面介绍到,可通过线程卡死状态监测,即可判断哪个线程卡住,具体卡在哪,可通过在线调试GDB的方法,切换到对应线程,如果然后打印栈信息,即可定位线程卡死的位置。
GDB工具调试

三、调试信息的规范管理
调试信息一般有两种,一种是可控,一种是不可控。不可控的调试信息一般用于调试阶段,像printf,直接打印。可控调试信息,一般用于维护阶段,通过一个开关去控制信息是否需要打印,避免所有调试信息全部打印,造成查看不变,关健信息难帅选的麻烦。
1、调试信息的打印使用要方便且详细
printf的封装可以加上对应的文件名、函数名,行号,方便调试定位。

#define DH(fmt, args...)  
printf("%s-%s-%d:" fmt,  __FILE__,__FUNCTION__,__LINE__, ## args)

2、按模块划分并控制打印信息,各个模块调试信息不影响
调试信息的控制有两种方式,一是总控制,总控制控制所有模块的信息的打印。另一种是模块控制,每个模块都有自己的调试信息的控制开关。

3、重要的调试信息需要存在保存到磁盘中,像重启日志,错误日志,提醒日志等。

猜你喜欢

转载自blog.csdn.net/weixin_40732273/article/details/109261376