Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1744457
  • 博文数量: 263
  • 博客积分: 1218
  • 博客等级: 少尉
  • 技术积分: 2862
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-19 02:33
文章分类

全部博文(263)

文章存档

2020年(12)

2019年(2)

2018年(10)

2016年(1)

2015年(20)

2014年(115)

2013年(46)

2012年(37)

2011年(20)

分类: 项目管理

2013-03-18 14:46:41

    说完编译和调试的效率,继续聊一下PM(项目管理)中程序调试的其它方法,比如两个支柱性的技术:Log系统和Dump工具。程序代码中,Log系统的设计越来越成熟,也越来越层次化,以利于调试和分析问题,Log系统一般是记录系统运行状况或问题的日志以供事后分析。程序调试的另一个支柱是实用的Dump工具,好的Dump工具或技术,它会让你的程序调试变得更轻松,一般Dump工具能输出程序运行过程中的实时数据。这两个关键的技术在解决BUG的实践中,往往也发挥了举足轻重的作用。

1.  Log的层次化
    Log/Trace要分层次和讲究主次。如果没有重点,海量Log将淹没关键信息;如果抓不住紧要的信息,解决问题无从谈起,调试之路漫漫长远;对于某些soaking类型的应用,不可能开放大量的Log,因为大量Log带来的I/O操作会严重拖慢系统的性能;而且另一方面,对于一个全新而陌生的模块或系统而言,关键流程上的Log信息能大大帮助对其的深入理解。
    通常的Log作法是将Log的级别分为四个,error,warning,info,debug。各个程序模块的Log等级一般可以在配置文件里面进行配置,比如配置文件叫module_plat.conf,每一行代表一个module的配置,格式如下:

    其中是指硬件+操作系统平台,是可执行文件或库的名字,是各级配置的开关,其值只能是0或1,表示关闭或使能本module的此级别Log。
    由于这种传统的分法过于笼统,不利于上述要求的达成。经过再分解和清晰化,Log层次可以这样设计:
    Debug     #这个Level的信息很多,用于深入细究时调查。
    Flow       #关键流程的信息,不能太多但紧要!相当于通常所说的Info。
    Warn      #一些不应该出现的警示,但不影响模块或系统的正常运行。
    Error       #一些简单的错误,但对模块或系统影响不大。
    Critical     #一些严重的错误,模块或系统已无继续运行的必要或可能,比如OOM或Panic。
    其中,Warn、Error和Critical层的Log一般常开。Debug层的Log一般不打开,也不适合soaking场景。Flow或Info层次的Log可以根据具体情况而进行调整,甚至再细分。个人觉得Flow级别的Log很重要,可以在各个模块或各个过程之间的接合带打印关键的信息,方便BUG的分离和定位,缩短调试和开发的时间,提高项目各domain合作的效率。通过对内核SCTP协议层的Debug系统进行调整重划分和信息补充,证明了此法行之有效。
    对于内核级别,Log Level的控制一般通过/proc/sys/*来配置。对于用户层的程序,一般通过信号的传递来控制Log Level。

2.  Dump工具
    Dump Tools的开发和使用也是一个有趣的话题。Dump工具用得顺手的话,也许会成为码农屌丝们逆袭的利器。可以自行开发Dump工具,也可以使用开源的工具。比如Windows系统下的ProcDumpLordPE(据说dump region功能非常强大)、ollydump(依托OD强大的功能)等工具。再比如Linux系统下的内核Dump工具Kdump/crash。
    Dump Tools主要是实时的打印出进程关键结构变量的状态和累计值,在不重装和重启进程的现场,为开发者提供原生态的关键信息和重要数据。比如内核网络模块TIPC中,提供了一个tipc-config工具,通过netllink从内核中获取TIPC协议层的运行状态数据,如一些工作队列的状态或某些counter信息。
    对于内核级别,一般通过netllink或/proc/*来获取dump信息。而对于用户层的程序,一般通过信号传递和信号捕获程序来实现随心所欲的信息跟踪。下面是一种用户层通行的做法。
    调试者对进程myprocess发出Dump命令:
kill -SIGUSR2 myprocess
    进程myprocess中main入口设定信号捕获程序signal_usr2_handler:
signal(SIGUSR2, signal_usr2_handler);
    信号捕获程序signal_usr2_handler中,实现对进程的状态跟踪和输出打印,一般是利用全局变量,也可以利用get_pointer来获取一个结构体的内存指针,再一一计算或直接打印输出你所关注的结构体的信息。
    当然你也可以把这些玩意做成一个库,以库和API的形式为所有进程提供通用的平台。一般来说,这个平台是针对特定场合的应用。或者,你也可以将这个库和API发布到互联网上,为开源世界贡献自己的智慧和力量。

3.  解决BUG
    开发中解BUG(de-bug),对于码农来说,就像每天吃饭喝水刷微博。如何快速的解决BUG呢,通过上面的两种工具可以起到很大的作用。这里补充说明一下另外两种极端的情况。
    一是在编译前期,大型项目开发中,为了保证代码的质量,比较重视代码静态检查(比如pclint工具)和自动验证(autosanity)。编译也可以采用多种平台下编译工具综合编译合格率的方式,比较常用的平台编译工具有MS的VC++系列,事实上这成为很多程序设计质量的标准之一。
    二是后期调试中,反汇编技术在汇编程序级的debug中也能发挥关键的作用。比如GDB工具找到了出错的哪一行代码,但未必能知道出错的原因,这时若能通过汇编代码来细究出错原因,必有所获。而且很多时候其实只知道出错的是哪一行汇编代码,不知道是哪一行C/C++代码,那么通过反汇编技术,将汇编代码还原成C/C++代码,也更容易找到程序出错所在。我的同事nana就精于此道。
    实际开发中,理想的状况是这样的。80%的BUG问题通过代码自动检查工具、编译工具、autosanity工具和TRACE/LOG工具发现并解决;15%的问题通过Dump工具发现并解决;剩下5%的问题让nana们反汇编解决吧~~~

阅读(1254) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~