wsxk / wsxk.github.io

MIT License
5 stars 0 forks source link

iot dev technology 5:系统整台 & & #158

Open wsxk opened 8 months ago

wsxk commented 8 months ago

https://wsxk.github.io/iot_dev_tech_five/

  1. 系统整台

    11.1 第一次整合 11.2 全功能整合 11.3 发行第一个版本

  1. 系统整台 11.1 第一次整合 第一次整合的最佳时间点一般会有以下几种情形: ■ 硬件设计不会再有大变化:基本组件与PIN脚配置都已确定,剩下的只是微调的工作而已,即以后硬件的调整‘应该’都不会影响到驱动程序。

■ 驱动程序已经稳定:‘稳定’的定义应该是通过长时间且大量的单元测试、整合测试与压力测试,其中压力测试对驱动程序的稳定度更显重要,单单验证驱动程序的正确性是不够的. 例如keyboard driver测试不能一个一个key慢慢按,至少必须测试快速且连续的按法,或者多个key同时被压下、某些key长时间被按下等。 除了使用‘较死板’测试手法之外,固件工程师还必须写作一些压力测试程序,例如长时间连续对存储器读写、利用信号发生器制作特殊信号输入到系统中,测试驱动程序是否仍可正常运行。 固件工程师必须自觉地做完这些测试,我们已经说过很多次了,底层的不稳定会随着被整合的程序增加而放大,稳定度是驱动程序最重要的基本需求之一。

■ 重要的系统功能都已完成:至少要整合的应用程序会用到的系统功能都必须完成。

■ 至少要有两个应用程序已完成所有功能,且已经请客户或规格制定者在模拟器上确认过其完成度。

当然因为现实原因,往往开始整合时,条件都有缺陷: 所以整合经常出现失败的情况,失败原因有如下几种: ■ 设计更改:设计阶段结束后还是有可能进行设计修改,可能因为来自客户的要求,或是在实作阶段才发现设计的瑕疵等原因,偏偏这个时间点正是兵荒马乱的时候,包含系统工程师,所有人都忙着写自己的程序,所以往往设计变更的结果无法顺利传达给每位工程师。 而工程师忙起来时通常会‘不小心’忽略其他人的mail,当然也没那种闲功夫与精神主动到server下载新的设计文件。最后结果就是:有人始终活在旧设计的世界中、模拟器与实际机器上API的接口或行为不一致、应用程序使用了不存在的API、固件工程师居然不知道硬件的新修正,导致系统不稳定或某个装置在新的板子上‘突然’不work了,这些状况在整合时才一一浮现,而且通常一时三刻还看不出到底是谁出了问题。

■ 这应该算是管理上的问题,要避免这种状况并不困难,只要设法贯彻设计更新的流程即可。首先要求所有工程师都必须注意设计修改的通知,并要求外部厂商(Third Party),如硬件或软件模块设计者,不得片面修改设计。 系统工程师对新设计最好能实时对应,如果是API改变的话,只要模拟器的相关函数一修改,其他应用程序应该马上就会发现编译或连接error,一来可以提醒工程师注意设计更新的通知,二来所有受影响的程序可以马上跟着对应。

■ 实作失误:有些自诩天纵英才的工程师根本不把设计文件当一回事,他们会用自己的方式实现其所负责的模块,一种是函数定义(参数及返回值)不同,另一种则是函数行为的差异,两者都会造成整合失败。 定期且确实的code review可以及早阻止这种行为的发生,如果工程师对其负责的模块有较好的设计或想法,应该要循管道进行设计变更流程,研发团队主管必须以整体的角度来讨论是否需要更改之前的设计成果,并评估这个修改的影响范围与程度。

■ 进度控制失误:这很容易理解,到了预计开始整合的时间点,但却有个重要的程序模块未完成,那么,整合工作当然无法如预期时间开始。就像在攻击发起日,所有的部队都已到达攻击发起线,但有个主力部队迟到,导致战线的中央有个明显的缺口,此时发起攻击必败无疑,但延后攻击时间却也未免耽误军机。 所以项目经理要时时注意各个工作阶段的“瓶颈”所在,宁愿集中人力与资源去完成可能造成瓶颈的工作项目,让较不重要的功能delay。

