乐于分享
好东西不私藏

[031] 航空软件的时间底线——WCET与航空安全

[031] 航空软件的时间底线——WCET与航空安全
摘要:在航空领域,一段代码"能跑"远远不够——它必须在规定时间内跑完。这个时间上限,就是WCET。它是适航认证绕不过去的一道坎,也是实时系统安全性的根基。本文从实际项目经验出发,聊聊WCET到底是什么、为什么航空软件必须做WCET分析、以及DO-178C和DO-248C对此提出了哪些硬性要求。

一段代码引发的思考

做过嵌入式项目的人都有过这种经历:功能跑通了,基本功能测试全过,代码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 #软件安全 #嵌入式开发 #安全关键系统