一段代码引发的思考
做过嵌入式项目的人都有过这种经历:功能跑通了,基本功能测试全过,代码review也没问题——结果一上目标板,系统卡死。
排查了半天,发现是一个后台任务把CPU时间全吃光了,其他高优先级任务根本抢不到执行窗口。
这种情况在消费电子里可能只是"体验差",但在航空领域,它意味着灾难。
想象一下:飞机进近阶段,飞控计算机需要在每个执行帧内完成姿态解算、舵面指令生成、传感器数据融合等一系列任务。如果任何一个任务超时,后果不是"用户体验差",而是飞机失控。
所以航空软件有一个硬性要求:每个任务的最坏情况执行时间必须被分析、被验证、被“记录在案”。
这个时间上限,就是WCET。听起来很简单,本打算一篇草草说一下,实际写完,发现至少得2~3篇。
什么是WCET
WCET(Worst Case Execution Time),任务的最坏情况执行时间。它的定义很直白:一个任务在目标处理器上完成执行所需的最长可能时间。注意,这个时间不包括任务执行过程中其他任务和中断的执行时间——它只关注这个特定任务本身。
注意两个关键词:"最长可能"和"特定任务"。
"最长可能"意味着不是平均值,不是典型值,而是最极端情况下的时间。哪怕这个极端情况即时在实际运行中几乎不会出现,你也必须把它算出来。
"特定任务"意味着WCET关注的是单个任务本身的执行时间,不是整个系统的响应时间。
WCET是软件最坏执行时间,相对应的,系统级别的响应时间叫WCRT(Worst Case Response Time),那是另一个维度的事。
为什么非得算最坏情况?因为在安全关键系统里,你不能赌运气。平均跑50ms没用,万一某次跑了120ms呢?如果周期是100ms,那指不定就出事了。
航空实时系统的时间约束
飞机上的控制器——飞控计算机、导航计算机、显示处理单元——它们需要在特定的时间范围内完成各自的处理任务。这不是"尽量快",而是"必须在截止时间前完成"。
这类系统叫实时系统(Real-Time System)。注意,实时不等于"快",而是"确定"。一个任务500ms完成但每次都在500ms以内,比一个任务平均50ms但偶尔飙到500ms要好得多。
实时系统对时间的要求体现在两个层面:
代码级:单个任务/进程/中断的执行时间。关注的是控制流、处理器架构(Cache、Pipeline)对执行时间的影响。对应的就是WCET。
系统级:多个任务/多功能集成后的端到端响应时间。关注的是调度策略、任务间干扰、资源竞争。对应的是WCRT。
代码级分析为系统级分析提供基础——你得先知道每个任务的WCET,才能算出整个系统的WCRT。
DO-178C怎么说
WCET分析在DO-178C中有明确的位置。核心要求出现在几个地方:
6.3.4.f节——源代码验证目标
DO-178C第6.3.4.f节指出,在源代码验证过程中,需要确定最坏情况执行时间。这一要求适用于A级、B级和C级软件。
具体来说,分析需要考虑:
- 编译器选项对执行时间的影响
- 链接器选项的影响
- 处理器行为的影响(特别是Cache和Pipeline)
这段话翻译成大白话就是:你不能只在开发环境里测一下就觉得够了,因为编译器优化、缓存命中率这些因素会显著改变实际执行时间。
Table A-5目标6
DO-178C附件A表A-5的第6个目标,直接指向了源代码层面的验证,其中包括最坏情况时间的确定。这个目标是A、B、C级软件都要满足的。
11.20节——软件完成摘要
WCET分析的结果最终要汇总到SAS(Software Accomplishment Summary,软件完成摘要)中。具体来说,11.20.i条要求在SAS中呈现WCET数据,包括时间余量(timing margins)。
这意味着WCET不是"做了就行",而是要做到能被审查员看到、能被追溯、能被验证的程度。
SOI#3审核
在SOI#3(Stage of Involvement 3)审核阶段,审查员会检查WCET分析的样本资料或方法。这不是走形式——如果你拿不出WCET分析的证据,SOI#3过不了。
DO-248C FAQ#73:测试时间测量够不够?
这个问题问得很直接:通过测试测量时间,能不能代替WCET分析?
DO-248C的回答是否定的。
原文的核心意思是:
1. 仅仅做时间测量是不够的,必须伴随一个分析来表明最坏情况会被达到
2. 分析必须考虑处理器行为,特别是Cache性能
3. 如果能证明测试确实覆盖了最坏情况,那么测试时间可以作为补充——但你得先证明这一点
这段话的潜台词是:大多数测试用例不会触发最坏情况。你跑了1000次,每次都是40ms,不代表WCET就是40ms——因为第1001次可能走了一条你从没测到的执行路径,花了80ms。
所以测试是补充手段,不是替代手段。WCET分析的核心还是基于代码结构、处理器模型的分析,然后补充最长路径的时间测试。
WCET分析到底在分析什么
做WCET分析,本质上要回答一个问题:这段代码在最极端的情况下,最多要跑多久?
为了回答这个问题,需要做两件事:
第一步:确定最坏情况执行路径
一段代码里有很多分支、循环、函数调用。不同的输入会走不同的路径,有的路径短,有的路径长。
WCET分析要找出那条最长的路径——也就是最坏情况执行路径(WCEP,Worst-Case Execution Path)。
这听起来简单,实际做起来非常复杂。因为:
- 函数调用关系可能很深(递归、间接调用)
- 循环边界可能依赖运行时数据
- 分支条件可能涉及多个变量的组合
- 有些路径在理论上可达,但在实际运行中永远不会被触发
如果把每个分支都取最坏情况,算出来的WCET会非常保守——远超实际需要的时间。但如果不够保守,又可能遗漏真正的最坏情况。
第二步:计算路径上的执行时间
确定了最坏情况路径后,需要计算这条路径上每条指令的执行时间,然后累加得到总时间。
听起来又很简单?问题是:现代处理器的指令执行时间不是固定的。
这就是Cache和Pipeline带来的复杂性,一会详聊。
为什么WCET分析可能难在哪
找最长路径,然后跑测试。听起来可能很简单,但是一个高置信度的WCET分析实际做起来,情况可能复杂得多,比如标准里提到要考虑高速缓存等。
如果处理器是简单的顺序执行、没有Cache、没有Pipeline、没有中断——那WCET分析就是把指令数乘以时钟周期,算完了。
但现实不是这样。
Cache的影响
Cache是处理器和主存之间的高速缓存。当数据在Cache中(Cache命中),访问速度很快;当数据不在Cache中(Cache缺失),需要去主存取,速度慢很多。
问题是:Cache的命中与否取决于之前访问了哪些数据,而这些又取决于程序的执行路径。不同的执行路径会导致不同的Cache状态,进而影响后续指令的执行时间。
更麻烦的是,多个任务共享同一个Cache。任务A把Cache填满了自己的数据,任务B一切换过来,Cache全部失效,所有数据都得重新从主存加载——这个现象叫"Cache抖动"(Cache Thrashing)。
Pipeline的影响
现代处理器使用流水线(Pipeline)来并行执行多条指令。但流水线不是万能的:
- 分支预测失败会导致流水线清空
- 数据依赖会导致流水线停顿
- 资源冲突会导致指令排队
这些都会导致同一条指令在不同时候的执行时间不同。
中断和调度
中断会打断当前任务的执行。虽然WCET定义中不包括中断本身的时间,但中断会导致Cache被污染、Pipeline被清空,间接影响任务后续的执行时间。
WCET分析的三种路径
面对这些复杂性,业界发展出了三种主要的WCET分析方法:
纯静态分析
只分析代码结构和处理器模型,不实际运行程序。
优点:能保证给出一个安全上界(不会低估WCET),不需要硬件环境,不需要测试用例。
缺点:对处理器的建模非常困难(特别是现代多核处理器),分析结果可能过于保守。也就是说,我软件工具算出来WCET是190ms,但需求要求是100ms,如果做软件的架构优化后,还是降不下来,怎么办?换CPU?
典型工具:aiT(Absint公司的产品)。
纯动态测量
在实际硬件上运行程序,通过插桩等方式测量执行时间。
优点:技术实现简单,直接反映硬件行为,可以支持多核处理器。
缺点:需要编写大量测试用例,且很难证明测试覆盖了最坏情况。大部分测量结果是"伪上界"——看起来是最大值,实际上可能遗漏了更坏的情况。
混合方法(推荐)
结合静态分析和动态测量。用静态分析推算最坏情况执行路径,用动态测量获取实际执行时间数据。
这种方法试图兼顾两者的优点:既有静态分析的安全性保证,又有动态测量的准确性。
典型工具:TimeWeaver、RapiTime。
无论用哪种方法,WCET分析结果最终都要在SAS中总结呈现,并且要能经得起SOI#3审核的检验。
WCET与系统时间的关系
前面提到,必竟WCET是代码级的时间分析,关注单个任务。但航空系统是多任务的——多个任务在同一帧内执行,它们共享处理器资源。
一个常见的误区是:把各任务的WCET简单相加,认为系统总时间就是各任务WCET之和。
实际上,这种做法往往过于保守。因为:
- 同一帧内的不同任务,它们的最坏情况分支可能是互斥的——任务A走最坏路径时,任务B可能走的是最好路径
- 但如果两个任务在同一帧内确实可能同时走到最坏路径,那WCET数据就必须相加
这背后的罗辑不简单,不是简单的数学加法。
系统级的时间分析叫WCRT(Worst Case Response Time),它考虑的是任务在调度策略下的端到端响应时间。WCET是WCRT的输入——你得先有每个任务的WCET,才能算出整个系统的WCRT。
一些容易踩的坑
坑一:只做测试不做分析。 跑了一堆用例,每次测出来的时间都在预算范围内,就觉得WCET没问题了。但DO-248C FAQ#73说得很清楚——测试是补充,分析才是核心。
坑二:忽视编译器优化的影响。 Debug模式下跑40ms,Release模式下跑25ms。看起来Release更快更安全?但问题是,Release模式下的执行路径和Debug模式下可能完全不同,某些路径在Release下反而更慢。另外,FPU蹬蹬高阶功能也显著影响执行时间。
坑三:把WCET和WCRT混为一谈。 WCET是单个任务的时间,WCRT是系统级的响应时间。很多人把WCRT的预算直接当WCET用,或者反过来,都是不可取的。
坑四:WCET数据没有记录在SAS中。 分析以经做了,结果也对,但没有在SAS中总结呈现。审查员看不到证据,等于没做。
写在最后
WCET分析不是"锦上添花"的可选项,而是航空软件适航认证的必选项。它直接关系到实时系统能不能在截止时间内完成任务,关系到飞机能不能安全飞行。
从DO-178C的要求到DO-248C的FAQ,从实践指南的分析方法到实际项目中的踩坑经验,WCET始终是航空软件开发中绕不过去的核心话题。
后续我们聊聊WCET的具体分析方法——静态分析和动态测量,各有什么优劣,实际项目中怎么选。聊聊高速缓存在CAST里是怎么说的。
觉得有用的话,点个「在看」让更多人看到 👇
#WCET #航空软件 #DO-178C #适航认证 #实时系统 #最坏情况执行时间 #Cache #软件安全 #嵌入式开发 #安全关键系统
夜雨聆风