■ 进度管理失误:实际上,有些功能的进度(除了检查程序之外)是‘看不到,的,通常是没有画面显示的模块,例如文件系统或其他算法的实现。如果主管没空做code review的话,有时工程师会刻意隐瞒进度落后的事实或目前碰到问题的困难度,谎称一切都on schedule,往往要等到整合前才穿帮。 为了掌握所有工程师的进度,各个小主管必须定时从server下载最新版本的程序,抽空检查其组员的程序,如果有问题应该立即召开code review会议,并协助该组员找出解决问题或追上schedule的方法。

■ 驱动程序压力测试不足:驱动程序在独立运行时可能完全没有问题,系统负担加重后,可能问题就会逐一出笼,这样的状况是不适合开始整合工作的,所以驱动程序开发不能以一般状况没问题为满足,固件工程师必须根据装置的特性,主动设计各个驱动程序的压力测试方法,可能的压力测试手法如下,只有做完所有装置的压力测试,这个平台才合适开始做系统整合。

■ 特殊的操作方式,例如:用笔或手指在touch panel上频繁的乱画。 □ 长时间地操作某装置,例如:持续不停的压下某个key。 □ 利用信号发生器产生特殊的信号,并连上CPU的特定PIN脚,模拟与此PIN脚连接的装置持续送出信号。 □ 写测试程序主动频繁的操作待测装置,例如:持续地对存储器进行读写操作。

11.2 全功能整合 全功能整合阶段:主要做的事情是日程表的检讨。 Schedule检讨: ■ 利于进度管理。工程师对schedule都有一定程度的依赖,一旦某项工作delay之后,排在后面的工作自然也得跟着delay,此时,管理者最好实时介入帮忙重排schedule,否则许多工程师会就此失去时间的方向,认为反正都delay了,先把手头的工作完成,其他的慢慢再说吧! ■ 使追踪往后日子的进度成为可能,如果整个项目已经开始在delay了,则项目经理很难只根据旧的schedule追踪进度。系统中软件模块众多且实作状况都不相同,不能只是简单地把各单项的进度加上整体delay的时间而当作新的进度,必须趁着要开始整合的时间点,逐一了解每个模块开发的最新状况,制定合理、可施行、可管理的新schedule。 ■ 通过对软件开发现况的“普查”,可以试着分析造成delay的症结所在,管理者可据此设法调派人力与资源,或许可以找到好的方法把delay的时间赶回来。

另外,在陆续的整合其他系统功能的过程中,会渐渐的出现一些问题,这些问题可能是: ■ Memory空间不足:这是全功能整合最常见的问题,因为存储器的使用量在项目早期并不容易估得精确,而硬件规格却已早早固定下来,而且应用程序在PC上使用模拟器开发几乎没有存储器用量的限制,所以‘用爆’存储器的问题往往在整合阶段才会爆发出来。 □ Stack:虽然我们已经三令五申地要求所有工程师谨慎使用Stack,包含不要使用size太大的局部变量与注意递归(Recursive)调用的阶层,但总是有人会出状况。还记得Stack被破坏时显现的‘病兆’是什么吗?包含Stack内或Stack区域前后的存储器内容莫名奇妙被破坏,以及function call无法正确return等 除了程序的疏忽导致Stack被破坏之外,也有可能是我们把Stack的最大用量估计得太小了,只要先试着把Stack区域放大,如果问题都解决了,几乎可以确定就是Stack区域太小问题 解决这个问题的方法虽然多少有点劳师动众,但Stack Overflow呈现出来的现象就是系统很不稳定,其影响的范围几乎是整个系统,绝对必须优先解决。 · 检查所有程序,确认Stack使用量最大的程序,并检讨是否真的需要这么大的Stack。 · 使用Profiling的方法,得出系统可能Stack的最大使用量

