OSEK‐V:应用特定的实时操作系统硬件实例化
摘要
在嵌入式控制系统中使用实时操作系统(RTOS)通常是一个非此即彼的决策:尽管RTOS抽象有助于简化软件组合与开发,但其在事件延迟和内存成本方面的代价较高。特别是在软硬件协同设计(HW/SW codesign)场景中,系统开发者往往尽可能避免采用完整的RTOS。在OSEK‐V中,我们通过将具体的RTOS实例深度定制到硬件中,缓解了这一权衡问题。我们并未将通用的操作系统组件实现为定制硬件设备,而是将实际可能发生的应用程序‐内核交互建模为有限状态机,并将定制化的RTOS语义直接集成到处理器流水线中。在基于OSEK实现四旋翼飞行控制器并集成到Rocket/RISC‐V软核的实验结果中,我们在适度消耗现场可编程门阵列(FPGA)资源的前提下,显著降低了事件延迟、中断锁定时间和内存占用。
1. 引言
本文探讨了嵌入式控制系统中的硬件‐操作系统边界。我们的现代生活由大量这类专用系统[30]驱动:仅在汽车中就已能找到超过一百个这样的系统[5],,家用电器中也有数十个,而物联网(IoT)等趋势将进一步提升它们在日常生活中的作用。
嵌入式控制系统通常需要在信息物理上下文中完成特定的预定义任务,且常常需满足严格的安全性和时序要求。由于这些系统被用于大规模生产的产品(如汽车)中,因此单个单元的成本压力很高。因此,即使使用系统软件,也通常采用编译时可定制的实时操作系统(RTOS),但在许多情况下,开发人员甚至试图避免使用小型RTOS内核所带来的成本。与裸机软件或离散硬件相比,使用RTOS的解决方案通常更难分析/预测,并会带来更高的事件延迟和内存成本。另一方面,RTOS所提供的抽象(例如,优先级已实例化的线程、报警、资源等显著简化了更复杂且可组合的控制应用程序的开发。然而,即使在软硬件协同设计的情况下,我们仍经常看到一种全有或全无的方法:工程师要么避免使用实时操作系统抽象(这会使软件开发复杂化),要么将完整的实时操作系统作为(昂贵的)标准软件组件进行实例化。
在本文中,我们通过结合两者的优势来解决软硬件协同设计环境中的全有或全无差距:其思想是保留实时操作系统接口以简化和组合应用程序开发,但将其实际实现积极地针对具体应用的独特使用模式直接定制到硬件中。
将操作系统(或其部分)推进(定制)硬件以改善事件延迟的想法,是一个长期存在的研究领域(例如, [6, 3, 21, 24, 15, 11])。与以往的工作相比,我们基于全系统方法对操作系统和硬件进行了更紧密的定制:不是在中央处理器之外将专用组件(如调度器)作为额外的硬件设备进行实例化,而是将实时操作系统语义直接集成到中央处理器流水线中。实际上,具体的实时操作系统交互模型(实际使用的系统调用及其调用点上下文)成为处理器指令集和寄存器文件的高效且面向应用程序的扩展。这种直接的处理器集成避免了完整实时操作系统的开销,同时展现出在现代架构上仅通过软件难以实现的特性:所有实时操作系统交互都具有完全可预测的时序(仅需几个处理器周期),无内核引起的缓存逐出,显著减少的中断锁定时间。从安全性的角度来看,对实时操作系统的严格定制减少了其“滥用能力”,而硬件中的实例化有效地消除了向内核域注入代码的可能性。结合内存保护机制(本文未涉及),可在不执行内核代码的情况下实现完全隔离。
在之前的研究中,迪特里希等人 [9] 提出了一种静态跨内核和全系统分析方法,以及一种基于应用程序特定有限状态机(FSM)的内核实现 [8]。
通过本文,我们提高了系统分析的效率,将基于有限状态机的表示集成到实际的处理器流水线中,并在硬件级别实现了对系统组件的进一步定制。具体而言,我们提出以下贡献:
- 我们提出了一种方法,将具体RTOS实例的语义捕获为有限状态机,以实现高效的硬件实现。
- 通过将标准实时操作系统接口应用特定实例化到处理器流水线中,我们实现了较低的系统调用和中断延迟。
- 整个定制过程是完全自动化的;硬件和软件变体按需生成。
- 我们的开源实现OSEK‐V涵盖了汽车领域的OSEK/AUTOSAR实时操作系统标准,并将其面向应用程序的语义集成到Rocket RISC‐V核心中。
本文的其余部分组织如下:第2节描述了系统模型,并概述了我们的方法:从应用程序开始,在第3节中推导出系统状态机,并在第4节中将其集成到中央处理器流水线中。我们在第5节以一个实际的飞行控制应用程序为例对本方法进行评估,在第6节讨论结果,在第7节概述其他相关工作,最后在第8节得出结论。
2. 系统模型与思想
我们假设一个采用固定优先级调度的静态实时控制系统:一个应用程序与静态配置的实时操作系统(所有线程和中断处理程序在编译时已知或可推导)相结合,并以系统镜像的形式交付。此外,我们假设应用程序结构是静态的(无动态代码加载,不通过复杂的函数指针调用系统调用)。请注意,这些要求虽然从通用计算的角度看似乎苛刻,但在大多数实时控制系统中却是常见的实践,并且本质上已基本满足:这些要求无论如何都由主流的安全性(例如MISRA‐C [10], ISO 26262[13])和实时操作系统行业标准所规定。例如,ARINC 653分区[1](航空电子)、 µITRON [28]以及OSEK/AUTOSAR [23, 2](汽车领域),甚至POSIX.4实时扩展(使用SCHED_FIFO)均规定对一个已知任务集进行固定优先级调度。
2.1 我们的方法概述
图1展示了我们将RTOS基于使用情况定制到硬件中的概念:首先,我们对具体应用及其描述的系统配置进行分析,以提取应用程序与RTOS之间所有可能的交互,并将其表示为一个有限状态机。该系统状态机(SSM)模拟了RTOS在具体应用中的语义;它接收输入信号(同步系统调用和中断),更新其内部状态,并将当前运行的线程作为输出信号暴露出来。其次,我们将此SSM集成到一个应用特定CPU设计中:应用程序通过新引入的指令触发SSM,流水线则响应并调度到另一个硬件线程。最终,我们得到一个针对具体实时应用自动定制的计算系统。
当然,在一般情况下,由于状态爆炸,这样的RTOS‐FSM将不可处理:事件触发的RTOS的内核内部状态包括就绪列表、线程上下文、运行中的线程等。每个系统调用都是一个潜在的重新调度点,在该点上,根据所选择的调度策略和就绪列表的动态状态,可能会继续执行其他线程,而该线程又可能触发更多的系统调用。
尽管如此,由于以下两个原因,我们的方法是可处理的:首先,我们依赖于一个具有内在有限数量可能系统状态的系统模型。其次,我们在编译时向系统分析提供应用程序特定的信息,以尽可能减少不确定性:我们利用关于RTOS配置及其语义的静态知识,并结合对应用程序所有控制流的全系统分析,来确定RTOS的实际使用方式。通过这种方式,我们可以大幅减少可能的状态数量,因为许多调度决策的结果可以在事先推导出来(或至少加以约束)[9]。这进而实现了在硬件中的高效实现,我们将实时操作系统及其定制硬件组件(例如线程上下文或定时器)直接集成到处理器流水线中。
在不失一般性的前提下,我们在下文中以OSEK规定的系统模型为例来描述我们的方法。我们名为OSEK‐V的实际实现涵盖了符合一致性类别ECC1的OSEK/AUTOSAR系统 [23, 2]。
2.2 OSEK‐OS 概述
OSEK标准定义了一类广泛使用的固定优先级RTOS,并在过去二十年中一直是汽车应用领域的主导行业标准。我们基于OSEK‐OS标准所规定的实时操作系统接口[23]来构建我们的方法,这并不影响一般性。接下来,我们将简要介绍其API提供的抽象。
基本上,OSEK提供了两种主要的控制流抽象:中断服务例程(ISRs)和任务(传统上称为线程)。ISRs由硬件异步激活,并对系统服务具有有限访问权限,而线程则具有静态分配的优先级,并由软件同步激活。线程可以使用所有系统服务,并按照固定优先级抢占式调度策略执行。每次新的激活时,线程都从头开始执行,直到其(自行)终止。
临界区可以通过粗粒度全局中断锁或更细粒度的资源对象进行同步。基于栈的优先级上限协议,OSEK 资源通过确保互斥来防止死锁和无界优先级倒置。此外,线程可以等待事件被设置并保持在等待状态,直到另一个控制流发出事件到达的信号。
通过静态声明的报警可以触发周期性以及非周期性的线程激活或事件。每个报警都关联一个计数器,该计数器通常由硬件定时器驱动。报警可以在系统启动时自动以相位/周期开始,或者在运行时间间动态启动。
对于特定应用程序,开发人员在领域专用的配置文件中声明所有系统对象及其参数。通常,系统生成器在编译时静态地派生出具体的实时操作系统实例,并将应用程序与操作系统库链接成一个单一的系统镜像。
描述了单个线程T及其每70个节拍的周期性激活,该激活在系统启动时自动开始。应用程序代码(app.c)包含线程T的实现,生成器将系统描述实例化为 generated.c)
在图2中,展示了一个包含一个任务和一个周期性报警的示例 OSEK系统。应用程序代码(app.c)包含任务T,该任务执行一次计算后自行终止。系统配置(app.oil)表明,任务T具有10的静态优先级,并且完全可被抢占(SCHEDULE= FULL)。此外,声明了一个计数器C并将其连接到报警A,报警A每70个节拍触发一次,在初始相位偏移35个节拍后开始。当报警A到期时,会激活任务T。在编译期间,系统生成器生成一个系统框架(generated.c):空闲任务以最低优先级运行;当中断发生时,报警_tick ISR处理程序负责管理计数器和报警。为了明确地锚定系统行为,我们在代码中添加了人工系统调用(idle,isr iret kickoff ,,)。
在本研究中,我们专注于OSEK扩展符合性类别1(ECC1),其包含等待状态和资源,但不包括每个优先级多个任务和每个任务多次激活。随后,我们将所述的RTOS原语视为用于表达实时系统(RTS)行为的标记语言,并使用线程(对应OSEK任务)和中断服务例程来区分不同类型的控制流。
3. 系统状态机
由于我们的方法是应用特定的,因此我们从对一个特定实时系统(RTS)的系统分析开始,以提取应用程序、外部环境和实时操作系统之间的交互模型。系统状态机(SSM)在已分析的应用程序和环境模型存在的情况下,捕获期望的内核行为(即重新调度序列)。迪特里希等人 [9] 描述了一种应用特定的状态转移图(STG),该图枚举并连接了所有可能的系统状态。在本研究中,我们改进了STG计算的效率,并由此推导出应用特定的SSM。
在事件触发的实时系统中,实时操作系统从两个方面接收信号:控制应用程序发出同步系统调用,外部组件提供异步硬件中断。在这两种情况下,实时操作系统都会被激活,操作其内部状态,并通过调度实现调度结果。内部系统调用的顺序受应用逻辑的约束;外部事件的可能序列由周围环境决定。
3.1 应用状态机
对于系统分析,我们将内部应用程序结构表示为一组应用特定的有限状态机;每个线程和每个中断服务例程都成为一个应用状态机(ASM)。这些状态机作为信号生成器作用于操作系统模型,而后者则协调多个抽象状态机的执行。在之前的工作中,迪特里希等人 [9] 使用(压缩的)控制流图来表达系统调用顺序。相比之下,ASM表示更加紧凑,并且由于状态数量减少,我们实现了更短的分析时间。
对于每个控制流,我们根据局部控制流图计算抽象状态机。首先,我们将代码划分为基本块,这些基本块不是最大化的,但每个基本块要么包含单个系统调用,要么仅包含计算代码;后者无法同步影响系统状态。为了实现这种影响的分离,我们需要在系统生成时就已知应用程序结构(控制流图和系统调用位置)。图3a展示了图2中 alarm_isr处理程序的基本块划分(系统调用以深红色显示)。
为了生成一个在每个执行的基本块上都产生信号的状态机,我们从控制流图(CFG)计算出其折线图。每个控制流图边变为一个顶点,而每个基本块变为一条标记为块内容的边。然而,由于操作系统状态只能通过系统调用影响,我们将所有计算替换为 ε‐转换。值得注意的是,转移标签对应于系统调用点而非系统调用类型。图3b显示了 alarm_tick中断服务例程的折线图。
我们通过对每个抽象状态机应用标准的 ε消除来移除 ε‐转换。此外,我们将可通过 ε‐转换到达的线程状态标记为可被中断服务例程(E)中断。对于每个抽象状态机的状态,其出边集合表示在应用程序中的某个时刻可能执行的系统调用。图3c展示了运行示例中的三个抽象状态机:当报警处理程序处于状态A2时,下一个可以执行 iret系统调用站点,并将其发送到SSM。
目前,我们使用一个非常简单的模型来包含其他分析结果,以限制外部事件模型。当某个线程(或一组线程)具有隐式截止时间时,触发事件将被阻塞,直到事件处理完成 [9]。然而,还可以推导并利用应用程序级别上其他动作逻辑来进一步限制事件模型。例如,可以定义“发送缓冲区为空”中断仅在相关联的 SendMessage() 函数被调用后才可能发生。
应用程序模型和外部事件模型连接到一个抽象操作系统模型。该操作系统模型通过系统配置实例化,并遵循OSEK语义[23]。我们使用系统状态枚举(SSE)[9]方法将这三个部分结合起来,并在状态转移图中显式地枚举所有可能的系统状态。
STG 是一个由抽象系统状态(AbSSs)组成的有向图,用于捕获某一时刻的可能系统状态,并包含能够影响调度决策的信息。具体而言,每个 AbSS 包含一个 ASM 状态向量,用以指示每个控制流的当前抢占点。在每个状态中,恰好有一个流被标记为当前运行的线程。有关 STG 构建的详细信息,请参考迪特里希等人 [9]。
由于抽象状态机中的每个转移标签对应一次内核激活,且系统语义引擎仅根据系统语义将多个抽象状态机组合起来,因此状态转移图可直接用作SSM。在图4中给出了运行示例的状态转移图/SSM:系统从空闲循环开始。当发生中断(E)时,报警处理程序可以激活线程T或直接返回空闲状态。如果被激活,线程T将被调度,执行计算并自行终止。尽管在计算过程中报警可能再次到期,但线程只能被激活一次。
3.2 系统状态机最小化
生成的SSM已经表现出正确的行为,但状态数量和转移边尚未达到最小化。然而,由于状态机最小化是一个广泛覆盖的长期课题 [22, 12],,我们将仅研究SSM特性。
对于SSM最小化,我们将表现出相同可观测行为的所有状态合并为单个状态。在我们的场景中,可观测行为是指可能的重新调度事件序列。例如,如果两个状态总是以相同的顺序出现,但调度仅在第二个状态之后发生,则第一个状态可以合并到后一个状态中。我们运行示例(图4)中的A1和A2状态就是此类状态对的一个实例。从系统视角来看,所有由硬件事件(E)激活的A1状态,其后续的重新调度序列与A2状态相同。因此,A1状态被对应的A2状态所包含。我们通过使用摩尔算法[22]来识别这些等价状态,并将它们合并为一个状态。如果某个转移标签在合并后仅出现在自循环中,则可以安全地将该信号从系统中完全移除。
3.3 静态报警
我们进行应用特定的硬件定制的一个优势在于能够实现与静态系统配置相匹配的优化组件。除了SSM之外,我们还在应用程序中检测静态报警,这在嵌入式控制系统中非常常见:静态报警在启动时自动开始,从不重新配置,并以恒定速率触发。我们通过对接口配置和应用程序代码的静态分析来检查这些属性。所有非静态的报警均为动态报警,可根据配置由具有较低基本速率的定时器IRQ驱动,从而降低IRQ负载。
运行示例中的报警是静态的:它在启动时自动开始( AUTOSTART= TRUE ), 相位为35个节拍,周期为70ticks,且从不重新配置。
4. 推导OSEK‐V处理器
在系统分析中,我们收集了信息以根据应用需求定制可参数化的处理器流水线。我们将每个操作系统线程映射到一个硬件线程(harts),并引入专用指令,这些指令与控制硬件线程调度的SSM组件进行交互。此外,静态报警组件生成周期性信号,并异步地激活SSM。
4.1 状态分配与逻辑最小化
为了在硬件中实例化SSM,我们必须提供状态转移函数的高效实现:除了当前SSM状态外,它接收一个系统事件,并返回一个新的系统状态以及(下一个)核心。
SSM: 〈系统事件〉 × 〈状态〉 7→ 〈状态〉 × 〈核心〉
系统分析生成具有符号信号(例如“TerminateTask”、“ ActivateTask(T)”)和状态的SSM。对于硬件实现,我们必须为这些符号值选择位向量(例如, 〈ActivateTask(T)〉= 1012)。这种选择被称为状态分配问题,它在很大程度上影响硬件实现所需的最小复杂度。幸运的是,已有多种方法被提出以解决不同硬件设计下的该问题[33, 7, 32]。
我们使用NOVA程序[33]来解决我们的状态分配问题。NOVA针对两级逻辑实现的目标是进行最优编码,并根据给定的 “线程ID”编码(我们任意选择)相应地为系统调用和SSM状态选择位向量。由于NOVA在内部使用了逻辑最小化器,因此我们最终得到了转换函数的最小化真值表。利用该真值表以及静态报警信息,我们继续实例化OSEK‐V处理器。
4.2 OSEK‐V处理器
我们在Rocket核心[17],(一种64位、6级、顺序流水线)的基础上构建了OSEK‐V。尽管该软核主要并非面向嵌入式系统,但目前正在开发一个兼容的精简版32位变体。Rocket实现了RISC‐V接口[34],,这是一种旨在支持计算机体系结构研究的指令集架构。
Rocket类似于一个硬件产品系列,并提供了大量配置开关,以使实现能够适应应用需求。
我们将OSEK‐V集成到Rocket芯片生成器中,该生成器能够在寄存器传输级生成周期精确的C++模拟器。通过我们的适配,它会根据系统分析的结果实例化所有组件,并将其连接至流水线(见图 5)。
为了实现快速控制流切换,我们扩展了流水线以支持硬件多线程。该处理器已启用
用于同时跟踪不同的执行流(硬件线程执行单元)及其上下文:每个流水线阶段都有一个标签,用于保存当前正在执行的硬件线程执行单元的信息;寄存器文件和程序计数器生成器(NPC生成)被扩展以保存多个硬件线程(硬件线程执行单元)的执行上下文。来自不同硬件线程执行单元的指令发射由SSM控制。
在我们当前的实现中,每个OSEK任务和空闲线程都被映射为独立的硬件线程执行单元,而中断服务例程仍在当前核心的上下文中执行。这是ISR激活时间与硬件资源消耗之间的一种权衡,但可以通过使用一个专用硬件线程来执行所有中断服务例程来缓解这一问题。
4.3 特殊指令和静态报警
此外,OSEK‐V流水线提供了两条新指令来与SSM交互: ssm.ld 和 ssm.tx。 ssm.tx指令用于启动代码中,以设置所有硬件线程执行单元的指令指针。ssm.tx指令将其立即数操作数作为系统事件(见第4.1节)传递给SSM,SSM随后在其上调用状态转换函数。
当 ssm.tx指令进入流水线并到达执行阶段时,前面的阶段将被暂停,直到内存和提交阶段清空。这种暂停确保了在 ssm.tx指令之前的所有异常保持精确。执行阶段向SSM发送系统事件。在SSM应用转换函数并更新“当前hart”信号期间,流水线处于暂停状态。如果发生重新调度,则会重用分支预测错误逻辑来清空流水线,并为新hart的程序计数器发起指令取指。
除了 ssm.tx指令外,静态报警组件还会发出系统事件。在内部,它从实时时钟节拍中衍生出具有不同相位和周期的时钟信号,并与SSM通信。当一个或多个报警超时时,静态报警组件会暂停流水线并等待当前指令执行完毕。随后,多个系统事件将原子方式传输,以确保报警可以同时触发。该传输以一个〈isr()〉开始,多个报警动作(例如, 〈ActivateTask(…)〉)构成主体部分,而〈iret()〉则触发可能的重新调度。
静态报警事件的处理方式与其他外部事件类似;只有在处理器当前未锁定中断时才会被接受。因此,所有中断被锁定的区域仍然具有运行至完成的语义。
OSEK‐V功能已集成到Rocket芯片生成器中;配置参数以 JSON格式编码,并由硬件设计直接读取和解释。这些参数包括 SSM逻辑的最小化真值表、硬件线程数量以及静态报警设置。虽然配置仅描述预期行为,但生成器负责决定如何实现这些需求。例如,静态报警组件使用根据报警激活的相位和周期,采用不同的策略来生成时钟信号。
4.4 系统生成和启动
定制硬件还要求系统软件进行相应的定制。通过将操作系统逻辑推向硬件,内核的软件部分仅需保留少量功能。在启动时,内核使用 ssm.ld指令配置程序计数器。堆栈指针由线程本身作为其首批指令之一进行初始化。当一个已终止的线程被重新激活时,它将从堆栈初始化代码处开始执行。剩余的动态报警以及常规中断由软件内核处理。在应用程序中,系统调用点被替换为携带系统事件标识符的 ssm.tx指令。为了确保中断服务例程和线程中的重调度点之间的对称性,系统调用点必须由一对中断禁用/启用命令包围。
我们使定制实时操作系统和硬件的过程完全自动化。系统分析与转换在 dOSEK 框架中实现,无需人工干预。Rocket 生成器读取处理器配置,并生成 OSEK‐V 实例;该实例可以是周期精确模拟器,也可以是 Verilog 代码。
5. 实验结果
在我们的评估场景中,我们采用了与西门子中央研究院合作开发的 I4Copter [31],,这是一种安全关键型嵌入式控制系统(四旋翼直升机)。我们分析了 I4Copter 控制应用程序的任务设置(图6):线程通过三个报警和一个中断服务例程(ISR)周期性地和偶发地被激活。线程间同步通过 OSEK 资源实现,同时一个看门狗线程监控遥控通信。该场景总共包含十一个线程、三个周期性事件(报警)、一个偶发中断和一个资源。其中一个报警用于控制看门狗线程,其激活率为低,且在运行时间进行重新配置,因此属于动态报警;其余两个报警为静态。
我们将应用逻辑替换为检查点标记,因为我们关注的是应用程序与内核之间的交互。这种替换不会影响分析,仅交换计算块的内容。整个系统包含52个系统调用点。
在SSM构建(第3节)期间,我们利用了关于隐式截止时间的应用知识来限制外部事件模型。例如,“采样”、“信号处理”和“飞行控制”任务总是在3毫秒的报警再次触发之前完成执行。正如迪特里希等人[ 9 ] ,所述,这种对可用信息的利用有助于简化系统分析。
5.1 性能
作为初步评估,我们针对不同定制程度运行了基准测试场景,并在周期精确模拟器中测量了不同系统操作所需的时钟周期。我们对三个超周期进行了基准测试,结果如图7所示。
前两个变体不涉及底层处理器,仅用于为OSEK‐V结果提供上下文:图7中的基线变体是标准的dOSEK实现,其中所有报警为动态。专用变体利用系统分析结果将系统调用点替换为专用代码片段[9]。如果结果可以静态地推导出来,专用系统调用可以省略某些操作(例如,查找最高优先级可运行线程)。在OSEK‐V– SSM变体中,流水线通过添加定制的SSM组件得到增强,同时所有报警仍被动态管理。最后,SSM+Alarms变体包含了SSM以及一个静态报警组件,该组件负责管理三个报警中的两个。
在周期精确跟踪中,我们识别出原子执行的内核状态操作。这些操作包括同步系统调用、管理动态报警的定时器ISR,以及静态报警信号的传输。我们统计了这些操作所需的时钟周期,同时将实际在流水线中执行的周期(a,b)与额外的缓存停顿周期(c,d)区分开来。这种区分使我们能够将OSEK‐V的实际计算开销与处理器特定的缓存层次结构区分开来。
在整个基准测试中,通过专用系统调用以及使用专用硬件组件(a),处理器非空闲状态下的有效时钟周期减少。这种减少源于更短的原子执行的内核激活,其与中断锁同步。更短的中断锁间隔对实时系统尤为重要;当中断延迟降低时,系统的责任增加。如果不考虑缓存停顿,所有操作的中断锁平均长度从195个时钟周期减少到41个时钟周期,降幅约为80%(SSM+Alarms)。这一减少主要由定时器ISR驱动。然而,即使没有静态报警,平均操作也仅需138个时钟周期(SSM)。
我们将同步系统调用和ISR激活的实例区分为两类:不会引起重新调度的事件,以及实际调度到另一个控制流的事件。此外,我们考虑处理时间最长的事件作为相关信息,因为我们需对实时能力进行分析。因此,我们不仅给出每种操作的平均运行时间,还给出了最大运行时间(上界)。
首先,我们考虑应用程序代码发出的同步系统调用。当不发生重新调度时,无静态报警的OSEK‐V的最坏情况时间下降了−79.29%,与具有专用系统调用的版本(下降−75.71%)处于相似范围。平均而言,定制硬件比专用软件快约50%。这种差异的原因在于,调度器和分派器通常已被消除针对这些非调度系统调用的专门化。对于带分派的系统调用操作, OSEK‐V硬件相比基线至少有75%的提升,而平均优势甚至超过90%。
在纯软件实现中,每个报警都是通过定时器ISR动态管理的。我们将整个定时器ISR的执行周期作为一个单一系统操作进行测量,因为报警激活的效果在 iret处是原子地体现的。同样,我们区分了有无调度另一个线程的操作。无论是否实际发生重新调度,系统调用特化对周期计数的影响都很小。
当定时器中断未引起重新调度时,SSM变体仅表现出轻微的最坏情况改进(−12.77%)。然而,在发生调度的情况下,该操作在最坏情况下执行速度大约快了一倍(−47.16%),并且平均导致显著更少的缓存停顿(−72 stalls)。
使用静态报警组件(SSM+Alarms)会导致系统在报警处理方面的行为发生多项变化。一方面,由于剩余的动态看门狗报警的基本速率得以降低,定时器中断请求(IRQ)的数量从280次减少到28次。这主要促使整个基准测试的中断阻塞时间显著下降。
除了中断频率降低外,静态报警变体的中断服务例程执行时间也有所下降:由于只需管理一个报警而非三个,因此无需调度的中断服务例程(−29.43%)以及需要重新调度的中断服务例程(−59%)的执行速度显著加快。此外,一次静态报警激活最多消耗10个时钟周期,并直接影响SSM,而无需占用处理器。
缓存停顿周期的减少与特化程度成正比,最高可达−46.79 percent(c,SSM+Alarms)。对于两种OSEK‐V变体而言,同步系统调用和静态报警激活所剩余的缓存停顿来源于应用程序代码的指令取指(d)。只有动态报警处理可能导致由执行的内核指令引起的缓存逐出。
5.2 OSEK‐V 核心的现场可编程门阵列 Synthesis成本
除了OSEK‐V方法在运行时间和延迟方面的优势外,我们还评估了在流水线旁边增加专用硬件组件的实际成本。我们首先概述 I4Copter基准测试和图2中运行示例的系统分析结果。这些数据为理解综合不同OSEK‐V核心时所产生的实际实现成本奠定了基础。
在表1中,我们展示了在单个Intel Core i7‐2600核心上通过 Python实现的dOSEK框架执行的系统分析结果。图2中的运行示例是一个小型系统:其分析速度快,初始SSM已经很小,且SSM最小化并未消除太多冗余。最终得到的最小化逻辑块实现了该状态转换函数仅由四个与子句组成(四个与门,其输出在一个或门中组合)。
对于I4Copter基准测试,系统分析耗时超过一分钟,其中运行时间主要由状态分配相位决定(占96.95%)。尽管如此,初始 SSM的规模仍随着系统规模(#IRQs,#Tasks)呈指数级增长,并表现出一个庞大的状态机。与之前的工作[8],相比,通过使用抽象状态机(ASMs)替代控制流图,初始STG的规模显著减少了−75.91%。此外,状态机最小化可进一步消除85.5%的状态。最终得到的状态转换函数接收一个15位的输入向量(状态:10位,系统事件:5位),并产生一个14位的输出信号(hart id:4位)。
我们使用赛灵思Vivado2015.2工具链为Zynq‐7020 FPGA芯片综合不同的OSEK‐V核心,该芯片被集成在ZedBoard平台中。火箭的流水线被限制以至少25MHz运行,而FPGA单个逻辑单元具有Fmax 100 MHz的频率。
如预期所示,与基准Rocketcore相比,图2示例仅导致现场可编程门阵列资源使用量小幅增加(+127内存LUT),具体结果见表 2。这一增加主要源于寄存器文件翻倍,因为Synthesis工具使用分布式RAM单元来实现用于额外核心(空闲线程,线程T)的第二个寄存器文件。
I4Copter基准测试产生了一个相当大的核心。在没有静态报警的情况下,需要多9%的查找表(LUTs),这些LUT主要被 SSM组件使用(76.09%)。额外所需的983个内存LUT中,大部分用于寄存器文件(96.24%),以保存额外的核心上下文。这些增加的现场可编程门阵列资源需求与系统镜像中内存消耗的减少直接相关(见表3);SSM避免了大部分内核代码,而扩展的寄存器文件避免了线程上下文对内存的占用。
当我们添加静态报警组件(SSM+Alarms)时,与不包含此附加硬件组件的变体相比,现场可编程门阵列资源消耗仅略微增加。系统镜像的静态内存消耗变化不显著。对于所有变体, Xilinx综合工具均至少耗时10分钟,并始终能够满足流水线的 25 MHz时序约束。
| 示例 | I4Copter |
|---|---|
| 生成时间 | 秒 0.06 |
| 初始SSM 状态 | 9 |
| 转换 | 13 |
| 最小化SSM 状态 | 6 |
| 转换 | 9 |
| 转换函数 子句 | 4 |
表1:基准的系统分析结果
| 火箭示例 | I4Copter |
|---|---|
| (基线) | (图3) |
| LUT | 29 460 |
| Mem‐LUT | 1033 |
| 触发器 | 14 208 |
| F max [MHz] | 26.37 |
表2:定制OSEK‐V核心的综合结果
| 字节 | 基线 | SSM | SSM+Al. |
|---|---|---|---|
| 文本段(内核) | 14 368 | 8669 | 8393 |
| 数据段(不含堆栈) | 1908 | 410 | 354 |
表3:I4Copter所需的闪存和内存空间
6. 讨论
与其他软硬件协同设计方法相比,我们专注于单个应用程序而非一小类应用程序,以揭示涌现系统特性。我们缩小的关注范围揭示了独特的属性,但也将讨论由此带来的限制。
6.1 专用化与标准化
我们针对基于可定制硬件设计的实时控制系统,这些系统采用现场可编程门阵列(FPGA)或旨在使用专用集成电路(ASIC)。这与当前行业领域通过将定制设计整合到高产量(因而更便宜)的商用现成平台以降低软硬件开发成本的趋势形成鲜明对比。
然而,我们相信,定制流程各个层面自动化程度的不断提高将部分扭转这一趋势——从长期来看,“按需专用集成电路”产业将大幅降低定制硬件的开发成本和单件成本。这种情况已经出现,正如帕特森和尼科利奇在最近发表于《电子工程时报》博客文章中所指出的那样。OSEK‐V 与此愿景高度契合,因为我们完全保持了软件端的兼容性:应用程序基于标准RTOS接口进行开发,但自动生成的优化实现可根据需要选择性地集成到硬件中。
6.2 应用程序领域与可扩展性
我们的方法适用于可以接受静态定制的不灵活性并最终采用应用特定芯片的情况。OSEK‐V 芯片将内部解决方案结构在硅片中实现;所使用的专用集成电路无法更新,只能更换。对于现场可编程门阵列系统情况则不同,其中 OSEK‐V 处理器将成为已部署系统更新的一部分。然而,仅当应用结构(系统配置和抽象状态机)发生变化时,才需要更新 OSEK‐V 核心;其他更新可照常进行。此外,通过分层调度方案可实现部分硬件化:高优先级线程可直接映射到硬件线程执行单元,而低优先级线程可合并到一个硬件线程执行单元中并通过软件管理。这将在关键情况下提供低延迟,同时在其他方面保持灵活性。
主要的可扩展性挑战是状态转移图(STG)的状态爆炸问题。理论上,系统的状态数量可能比线程和中断的数量呈指数级增长。即使可行,这种负担也会导致较长的分析和构建时间。然而,我们能够证明,我们的原型实现在处理实际场景时,速度超过了生成的硬件描述被综合所需的时间。
硬件可扩展性由两个成本因素决定:寄存器文件和SSM逻辑。由于寄存器文件必须保存 n个线程上下文,因此我们必须分配存储容量。然而,它与硬件线程的数量呈线性增长,并且可以放置在FPGA的块状RAM中。SSM逻辑则随着应用程序的复杂性和系统必须面对的外部非确定性而扩展。对于那些对周围环境具有充分了解的小型系统而言,将RTOS语义在硬件中实例化将使其受益最大。
除了工业中使用的传统实时控制系统外,我们认为新兴的物联网领域也是一个可能的应用领域。当小型控制系统变得无处不在时,专用性与灵活性之间的权衡将被重新评估。物联网系统以大量销售,面临较高的价格压力,并且与所用设备的任务和使用寿命紧密耦合。我们相信,应用特定的高度定制化芯片非常适合这些变化的设计因素。
6.3 语义和应用程序的限制
除了可扩展性问题外,我们对(1)实时操作系统语义和(2)应用结构所施加的限制,对语义提取的普遍适用性构成了威胁。本质上,状态转移图包含了在编译时可获得的固有确定性到实时操作系统语义及其被应用程序的使用;即使存在外部中断也是如此。虽然这对于固定优先级调度效果较好,但在提供确定性明显较差的系统上其用途受限,例如采用最早截止时间优先 (EDF)调度器或执行在线接纳测试的任何其他调度器的实时操作系统。在应用程序方面,所有与实时操作系统的交互都必须能够在编译时被检测到。这禁止任何形式的动态代码加载、通过函数指针调用系统调用,以及在编译时无法计算出值的系统调用参数。
然而,对于许多领域而言,这些限制在实践中几乎没有影响——它们本来就是相关行业和实时安全标准所规定和要求的:例如,最早截止时间优先(EDF)调度在嵌入式控制系统中几乎不被使用;相关行业标准 (如OSEK/AUTOSAR [23, 2], 653[1] µ [28], 4 ARINC、 ITRON以及POSIX.)均采用固定优先级调度;函数指针的使用以及任何形式的动态代码修改都被相关的编码和安全标准(例如[10, 13])所禁止。总之,我们的大多数要求无论如何都必须由需要通过认证的嵌入式控制系统满足。
6.4 可预测的实时操作系统实现
实时开发人员使用最坏情况执行时间(WCET)分析来确定作业所需的执行预算的上限。 tighter界限将简化实现时间可预测系统所需的配置工作。我们可以通过改进分析本身,或通过首先使底层平台更具可预测性来增强我们的预测能力。与 T‐CREST/Patmos项目[27], OSEK‐V一样,它为实时应用程序提供了更具可预测性的处理器平台。
通过OSEK‐V,实时操作系统对时序行为的影响被降至最低。SSM激活仅需消耗少数几个周期,主要由重新调度的硬件线程的取指延迟决定。SSM自身的执行不会驱逐任何缓存行;只有所需的流水线冲刷会影响应用程序。此外,静态报警组件承担了周期性系统协调任务,从而降低了中断负载。
尽管及时性是可预测性的一个重要方面,但安全性正变得越来越重要,尤其是当控制系统连接到(公共)网络时。OSEK‐V 核心仅继承所需的实时操作系统语义,减小了可信代码基,并将控制组件推进到更可信的硬件实现领域。结合定制内存保护机制,其中核心切换意味着保护域切换,可以在不执行任何内核指令的情况下实现完全隔离。然而,这属于进一步研究的课题。
7. 相关工作
将操作系统接口视为对实际处理器接口的扩展,从而定义一个分层机器[29],这在系统领域是一个公认的观点。因此,通过将操作系统(或其部分)移入(定制)硬件以改进各种非功能性属性,来实现对系统调用的部分解释,是一种顺理成章的做法。
HybridThreads [3]通过将操作系统组件置于实际处理器旁边,实现了低运行时开销和快速中断处理。调度决策通过中断服务例程(ISR)在软件中进行调度。Sloth [11]通过将所有调度和调度决策委托给中断硬件,在标准硬件上为OSEK实现了类似优势。FlexPRET处理器 [35],同样暴露了RISC‐V指令集架构,通过细粒度的硬件多线程实现了混合关键性系统的可预测执行,同时处理线程间依赖且未考虑同步问题。相比之下,ReconOS 项目 [18], 为线程和硬件组件提供了一个类似于 POSIX 的统一操作系统接口;协调与 同步仍然在软件中完成。Mooney 和 Blough [21] 将操作系统组件实例化于硬件中,以提供一个应用特定的平台;开发者可以手动选择与核心服务正交的预构建组件。与所有这些方法不同, OSEK‐V 对实时操作系统进行了深入的定制:我们从特定应用程序的角度捕捉实时操作系统的语义,而不是在硬件中复制一个 (通用的)软件实现。此外,我们将组件直接集成到处理器流水线中,以实现细粒度且应用特定的定制。
本质上,OSEK‐V 通过对每个调用点上的每个系统调用来进行完全特化,从而获得其定制的实时操作系统语义。这在某种程度上类似于 Synthesis [26, 19] 中已知的路径特定系统调用优化,或 Tempo [20] 框架提供的部分特化。然而,这两者都是在运行时进行特化的,这(a)需要昂贵的运行时支持,并且(b)支持可逆的概率性优化。相比之下,OSEK‐V 是在编译时进行定制的,因此所有特化都必须是健全且完整的,即生成的实时操作系统实例可以表示为一个有限状态机。
将有限状态机作为整个系统模型的使用也已被提出,用于深度嵌入式传感器节点,以增强简单性和能效:SenOS [14] 是一种软件事件分派器和执行器,用于多个手动编码的有限状态机。Kothari 等人 [16] 通过对 TinyOS 程序进行符号执行,推导出紧凑的状态机(< 16 状态),以促进对现有应用程序的理解。
8. 结论
借助 OSEK‐V,我们在硬件与操作系统边界探索了事件触发、固定优先级实时系统的软硬件设计空间。从单个应用程序和标准化的 OSEK‐OS API 出发,我们将实际使用的 RTOS 行为提取为一个有限状态机。该系统状态机由系统调用和中断触发,并控制线程调度。OSEK‐V 核心将每个 RTOS 线程映射到一个硬件线程,并配备实现所提取 RTOS 语义的应用特定硬件组件。由此,我们揭示了理想的非功能性特性,例如低事件延迟(平均 IRQ 锁定时间为 −79%)、减少干扰的 RTOS 执行(内核中缓存停顿为 −47 %)以及快速线程重新调度(调度系统调用耗时 −81% 个周期)。这些改进仅需适度的现场可编程门阵列资源开销,即多出 10% 的查找表和每个映射的 RTOS 线程占用 86 个分布式存储单元。
致谢
作者感谢匿名评审人员的反馈意见。本工作得到了德国研究基金会 (DFG)的资助,资助编号为 LO 1719/1‐3、SFB/Transregio 89 “Invasive Computing”(项目 C1)以及 LO 1719/4‐1。
OSEK‐V 的源代码可在以下地址获取:
https:// gitlab.cs.fau.de/osek-v
3142

被折叠的 条评论
为什么被折叠?



