10条关于嵌入式软件开发测试的秘诀,知道

10条关于嵌入式软件开发测试的秘诀,知道

在嵌入式软件开发进程中,一般来说,花在测试和花在编码的时间比为3:1(实际上可能更多)。这个比例随着你的编程和测试水平的提高而不断下落,但不论怎样,软件测试对常人来说很重要。很多年前,一名开发人员为了对嵌入式有更深层次的理解,向Oracle询问了这样的一个问题:我怎样才能知道并晓得我的系统到底在干些甚么呢?

Oracle面对这个问题有些吃惊,由于在当时没有人这么问过,而同时代的嵌入式开发人员问的最多的大都围绕“我怎样才能使程序跑的更快”、“甚么编译器最好”等浮浅的问题。所以,面对这个不同寻常却异乎成熟的问题,Oracle感到欣喜并认真回复了他:你的问题很有深度很成熟,由于只有不断地去深入理解才有可能不断地提高水平,并且Oracle为了鼓励这位执着的程序员,把10条关于嵌入式软件开发测试的秘诀告知了他。

这十条秘诀在业界广为流传,使很多人受益。本文围绕这十条秘诀展开论述。

1.晓得使用工具

通常嵌入式系统对可靠性的要求比较高。嵌入式系统安全性的失效可能会致使灾难性的后果,即便是非安全性系统,由于大批量生产也会致使严重的经济损失。这就要求对嵌入式系统,包括嵌入式软件进行严格的测试、确认和验证。随着愈来愈多的领域使用软件和微处理器控制各种嵌入式装备,对日趋复杂的嵌入式软件进行快速有效的测试越发显得重要。

就像修车需要工具一样,好的程序员应当能够熟练应用各种软件工具。不同的工具,有不同的使用范围,有不同的功能。使用这些工具,你可以看到你的系统在干些甚么,它又占用甚么资源,它到底和哪些外界的东西打交道。让你愁闷好几天的问题可能通过某个工具就能轻松搞定,惋惜你就是不知道。那末为何那么多的人总是在折腾个半死以后才想到要用测试工具呢?缘由很多,主要有两个。一个是畏惧,另一个是惰性。畏惧是由于加入测试工具或测试模块到代码需要技能同时有可能引入新的毛病,所以他们总喜欢寄希望于通过不断地修改重编译代码来消除bug,结果却杯水车薪。懒散是由于他们习惯了使用printf之类的简单测试手段。下面来介绍一些嵌入式经常使用的测试工具。

.源码级调试器[Source-levelDebugger]

这类调试器一般提供单步或多步调试、断点设置、内存检测、变量查看等功能,是嵌入式调试最根本有效的调试方法。比如VxWorksTornadoII提供的gdb就属于这一种。

.简单实用的打印显示工具[printf]

printf或其它类似的打印显示工具估计是最灵活最简单的调试工具。打印代码履行进程中的各种变量可以让你知道代码履行的情况。但是,printf对正常的代码履行干扰比较大(一般printf占用CPU比较长的时间),需要慎重使用,最好设置打印开关来控制打印。

.ICE或JTAG调试器[In-circuitEmulator]

ICE是用来仿真CPU核心的装备,它可以在不干扰运算器的正常运行情况下,实时的检测CPU的内部工作情况。像桌面调试软件所提供的:复杂的条件断点、先进的实时跟踪、性能分析和端口分析这些功能,它也都能提供。ICE一般都有一个比较特殊的CPU,称为外合(bond-out)CPU。这是一种被打开了封装的CPU,并且通过特殊的连接,可以访问到CPU的内部信号,而这些信号,在CPU被封装时,是没法“看到”的。当和工作站上强大的调试软件联合使用时,ICE就能提供你所能找到的最全面的调试功能。但ICE一样有一些缺点:昂贵;不能全速工作;一样,并不是所有的CPU都可以作为外合CPU的,从另一个角度说,这些外合CPU也不大可能及时的被新出的CPU所更换。JTAG(JointTestActionGroup)虽然它最初开发出来是为了监测IC和电路连接,但是这类串行接口扩大了用处,包括对调试的支持。

.ROM监视器[ROMMonitor]