□ Heap:程序中使用动态存储器可能发生的问题如下。
    · 程序超用其配置来的存储器,导致Memory Pool中的队列被破坏。
    · 碎片。程序明明没有用到这么多存储器,但有时候就是要不到,这会导致某些功能有时候运行正常,有时候无法执行。外行人统一用‘不稳定’这个词来形容这种系统状态。
    · 目前配置之Heap空间的大小真的不符应用程序的需求。
Heap的问题越早解决越好,最好每整合一个模块,就观察一下Heap有没有异常状况,否则,等到所有程序都整合了,Heap的使用状况将变得更复杂,出了问题会更难找出到底是哪些程序造成的。

□ 程序size超出预期、ROM空间不足。
在系统设计时会先预估各个用途的存储器使用量,并据此设计Memory Layout,但这毕竟都是估计值,等到整合工作开始后才会渐渐明朗。
如果当初存储器配置的设计就是连接的很紧密,若某段存储器的size超出预期,势必会压到另一个存储器区段。这个状况在制作ROM的Binary File(或Image File)时就可以被发现,解决方法是程序减肥(Downsizing),或重新配置ROM里各个区块的位置。

■ Task不协调:如果应用程序必须用到多任务,则系统中会有多个Task(或Thread),而这些Task可能由不同的工程师负责实现;如果彼此没有协调好,或者有某位工程师对多任务系统的理解不扎实,在整合时可能会发生各个Task单独执行都很正常,但‘同时’执行时就出问题了 这些问题不外乎Task间通信、同步、优先级设定、共享资源的保护等,只要理解对都不难解决,可以去参考一些Multi-Threading Programming(多线程操作)的数据。重点是在已经整合的Task还少时就要尽量测试,有问题便实时解决.

■ Critical Section未保护:这里说的Critical Section有两种,第一种是Task间可能会‘同时’存取的全局变量,或同时执行的程序段;第二种是一般程序与ISR(中断处理程序)可能会同时存取的全局变量,或同时执行的程序段。 中断与工作切换(Task Switch)会被引发的时间点可能每次执行都不一样,程序必须设法避免操作Critical Section尚未完成前就被切换到别的程序段,否则等恢复执行时,Critical Section的状态已经被改变。反映出来的状况是每次执行的结果可能都不一样. 保护Critical Section的方法很多,driver层会提供中断enable/disable的功能,在进入Critical Section前禁止中断产生,离开Critical Section后再恢复,即在Critical Section内什么中断也不能产生,保护功能为最佳。

■ 许多在模拟器上OK,但在机器上NG的bug会纷纷出笼,除了上述存储器或Critical Section的问题之外,这类bug多半与驱动程序、Cross-Compiler、甚至与CPU的特性有关。 这种问题难处理的地方在于它不能在Windows上Trace,而应用程序工程师通常都不熟悉在机器上调试的流程,所以往往需要固件工程师的协助.

还有一种和系统整合有关的工作项目,叫做‘Porting’,顾名思义,就是将在别的平台运行正常的程序或函数库移植到我们的机器上 这些程序模块可能来源: ■ 其他项目的程序:即曾经开发过的技术或程序模块,也可以说是研发团队或公司的技术资产

■ Open Source的函数库:近年来开放源码的思想大为流行,几乎什么样的应用都可以找到开放源码的程序,尤其是Linux,它简直就是技术人员的宝库

■ Third Party厂商开发的函数库:我们是负责产品开发的团队,有些特殊应用的技术网络上找不到,也不是我们做得来的,如手写辨识、语音压缩等,这些技术通常可以当成一家软件公司的主要业务了。

