嵌入式开发:周期调度和代码执行时间理解

汽车嵌入开发中,我们常常听到这样的名词:1ms Task、5ms Task、10ms Task...试问:"1ms Task是说这个任务要执行1ms吗?"本文,带着这个疑问,展开讨论。

1、代码调度

程序员按照需求,负责写代码,这些代码最终被CPU执行,进而控制执行器,以此达到预期功能。如果想要达到预期功能,对应的功能代码就要被CPU执行,多长时间执行一次呢?:这取决于具体的功能。比如:收音机开启检测功能,此功能对应一段代码(eg:Check_AF_Switch())。驾驶员想要打开车载收音机,触发动作10s以后,收音机打开可以吗?:可以,但是,驾驶员的体验会非常不好。所以,对于打开车载收音机的检测就应设计一个合理的检测周期,以便于及时捕获驾驶员的意图。假设:10ms周期检测驾驶员是否有打开车载收音机的请求,那这10ms如何理解呢?:10ms就是收音机开启与否的检测频率,在这10ms的时间内,CPU要完整执行一次Check_AF_Switch()代码。所以,代码开发中,往往会将Check_AF_Switch()这段代码放到10ms Task中,即:让Check_AF_Switch()这段代码每10ms执行一次。

那么,Check_AF_Switch()这段代码执行时间等于10ms吗?:显然不是。10ms,是CPU去执行Check_AF_Switch()这段代码的频率,并不是Check_AF_Switch()这段代码执行一次所要花费的时间,实际上,Check_AF_Switch()这段代码执行一次花费的时间要远远低于10ms(eg:100ns)。Check_AF_Switch()调度频率与执行时间示意如下所示:

(一)CPU时钟周期与指令执行时间理解

我们知道,高级语言代码(eg:C语言)汇编后,变成一个一个汇编指令(注意:不同架构的单片机,汇编指令不同),一个汇编指令具体需要多少个CPU时钟周期,在芯片的用户手册中会有说明。比如:Aurix单片机的指令,需要的指令时钟周期,示例如下:

eg:ADD指令,需要一个CPU Clock即可完成。如果CPU的主频为300MHz,意味着ADD指令仅需要1 / 300000000 ≈ 3.33ns即可完成。我们对CPU执行一个指令花费的时间有了一定认知,也就能认识到:CPU执行一段代码,实际花费的时间并不多。假设:Check_AF_Switch()有100行代码,汇编后有200个指令,每个指令需要1个CPU Clock,则Check_AF_Switch()代码执行一次,需要耗费200*3.33≈666ns,都不到1us,所以,相对于一个10ms的Task,Check_AF_Switch()这段代码执行的时间是极小的。

(二)空闲任务与CPU的关系

既然CPU执行速度很快,一个Task的代码量有限,那么,CPU执行完一次Task中的代码,下一次执行时间还没到,CPU在干啥呢?:"偷懒"。假设:CPU仅有一个10ms周期性Task,Task中代码执行需要2ms,这意味着CPU有8ms时间可以去"偷懒"。既然偷懒,就别让人看到,去空闲Task呆着去,这也就是工程上常说的Idle Task(空闲任务,优先级最低)或者Background Loop(背景loop),示意如下:

(三)如何理解CPU使用率和CPU负载

在汽车嵌入式开发中,我们往往会关注一个参数:CPU负载。CPU负载和CPU使用率有什么不同呢?假设:系统只有一个CPU,也就是单核处理器,这个CPU仅需要处理一个10ms周期的Task,执行这个Task中的代码需要花费2ms,则CPU有效使用率就是20%,这和我们常说的CPU负载有什么关系呢?:个人理解,工程中常说的CPU负载应该是这里的CPU使用率。真正的CPU负载又怎么理解呢?假设:一个CPU分配了3个Task:

  • 20ms Task1,优先级最低,对应代码完整执行一次需要6ms;

  • 5ms Task2,优先级中等,对应代码完整执行一次需要1ms(下图中的10应该是5);

  • 5ms Task3,优先级最高,对应代码完整执行一次需要3ms。

三者使用CPU的关系如下所示:

如上图,Task1并不能在20ms时间内,完整执行一次对应的代码,虽然此期间,CPU一直在干活(CPU使用率100%)。由于Task1的优先级最低,在执行Task1程序期间,不断地被Task2和Task3抢占,因此,CPU要完整的执行一次Task1中的代码,至少需要26ms。而这26ms地时间内,Task2、Task3中代码,均按照预期,完整地执行了6次。提示:工程开发中,除了Task之间的抢占,中断也会抢占Task。

当出现上述工况时,CPU的负载率>1。如何理解CPU负载率>1呢?举一个例子:一个5座小汽车,最多可以承载5人,如果超过5人乘车,小汽车则无法承载,即:小汽车的负载>1。类比CPU,如果让CPU处理上述的Task2、Task3,CPU游刃有余,还可以"偷懒",此时,CPU的负载率<1。当CPU同时处理Task1、Task2、Task3时,即使CPU一直不停的工作(CPU使用率100%),也无法在Task1规定的期限内(20ms),有效的将Task1中的任务,完整的执行一次,此时,CPU的负载>1。

所以,CPU负载<1,是CPU可以有序处理Task的前提,CPU负载和CPU使用率是两个概念。也就是说,CPU使用率≤100%,也可以有效的处理任务,但是,CPU负载>1,则不能按照预期处理Task。

2、Task超时引发的工程问题

(一)问题描述

在某Task中增加一段复杂代码后,此Task中的软件定时器失准,具体表现:时间明明过了1s,软件定时器只计时0.5s。

(二)原因分析

在Task中,增加复杂代码以后,意味着此Task的代码执行时间更长。此Task被高优先级任务/中断服务打断的概率增加。假设:增加复杂代码所在Task为Task1,Task1、Task2、Task3属性同上,三者使用CPU的工况如下:

如上图,设计中,每20ms,预期Task1中的计数器加1,而实际上,需要经过26ms,计数器才能加1,进而软件计数器失准。为什么Task1会被频繁的抢占呢?:工程中,Task有优先级,高优先级Task会抢占低优先级Task,同时,中断可以打断任何Task,所以,当Task的优先级较低时,被打断的频率会大大增加。

(三)解决测试

解决措施可根据实际情况选择:

  1. 优化算法,减少复杂代码运行时间,降低所在Task被打断或者抢占次数;

  1. 如果算法要求的执行频率不高,可将算法放到周期更长的Task中,比如:100ms

  1. ......

  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NMR0574

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值