ROM监控器是一小程序,驻留在嵌入系统ROM中,通过串行的或络的连接和运行在工作站上的调试软件通讯。这是一种便宜的方式,固然也是最低端的技术。它除要求一个通讯端口和少许的内存空间外,不需要其它任何专门的硬件。并提供了以下功能:下载代码、运行控制、断点、单步步进、和视察、修改寄存器和内存。由于ROM监控器是操作软件的一部分,只有当你的应用程序运行时,它才会工作。如果你想检查CPU和应用程序的状态,你就必须停下应用程序,再次进入ROM监控器。

.Data监视器[DataMonitor]

这类监视器在不停止CPU运行的情况下不但可以显示指定变量内容,还可以搜集并以图形情势显示各个变量的变化进程。

.OS监视器[OperatingSystemMonitor]

操作系统监视器可以显示诸如任务切换、信号量收发、中断等事件。一方面,这些监视器能够为你出现事件之间的关系和时间联系;另一方面,还可以提供对信号量优先级反转、死锁和中断延时等问题的诊断。

.性能分析工具[Profiler]

可以用来测试CPU到底耗在那里,profiler工具可以让你知道系统的瓶颈在那里、CPU的使用率和需要优化的地方。

.内存测试工具[MemoryTeseter]

可以找到内存使用的问题所在,比如内存泄漏、内存碎片、内存崩溃等问题。如果发现系统出现一些不可预知的或间歇性的问题,就应当使用内存测试工具测测看。

.运行跟踪器[ExecutionTracer]

可以显示CPU履行了哪些函数、谁在调用、参数是什么、什么时候调用等情况。这类工具主要用于测试代码逻辑,可以在大量的事件中发现异常的那些。

.覆盖工具[CoverageTester]

主要显示CPU具体履行了那些代码,并让你知道那些代码分支没有被履行到。这样有助于提高代码质量并消除无用代码。

.GUI测试工具[GUITester]

很多嵌入式运用带有某种情势的图形用户界面进行交互,有些系统性能测试是根据用户输入响应时间进行的。GUI测试工具可以作为脚本工具有开发环境中运行测试用例,其功能包括对操作的记录和回放、抓取屏幕显示供以后分析和比较、设置和管理测试进程(Rational公司的robot和Mercury的Loadrunner工具是杰出的代表)。很多嵌入式装备没有GUI,但常常可以对嵌入式装备进行插装来运行GUI测试脚本,虽然这类方式可能要求对被测代码进行更改,但是节省了功能测试和回归测试的时间。

.自制工具[Home-madetester]

在嵌入式运用中,有时候为了特定的目的,需要自行编写一些工具来到达某种测试目的。本人曾编写的视频流录显工具在测试视频会议数据流向和变化上帮了大忙,帮公司找到了几个隐藏很深的bug。

2.尽早发现内存问题

内存问题危害很大,不容易排查,主要有3种类型:内存泄漏、内存碎片和内存崩溃。对内存问题态度必须要明确,那就是早发现早“医治”。在软件设计中,内存泄漏的“名望”最大,主要由于不断分配的内存没法及时地被释放,长此以往,系统的内存耗尽。即便仔细的编程老手有时后也会遭受内存泄漏问题。有测试过内存泄漏的朋友估计都有深入地体验,那就是内存泄漏问题一般隐藏很深,很难通过代码浏览来发现。有些内存泄漏乃至可能出现在库当中。有可能这本身是库中的bug,也有可能是由于程序员没有正确理解它们的接口说明文档造成错用。

在很多时候,大多数的内存泄漏问题没法探测,但可能表现为随机的故障。程序员们常常会把这类现象怪罪于硬件问题。如果用户对系统稳定性不是很高,那末重启系统问题也不大;但如果用户对系统稳定很高,那末这类故障就有可能使用户对产品失去信心,同时也意味着你的项目是个失败的项目。由于内存泄漏危害巨大,现在已有许多工具来解决这个问题。这些工具通过查找没有援用或重复使用的代码块、垃圾内存搜集、库跟踪等技术来发现内存泄漏的问题。每一个工具都有利有弊,不过总的来说,用要比不用好。总之,负责的开发人员应当去测试内存泄漏的问题,做到防患于未然。

