恭喜,你发布的帖子
发布于 2022-11-17 15:22:33
15楼
Trace应用和场景分析又一例
这个例子的起因是:今天我无意中仔细看了一眼,前面在3楼发的,大量优先抢断任务的Trace图片。结果无意中瞟到了两个微小细节。这两个细节对于功能是完全无碍的,只是它们的出现超出了我的预料,需要找到原因。
所以这个例子是一个非常合适的,并非事先准备的。借此就着本帖,给大家呈现一下,我是如何结合Trace和FB的结构设计,在一个随时发生的调试场景中,步步收敛,回溯原因的过程,而不是靠脑袋干想,这样的一个真实思考过程。
刚刚分析完,原因已经找到。还是很快的,截了几张图片。就写了这个上传。
1、首先我在Trace中,再现了之前发现的那两处细节场景。
图中这两处4号温控器的执行被1号温控器抢断的场景,和其他一堆抢断情景,有一处不同,那就是:当4号温控器之后再次获得485执行权之后,它执行的任务序号,不是按照我预想的从0开始,而是接续上一次被抢断的断点之后的下一个默认顺序任务来执行的。
其实这样是没问题的,并且还有点自动接续的味道。只是它超出了我懒惰的思考,是什么原因呢?要找到。失控对设计者不是好事,这意味着浑浊和失真,而我喜欢清澈和真相。
图中显示,4号站被抢断的时候,是在它的上一个任务执行完毕之后,iJob回到了-1(看最后一行的红色箭头所指的那个一周期缝隙)。这说明优先权的切换,是按照预定的调度结构被派发出去的,上一个任务也是正确收尾的。
我在前面和在其它帖子中讲过:我的设备FB内部的调度结构是分层解耦架构的。
所以我首先想知道这个现象的紧邻原因是发生在哪一个层中,也就是哪个代码段中。
2、我在Trace增加了几个调度变量,来继续观察和捕捉,这样的场景出现和哪个调度层有关联。于是有了下面这张图片。
图中可以看到,我依然是继续触发了一大堆抢断任务。在最底下一行,我只保留了任务执行前调度这个变量。后面的原因就和它有关。
3、在前面2的Trace中,我的确又找到了两个一样的异常,并且找到了这两个异常的调度关联,与其它那一堆任务的不同之处。就在下面这张图片中。
我在其它主贴中讲过:因为通信属于公共IO资源,所以每一个使用者承担的义务,就是实时要关注别人的情况,这就是公平的代价。
落到程序中就是:在一个设备FB实例获得通信资源使用权之后,在它执行每一个任务之前,之中和之后,都要随时检查全局交互与竞争环境,知己知彼,做出恰如其分的公正判断。
尤其,通信任务都是异步的,跨多个扫描周期。而各种事件,在任一周期都随时可能出现。所以,调度结构需要尽量面面俱到,圆满无漏。这就和中国人团聚的时候,三老四少圆桌围坐,菜品高低搭配层次齐全;或者无论是建筑还是做事做人,讲究上下左右高低前后,层次和布局工整对称,一样的道理。尤其看古代精品建筑的结构,无不彰显多角度多层次观察和呈现事物的智慧,千手千眼。所谓中庸之海纳百川,也就是设计中的无为而无不为。这就是调度体系分层设计的一种理由,为了均衡和包容。
在上图中,我发现这两处异常,和其它所有优先抢断的不同之处都有一个特点:优先权切换都是在执行前调度这个环节发生的。其它所有正常切换如预料的,都不是从这个层派发的。于是,溯源焦点被收缩到执行前这个环节。
4、执行前调度的状态,其实是和执行后调度的状态关联的。
因为下一个任务执行前的调度,一定是和上一个任务执行完毕后的调度,相关联的,那是历史信息的来源。于是,溯源焦点被转移到执行后调度这个环节。
5、在执行后调度这个层中,有一个变量,是除了iJob之外,记录下一个任务序号的。
那么这个异常的出现,一定和这个变量的使用场合有关。而这个变量就是被用在执行前调度中。于是,溯源焦点又再次被转移回执行前这个环节。
6、在执行前调度层中,在优先权切换这个调度元素中,这个变量没有被复位,这就是最终的原因。
这个变量是用来给iJob赋值的,因为没有复位,所以下一次再获得执行权的时候,iJob就会按照下一个默认次序来执行,而不是从0开始。
所以,只要在这个调度元素中,加入一个简单的赋值语句来给这个变量复位,就OK了。当然了,改不改都可以,关键是找到原因,本来也没啥影响。
那么为什么会出现这种异常呢?
首先因为:这个异常不会引起任何功能障碍,所以在使用层面觉察不到。我在调试中,很多时候也懒得去看那些不引起我注意的无关环节。
所谓分层解耦架构的意义就在这里:特定的异常,总是和特定的层与元素相关。与逻辑回溯路径相关的层,它们以外的其它层和元素,是根本不用考虑和改动的。赖人喜欢这样。
这就是我前面提到的:可能性的收窄设计,强化可溯源的因果链。效率就是这样来的。
写这段帖子,比回溯原因还费事。
请填写推广理由:
分享
只看
楼主