引言
TOPPERS/FMP是由日本名古屋大学高田广章教授发起的开放实时嵌入式软件平台TOPPERS(Toyohashi Open Platform for Embedded Realtime Systems)中的一个面向于多核环境的嵌入式实时操作系统,全称是Flexible Multiprocessor Profile RTOS。FMP目前已经移植到了部分ARM架构的处理器、Nios II处理器以及瑞萨的SH处理器。
1 TOPPERS/FMP的多核扩展
TOPPERS组织为功能分散型多核处理器开发了一款实时操作系统TOPPERS/FDMP(Function Distributed MultiProcessor RTOS kernel),也是遵循μITRON规范标准功能集。在TOPPERS/FDMP内核的基础上,TOPPERS组织开发一个新的内核TOPPERS/FMP,支持动态任务迁移功能,也是针对TOPPERS/ASP内核实现的多核扩展,主要支持对称多核处理器。
1.1 总体结构
TOPPERS/FMP内核总体结构如图1所示,FMP内核支持对称多核处理器,所有的处理器共享同一个程序镜像。
图1 TOPPERS/FMP内核总体结构
FMP内核还引入了自旋锁的机制,主要用在处理器间进行资源竞争时保护共享资源。
1.2 内核管理与调度
TOPPERS/FMP内核中新增了一个结构体,叫做 PCB(Processor Control Block),主要用于管理每个处理器的数据,内核为每个处理器维护一个这样的结构体。内核可以单独管理每个处理器的状态。内核中task、task excpt、cyc handler、alm handler这些可执行单元(Processing Unit)被划分到指定的处理器上,属于处理器私有资源,对应的处理器上的内核代码会对其进行初始化操作。而dataqueue、eventflag、mailbox、memfix、pridataq、spin_lock这些内核对象(Kernel Object)属于共享资源,由主处理器完成初始化操作。为了方便应用开发,TOPPERS/FMP内核扩展了静态配置器,使其支持对多核处理器进行配置,属于某一个处理器内核的可执行单元和内核对象,被归为一个类型,在静态配置脚本中叫做CLASS,配置脚本示例略——编者注。
内核采用了局部队列调度的方式,在PCB中维护了一个局部的就绪队列(ready_queue)。采用这种调度方式,任务基本无需在不同处理器间切换,提高了任务执行的效率,但是如果应用开发者没有设计好应用程序,有可能出现某些处理器核心负载很轻,某些处理器核心负载很重的负载不均衡的状态,多核处理器的性能将无法充分发挥。为了解决负载不均衡的状态,TOPPERS/FMP内核提供了一组用于任务迁移的系统调用API,应用开发者可以根据自己需求来进行应用层的任务迁移管理,TOPPERS/FMP内核没有直接在内核层提供动态迁移的功能的主要原因是由于无法确保内核的实时性。
1.3 中断管理
多核处理器中中断管理分为两种类型:①所有处理器共享一个中断源;②每个处理器有自己的中断源。多核处理器一般引入全局中断控制器进行总体的中断管理,每个处理器内部有自己私有的中断控制器。针对这样的改变,FMP内核也引入全局中断的管理部分,将中断号与中断处理程序号的高位区域(如果是32位的编号,就是高16位)用于标示对应进行处理的处理器ID。这样对于那些中断号一样的中断,通过高位区域进行处理器ID的判别也可以知道哪个处理器响应哪个中断[8]。对于每个处理器内部的中断处理流程还是采用TOPPERS标准中断模型。
1.4 处理器间通信
多核操作系统实现处理器间系统调用(interprocessor system call)采用两种实现方式:直接内存操作(direct memory access)和远程过程调用(remote procedure call)。远程过程调用方式广泛应用于非对称处理器,或是不存在共享内存的消息传递型处理器中,执行时间不确定。TOPPERS/FMP内核为了保证实时性,采用了直接内存操作的方式。
1.5 同步
TOPPERS/FMP内核启动过程中,采用了多级屏障锁的方式保证每个处理器的启动进程一致,以确保内核正确启动。
TOPPERS/FMP内核采用了直接操作其他处理器控制块(Control Block)的方式来实现处理器间的系统调用,这就需要保证处理器间的操作是互斥的。TOPPERS/FMP内核采用了自旋锁的方式来实现互斥,自旋锁是通过test and set的方式实现的。锁的粒度严重影响着系统调用的灵活性以及响应时间,锁的粒度越高,并行性越好,但是响应时间就有可能得不到保证,TOPPERS/FMP实现了三种不同粒度的锁,用户可以在内核配置的时候进行选择。这三种粒度的锁分别是巨锁(giant lock)、处理器锁(processor lock)、细粒度锁(finegrained lock)。FMP内核在每个处理器上将会定义两种锁:任务锁(task lock)和对象锁(object lock)。为了避免死锁,TOPPERS/FMP内核规定了锁获取的顺序。在进行系统调用时,先获取对象锁然后获取任务锁,释放锁时先释放任务锁,再释放对象锁。由于获取到对象锁后,其他的任务有可能修改了待获取的任务控制块,TOPPERS/FMP内核采用一种简单的重试机制,在获取到任务锁时,检查对应的任务是否已经被修改,如果被修改就释放对应的任务锁,开始重新获取任务锁,循环往复。
2 TOPPERS/FMP在ZYNQ上的移植
2.1 移植工作
TOPPERS/FMP的代码主要也是在GNU环境下进行开发的,而且开发移植大致与TOPPERS/ASP的移植[10]基本一致,只是增加了一些多核相关的移植工作。
图2 TOPPERS/FMP内核的启动流程
2.1.1 内核的启动
TOPPERS/FMP内核在ZYNQ上的启动如图2所示,主要分为三个流程:Bootloader阶段,内核启动——汇编部分,内核启动——C语言部分。
由于各自处理器执行的初始化内容不一样,导致执行每一阶段的耗时不一样,为了能保证每个阶段处理器都能同时开始运行,引入屏障同步的功能来实现处理器同步。
2.1.2 标准中断处理模型移植
ZYNQ上的中断分为私有外设中断(PPI)、共享外设中断(SPI)和软中断(SGI)。软中断主要用于处理器间通信。中断优先级总共有32级,所有的中断产生以后,将会产生IRQ或者FIQ异常。FMP内核中配置成IRQ模式进行中断处理,因此所有的中断产生后,将直接跳转到IRQ的中断向量入口处,程序可以通过查询中断控制器中的相应的寄存器获知当前的请求的中断号,然后通过查表的方式就可以跳转到对应的中断处理程序。
中断处理的实现的流程图如图3所示,需要注意的是如果内核配置时采用了处理器锁或者细粒度锁的方式就需要释放已经获取的第一阶段和第二阶段锁。还有在进行中断处理时还需要判断对应的中断是不是伪中断,如果是的话就直接返回。伪中断表示原始的中断已经不再等待处理了,通常是因为另外一个处理器已经在处理这个中断了。
2.1.3 任务迁移支持
为了实现任务迁移,需要在目标依赖部分实现如下功能的函数:①用于当前任务的迁移函数支持,dispatch_and_migrate;②用于任务结束时的迁移函数支持,exit_and_migrate。两个函数均在任务上下文中,在CPU锁定状态下,获取到待迁移任务的源处理器和目的处理器的锁后被调用。实现的流程图如图4所示。
本文分别实现采用私有定时器、私有看门狗定时器、全局定时器三种方式作为系统时钟驱动。还有为了实现每个处理器单独的日志输出功能,在ZedBoard上通过MIO引出另外一路串口,并且在程序上实现了双串口的驱动程序。然后采用FMP内核自带的sample测试例程进行测试,验证功能正常,移植成功。
2.2 内核性能测试
2.2.1 测试环境说明
本文所做的评测实验均是在ZedBoard上完成,ZYNQ处理器运行在667 MHz,MMU和数据Cache、指令Cache均使能,所有测试均运行10 000次,分别在DDR RAM和片内的OCM RAM单独进行测试。
FMP内核配置:内核采用巨锁方式,内核系统时钟采用32位私有定时器实现,测试所用计时器采用64位的全局定时器。
2.2.2 测试结果
本文对内核进行了如下评测实验:内核启动、任务切换、任务迁移、信号量、事件标志位以及优先级数据队列的时间消耗测试。
测试发现启用了MMU和Cache后,除了内核启动外,在DDR RAM和OCM RAM的测试时间基本一致。
按照图2中FMP内核启动流程所示,程序中将从各处理器的必要的硬件相关初始化开始到第三阶段屏障同步开始记作FMP内核启动消耗时间,各处理器消耗的启动时间表略——编者注。由于处理器1作为主处理器比从处理器多的任务因此启动时间比处理器2长一些,由于MMU和Cache是在启动过程使能的,导致在OCM中运行FMP内核的启动时间稍快于DDR。
图3 TOPPERS/FMP内核中断移植
FMP内核中各个API执行的场景不同导致执行时间不同,表略——编者注。
任务激活API act_tsk按照5种测试场景进行测试。具体测试场景略——编者注。
任务指定处理器激活API mact_tsk按照2种测试场景进行测试。具体测试场景略——编者注。
任务迁移API mig_tsk按照以下3种测试场景进行测试。具体测试场景略——编者注。
图4 任务迁移目标依赖部分需实现函数
任务休眠API slp_tsk和任务唤醒API wup_tsk测试了均会引起任务切换的场景。
信号量释放API sig_sem按照以下2种测试场景进行测试。具体测试场景略——编者注。
优先级数据队列发送API snd_pdq按照如下方法进行测试:在发送低优先级的数据队列前,先发送若干个高优先级的数据队列,测试了高优先级数据队列的个数与snd_pdq的执行时间的关系,如图5所示,执行时间与高优先级数据队列个数近似成正比关系。
图5 优先级数据队列发送snd_pdq执行时间
事件标志位设置API set_flg按照如下方法进行测试:在set_flg执行之前,有若干个低优先级的任务等待事件标志位,测试了等待事件标志位的任务的个数与set_flg执行的时间的关系,如图6所示,执行时间与等待事件标志位的低优先级的任务的个数近似成正比关系。
结语
鉴于ZYNQ处理器上支持TrustZone功能,下一步将移植TOPPERS/SAFEG[9]嵌入式虚拟机到ZYNQ处理器上,以实现在该处理器上同时运行两个操作系统,一个实时操作系统用于实时控制,另外一个通用操作系统(如Linux)用于实现一些比较复杂的功能,如人机交互、网络通信等。
图6 事件标志位设置set_flg执行时间