内存碎片比内存泄漏隐藏还要深。随着内存的不断分配并释放,大块内存不断分解为小块内存,从而构成碎片,长此以往,当需要申请大块内存是,有可能就会失败。如果系统内存够大,那末坚持的时间会长一些,但终究还是逃不出分配失败的恶运。在使用动态分配的系统中,内存碎片常常产生。目前,解决这个问题最效的方法就是使用工具通过显示系统中内存的使用情况来发现谁是致使内存碎片的罪魁祸首,然后改进相应的部份。

由于动态内存管理的种种问题,在嵌入式运用中,很多公司干脆就禁用malloc/free的以绝后患。

内存崩溃是内存使用最严重的结果,主要原因有数组访问越界、写已释放的内存、指针计算毛病、访问堆栈地址越界等等。

这类内存崩溃造成系统故障是随机的,而且很难查找,目前提供用于排查的工具也很少。

总之,如果要使用内存管理单元的话,必须要当心,并严格遵守它们的使用规则,比如谁分配谁释放。

3.深入理解代码优化

讲到系统稳定性,人们更多地会想到实时性和速度,由于代码效力对嵌入式系统来讲太重要了。知道怎样优化代码是每一个嵌入式软件开发人员必须具有的技能。就像女孩子减肥一样,最少知道她哪一个地方最需要减,才能去购买减肥药或器材来减掉它。可见,代码优化的条件是找到真正需要优化的地方,然后对症下药,优化相应部份的代码。前面提到的profile(性能分析工具,一些功能齐全IDE都提供这类内置的工具)能够记录各种情况比如各个任务的CPU占用、各个任务的优先级是不是分配妥当、某个数据被拷贝了多少次、访问磁盘多少次、是不是调用了络收发的程序、测试代码是不是已关闭等等。

但是,profile工具在分析实时系统性能方面还是有不够的地方。一方面,人们使用profile工具常常是在系统出现问题即CPU耗尽以后,而profile工具本身对CPU占用较大,所以profile对这种情况极可能不起作用。根据Heisenberg效应,任何测试手段或多或少都会改变系统运行,这个对profiler一样适用!

总之,提高运行效力的条件是你必须要知道CPU到底干了些甚么干的怎样。

4.不要让自己大海捞针

大海捞针只是对调试的一种生动比喻。常常听到组里有人对自己正在调试的代码说shit!可以理解,由于代码不是他写的,他有足够的理由去shitbug百出的代码,只要他自己不要写出这类代码,否则有一天同组的其它人可能一样会shit他写的代码。为什么会有大海捞针呢?肯定是有人把针掉到海里咯;那针为什么会掉在海里呢?肯定是有人不当心或草率呗。所以当你在抱怨针那末难找的时候,你是不是想过是你自己草率地丢掉的。一样,当你调试个半死的时候,你是不是想过你要好好检讨一下当初为了寻求捷径可能没有严格地遵照好的编码设计规范、没有检测一些假定条件或算法的正确性、没有将一些可能存在问题的代码打上记号呢?关于如何写高质量请参考林锐的《高质量c++/c编程指南》或《关于C的0x8本“经书》。

如果你确切已把针掉在海里是,为了避免在找到之前刺到自己,你必须要做一些防范工作,比如戴上安全手套。一样,为了尽能地暴露和捕捉问题本源,我们可以设计比较全面的毛病跟踪代码。怎样来做呢?尽量对每一个函数调用失败作出处理,尽量检测每一个参数输入输出的有效性,包括指针和检测是不是过量或过少地调用某个进程。毛病跟踪能够让你知道你大概把针掉在哪一个位置。

5.重现并隔离问题

如果你不是把针掉在大海了,而是掉在草堆里,那要好办些。由于最少我们可以把草堆分成很多块,一块一块的找。对模块独立的大型项目,使用隔离方法常常是对付那些隐藏极深bug的最后方法。如果问题的出现是间歇性的,我们有必要想法去重现它并记录使其重现的整个过程以备在下一次可以利用这些条件去重现问题。如果你确信可以使用记录的那些条件去重现问题,那末我们就可以着手去隔离问题。怎样隔离呢?我们可以用#ifdef把一些可能和问题无关的代码关闭,把系统最小化到仍能够重现问题的地步。如果还是没法定位问题所在,那末有必要打开“工具箱”了。可以试着用ICE或数据监视器去查看某个可疑变量的变化;可以使用跟踪工具取得函数调用的情况包括参数的传递;检查内存是不是崩溃和堆栈溢出的问题。

