实时性迷思(3)——80%时间屏蔽了中断,实时性还有救么?
【写在前面的话】
并得出两个重要的结论:
实时性只关注“是否能在实时性窗口内完成对应事件的处理”,而与事件处理的快慢无直接关系;
从应用整体的角度来看,实时性窗口内越靠前的时间越珍贵;
当应用在运行时有大比例的时间屏蔽了中断,系统的实时性还有救么?
当应该频繁的开关中断,系统的实时性还有救么?
【从一个例子开始】
int main(void)
{
...
while(1) {
__disable_irq(); //! 关闭全局中断
do_some_work(); //! 经过测量,占用了7个周期
__enable_irq(); //! 开启全局中断
}
}
这个代码本身并不复杂,事实上,它在前后台系统中非常典型。作为例子,这里有几个要点需要首先明确:
这只是一个例子,它存在的意义是为我们提供一个讨论的起点,请不必在意和猜测它在实际应用中的意义;
假设 __disable_irq() 消耗一个周期;当它执行完成后,全局中断会被关闭;
假设 __enable_irq() 消耗一个周期;当它执行完成后,全局中断会被打开;
假设 这里的 while(1) {} 导致的循环跳转(无条件跳转)会消耗一个周期(其实Cortex-M3/M4就是这样);
函数 do_some_work() 消耗7个周期。
从执行 do_some_work() 开始到 __enable_irq() 执行结束,总共 7+1=8 个周期——在这期间,中断都是被屏蔽的;
自从“无条件跳转”开始到 __disable_irq() 执行结束,总共 1+1=2 个周期——在这期间,全局中断是可以被响应的;
整个循环占用10个周期:其中8个周期中断被屏蔽。又由于这是main函数内的超级循环,因此可以大体推断出:在整个应用执行期间 80% 的时间中断是被屏蔽的。
这符合本文一开头所提出的两个问题的条件,即:大比例的时间屏蔽了中断 和 频繁的开关中断。
【是时候搬出模型了……】
【CPU资源磨刀霍霍……】
思考这个问题,实际上直接引出了第三个重要的结论:
结论3:
文章的开始部分,我们提出了两个问题:
当应用在运行时有大比例的时间屏蔽了中断,系统的实时性还有救么?
当应该频繁的开关中断,系统的实时性还有救么?
已知当前系统中,最大的中断屏蔽时间长度为 Tmask;系统频率为 F;对已有的实时性事件处理来说,系统的实时性是否仍然能够得到保证?
对每一个具体的系统来说,求解过程也很简单:
由于屏蔽中断的时候,任何实时性事件都有可能发生,因此我们要重新计算系统的CPU资源占用——评估它是否接近或超过了 100%
计算每一个实时性任务的CPU占用时,都要把“事件无法响应”Tmask 加到 “处理事件所需时间” 里——作为分子去除以作为分母的“实时性窗口”:
【小结】
频繁开关中断并不可怕;
别管关闭中断的时间总比例是多大,这没意义;
找到系统中关闭中断时间最长的那个代码,测量它占用的时间——它才是罪魁祸首;
使用“以小换大策略”——借助一切可能的手段,使用小的屏蔽来替换掉长时间的屏蔽——无论是屏蔽中断还是RTOS里的屏蔽调度,道理都是一样的。
RTOS里尽可能用 mutex,而不要长时间关调度——因为mutex几乎是RTOS可以提供的屏蔽时间最短的手段了。
裸机自求多福。