我们正在编译一个嵌入式C++应用程序,它部署在电离辐射轰击的环境中的屏蔽设备中。我们正在为ARM使用GCC和交叉编译。在部署时,我们的应用程序会生成一些错误的数据,并且比我们希望的更频繁地崩溃。硬件是为这个环境而设计的,我们的应用程序已经在这个平台上运行了几年。
我们是否可以对代码进行更改,或对编译时进行改进,以识别/纠正由单个事件扰乱导致的软错误和内存损坏?是否有其他开发人员成功地减少了软错误对长时间运行的应用程序的有害影响?
我们正在编译一个嵌入式C++应用程序,它部署在电离辐射轰击的环境中的屏蔽设备中。我们正在为ARM使用GCC和交叉编译。在部署时,我们的应用程序会生成一些错误的数据,并且比我们希望的更频繁地崩溃。硬件是为这个环境而设计的,我们的应用程序已经在这个平台上运行了几年。
我们是否可以对代码进行更改,或对编译时进行改进,以识别/纠正由单个事件扰乱导致的软错误和内存损坏?是否有其他开发人员成功地减少了软错误对长时间运行的应用程序的有害影响?
当前回答
NASA有一篇关于防辐射软件的论文。它描述了三个主要任务:
定期监控内存中的错误,然后清除这些错误,稳健的错误恢复机制,以及如果某些东西不再工作,重新配置的能力。
请注意,内存扫描速率应该足够频繁,很少发生多位错误,因为大多数ECC内存可以从单位错误而不是多位错误中恢复。
稳健的错误恢复包括控制流传输(通常在错误发生之前的某个点重新启动流程)、资源释放和数据恢复。
他们对数据恢复的主要建议是,通过将中间数据视为临时数据,避免数据恢复的需要,以便在错误发生之前重新启动也能将数据回滚到可靠状态。这听起来类似于数据库中的“事务”概念。
他们讨论了特别适用于面向对象语言(如C++)的技术。例如
用于连续内存对象的基于软件的ECC契约编程:验证先决条件和后决条件,然后检查对象以验证其是否仍处于有效状态。
而且,正是如此,美国宇航局(NASA)已将C++用于火星探测器等重大项目。
C++类抽象和封装支持多个项目和开发人员之间的快速开发和测试。
他们避免了某些可能产生问题的C++特性:
例外情况模板Iostream(无控制台)多重继承运算符重载(new和delete除外)动态分配(使用专用内存池并放置新的以避免系统堆损坏的可能性)。
其他回答
NASA有一篇关于防辐射软件的论文。它描述了三个主要任务:
定期监控内存中的错误,然后清除这些错误,稳健的错误恢复机制,以及如果某些东西不再工作,重新配置的能力。
请注意,内存扫描速率应该足够频繁,很少发生多位错误,因为大多数ECC内存可以从单位错误而不是多位错误中恢复。
稳健的错误恢复包括控制流传输(通常在错误发生之前的某个点重新启动流程)、资源释放和数据恢复。
他们对数据恢复的主要建议是,通过将中间数据视为临时数据,避免数据恢复的需要,以便在错误发生之前重新启动也能将数据回滚到可靠状态。这听起来类似于数据库中的“事务”概念。
他们讨论了特别适用于面向对象语言(如C++)的技术。例如
用于连续内存对象的基于软件的ECC契约编程:验证先决条件和后决条件,然后检查对象以验证其是否仍处于有效状态。
而且,正是如此,美国宇航局(NASA)已将C++用于火星探测器等重大项目。
C++类抽象和封装支持多个项目和开发人员之间的快速开发和测试。
他们避免了某些可能产生问题的C++特性:
例外情况模板Iostream(无控制台)多重继承运算符重载(new和delete除外)动态分配(使用专用内存池并放置新的以避免系统堆损坏的可能性)。
如何运行应用程序的许多实例。如果崩溃是由于随机的内存位变化造成的,那么你的一些应用程序实例很可能会通过并产生准确的结果。(对于有统计背景的人来说)很容易计算出在给定的比特翻转概率下需要多少个实例才能实现所希望的最小总体错误。
有一点似乎没有人提到。你说你在GCC中开发,并在ARM上交叉编译。你怎么知道你的代码中没有关于空闲RAM、整数大小、指针大小、执行某个操作需要多长时间、系统将持续运行多长时间等的假设?这是一个非常普遍的问题。
答案通常是自动单元测试。编写在开发系统上执行代码的测试线束,然后在目标系统上运行相同的测试线束。寻找差异!
还要检查嵌入式设备上的勘误表。您可能会发现“不要这样做,因为它会崩溃,所以启用编译器选项,编译器会解决它”。
简而言之,崩溃的最可能来源是代码中的错误。在你确定这不是事实之前,不要担心更深奥的故障模式。
我真的读了很多很棒的答案!
这是我的2美分:通过编写软件检查内存或执行频繁的寄存器比较,建立内存/寄存器异常的统计模型。此外,以虚拟机的形式创建一个仿真器,您可以在其中试验该问题。我想,如果你改变结尺寸、时钟频率、供应商、外壳等,你会观察到不同的行为。
即使我们的台式电脑内存也有一定的故障率,但这不会影响日常工作。
考虑到超级跑车的评论、现代编译器的趋势以及其他因素,我很想回到古代,用汇编和静态内存分配的方式到处编写整个代码。对于这种完全的可靠性,我认为组装不再会带来很大的成本差异。