6.以退为进

猎人为了不使自己在森林里迷路,他常常会在树木上流下一些标记,以备自己将来有一天迷路时可以根据这些标记找到前途。

对过去代码的修改进行跟踪记录对将来出现问题以后的调试很有帮助。假设有一天,你最近一次修改的程序跑了很久以后忽然死掉了,那末你这时候的第一反应就是我到底改动了些甚么呢,由于上次修改之前是好的。那末如何检测这次相对上次的修改呢?没错,代码控制系统SCS或称版本控制系统VCS(ConcurrentVersionControl,CVS是VCS的演变版本)。将上个版本checkin下来后和当前测试版本比较。比较的工具可以是SCS/VCS/CVS自带的diff工具或其它功能更强的比较工具,比如BeyondCompare和ExamDiff。通过比较,记录所有改动的代码,分析所有可能致使问题的可疑代码。

7.肯定测试的完整性

你怎样知道你的测试有多全面呢?覆盖测试(coveragetesting)可以回答这个问题。覆盖测试工具可以告知你CPU到底履行了那些代码。好的覆盖工具通常可以告知你大概20%到40%代码没有问题,而其余的可能存在bug。覆盖工具有不同的测试级别,用户可以根据自己的需要选择某个级别。即便你很确信你的单元测试已很全面并且没有deadcode,覆盖工具还是可以为你指出一些潜伏的问题,看下面的代码:if(i=0(almostAlwaysZero==0(last=i)))如果almostAlwaysZero为非0,那末last=i赋值语句就被跳过,这可能不是你所期望的。这类问题通过覆盖工具的条件测试功能可以轻松的被发现。总之,覆盖测试对提高代码质量很有帮助。

8.提高代码质量意味着节省时间

有研究表明,软件开发的时间超过80%被用在下面几个方面:调试自己的代码(单元测试);调试自己和其他相干的代码(模块间测试);调试全部系统(系统测试),更糟的是你可能需要花费10-倍的时间来找一个bug,而这个bug在开始的时候可能很容易就能找到。一个小bug可能让你付出巨大的代价,即便这个bug对全部系统的性能没有太大的影响,但极可能会影响让那些你可以看得到的部份。所以我们必须要养成良好的编码和测试手段以求更高的代码质量,以便缩短调试的代码。

9.发现它,分析它,解决它

这世界没有万能的膏药。profile再强大也有力不从心的时候;内存监视器再好,也有没法发现的时候;覆盖工具再好用,也有不能覆盖的地方。一些隐藏很深的问题即便用尽所有工具也有可能没法查到其本源,这时候我们能做的就是通过这些问题所表现出来的外在现象或一些数据输出来发现其中的规律或异常。一旦发现任何异常,一定要深入地理解并回溯其本源,直到解决为止。

10.利用初学者的思惟

有人这样说过:“有些事情在初学者的头脑里可能有各种各样的情况,可在专家的头脑里可能就很单一”。有时候,有些简单的问题会被想的很复杂,有些简单的系统被设计得很复杂,就是由于你的“专家思惟”。当你被问题难住时,关掉电脑,出去走走,把你的问题和你的朋友乃至你的小狗说说,也许他们可以给你意想不到的启发。

总结

嵌入式调试也是1门艺术。就想其它的艺术一样,如果你想获得成功,你必须具有智慧、经验并晓得使用工具。只要我们能够很好地领悟Oracle这10条秘诀,我相信我们在嵌入式测试方面就能够获得成功。

免责声明:本文系络转载,版权归原作者所有。如触及作品版权问题,请与我们联系,我们将根据您提供的版权证明材料确认版权并支付稿酬或删除内容。









































北京中科医院是假的吗
北京中科医院是假的吗



转载请注明:http://www.zjiaren.com/zyjs/686.html

  • 上一篇文章:
  •   
  • 下一篇文章: 没有了