MICROSAR OS中Alarm和ScheduleTable的HEAP/LIST算法浅析
Heap算法(Os_PriorityQueue):专门为Alarm和ScheduleTable抽象出的O(logN)复杂度的二叉堆算法。
函数设计:
Os_PriorityQueueParentIndex
寻找父节点
Os_PriorityQueueHeadUp
新插入的节点数据会一直和父节点比较并交换位置上浮
Os_PriorityQueueHeadDown
①计算当前节点的左节点
②While循环遍历下沉,循环条件用的左节点小于当前队列的元素个数
③因为用的是数组结构,最后那个复制到头做下沉操作的数据会有两个,尾部数据其实还在,这样right节点就算没有拿到的也是这个安全区的值,这样不存在越界的问题。
Os_JobPriorityCompare
因为时间的计数器在硬件层面看都存在翻转的原因,为了减少模除运算的使用(占用CPU周期明显大于加减运算),老版本或者新版本的底层都会有其不同的优化方案。
①针对瑞萨这个32位的芯片,最大值理论上是FFFF FFFF,此时可以将OsCounters中的最大允许值设置为较小的值,比如常用到的3FFF FFFF。底层在处理超过最大值的TICK 时会通过减法运算计算差值,这样避免了模除。这里有个细节需要注意,这个设计上的最大允许值是客户所感知的,你的使用场景需要基于此值。也就是说你在设置时间范围的时候你一定不能设置一个超过3FFF FFFF的值。
②最新的MICROSAR OS中此函数同样涉及到此问题,不过我们是通过这个值做溢出判断。当然溢出判断的前提是你得设置为7FFF FFFF。在做二叉堆的下沉操作时需要和左右节点做时间戳的对比,如果差值在7FFF FFFF之内说明没有发生溢出,反之则是溢出,溢出时不正常处理会影响下沉。注意二叉堆记录的时间戳是绝对时间,是从寄存器中读到的时间+偏移。同样设置时间范围的这个偏移值不能超过7FFF FFFF。
Os_PriorityQueueInit
队列元素清零
Os_PriorityQueueInsert
新数据插入到队尾并做上浮操作
Os_PriorityQueueDeleteTop
队尾的赋值给队头然后调用下沉操作
Os_PriorityQueueDelete
删除非堆顶元素,用队尾的覆盖删除节点然后分别做下沉和上浮操作
数组遍历算法(Os_Counter):少数Alarm和ScheduleTable下的O(N)复杂度的算法。
设计亮点:
①强制内联的使用代替函数指针。如果使用函数指针会存在一个函数调用栈的开销(Push->Branch->Pop),几十条汇编指令对应的就是几十个指令周期。强制内联则在编译阶段完成点对点的映射,完全规避栈的开辟。
②掩码操作代替打断流水线的if else操作。比如在OS未完全准备好的时候掩码用0x00000000去规避运算,在OS准备好之后用0xFFFFFFF使能运算。
③开关中断的时间控制。底层代码会在4个元素的遍历之后开启中断以防止长时间的中断挂起。在我看来这个设计是一个工程上的经验值,底层设计工程师可以根据架构优化分析。

浙公网安备 33010602011771号