11.3 发行第一个版本 原则上应该所有功能都整合上来后,才发行第一个版本并送测会比较好,否则,若功能A整合完毕就送测,测试人员兴高采烈地测试、写Bug Sheet,负责功能A的工程师也兴高采烈地修改,结果当功能B整合上来后,影响了功能A,导致其某些功能不正常,那之前的测试工作岂不是如同白做工? 可惜现实与理想总是存在差距,一般情况系统整合还没完成就已经开始测试了,此时需要约定几个规则以便让工作能够顺利做下去: ■ 在整合工作完成之前,所发行的版本都是内部版本。 ■ 系统整合人员会尽量配合测试人员的需求发布内部版本,并详细告知系统中各个功能的完成度,也可建议测试项目的优先级。 ■ 内部版本没有正式编号,如A01-build 05(当然还是需要个识别编号,用日期是个很好的选择)。 ■ 如果没有必要,为避免增加复杂度,在此阶段只会发行模拟器版本,不会发行实际机器的版本。 ■ 因为正式版本尚未发行,所以此时测试人员找出的问题点,尽量不要以‘bug’称之,也不需填Bug Sheet(工程师通常都有自尊心强的特性)。 ■ 测试人员将所有找到的问题点汇集给RD主管,不直接接触工程师,由RD主管分配处理之。 ■ 在第一个正式版本发行之前,bug管理系统暂不启动。

在正式版本出来之后,就要正式启动BUG控制系统 Bug控制系统除了可以追踪bug外,也是项目团队所有成员(包含客户)对bug处理方式的沟通平台。以Bugzilla为例: ■ 测试人员在填写bug时,会根据其认知将其分类,而每种类别的bug都会有预设的处理者,通常是RD部门的小主管,当某bug的状态有变化时,如新增、已修改(FIXED)、REOPEN、CLOSE等,Bugzilla会主动寄发mail给预设处理者(Assigner)。相关人员必须主动检查Bugzilla寄出来的mail,并登入Bugzilla Server处理之。

■ 测试人员会将可重现bug的操作手法详细写在Bugzilla上,预设的处理者应该根据bug的内容判断该bug的分类对不对,如果分类不恰当,应该立即更改之。接着,根据研发团队各成员的工作职责,决定应该由哪位工程师负责,并将这个bug指定给他,被指定的工程师称为Assigner。

■ 某bug的Assigner会收到Bugzilla发出的通知信,应该即刻登入确定可否处理该bug,如果这个bug不该是自己负责,则应该立即协调指定另一位工程师负责,而不是任其放着。

■ 如果Assigner对该bug有疑问、无法重复发生、认为是规格的模糊地带、或不需要修改等,应该在Bugzilla上陈述理由,测试人员及其他可仲裁的人员可对此bug在在线进行讨论,所有讨论的内容都会被记录在Bugzilla Server中。如果最后确定这不是个bug,或者裁定不需要修改,则bug的状态会被改为INVALID或WONTFIX,再经多次确认后,这种bug就可以被CLOSE。

■ 当Assigner“接受”并解决了某个bug之后,应该到Bugzilla Server描述造成该bug的原因、解决方式、Side Effect评估、预计在哪个版本可以对应等信息,留下这些信息最大的受益人应该就是Assigner本人。程序代码那么多,谁能记得什么bug改了什么地方?如果以后有类似的bug,或该bug的修改方式确实造成了Side Effect,只要参考Bugzilla内之前记录的资料,就能够以最快的速度找到程序的问题点。所以Assigner在填写解决方案时要尽可能详细,如果可以的话,最好把改了哪个程序文件的第几行都不分轻重的记录在server上。

■ 当某bug被解决后,其状态由ASSIGN或NEW变为FIXED,要经过测试人员的重复验证后才可以被设为CLOSE(结项)。如果测试人员发现该bug未完全被修复,或发生其他的Side Effect,则此bug状态会被设为REOPEN,负责的工程师应该再行检查。

■ 研发主管应该时时利用Bugzilla自动产生报告的功能,检验查看还有多少bug未被解决?哪位工程师“囤积”了最多的bug?有哪些bug从被找到至今尚未被解决的时间最长。此举可以找出人力与困难度的瓶颈,研发主管应该即刻处理,如约谈相关工程师并了解其工作方式,如果只是单纯loading太重,可以先调派人力减轻负担,如果是碰到无法解决的关键问题,研发主管也应当在团队内寻求解决方案。

Callback Function 附录B

用C来实作面向对象的概念   附录C