linux 系统 CPU 负载高导致丢失 camera 中断从而丢帧的查找过程

问题背景

编写 camera 应用应该都知道,如果应用层没有及时的获取 buf,或者长期占用了内核的 buf 而没有返回给内核队列将会导致丢帧。这个丢帧是应用操作导致内核驱动队列 buf 不够用而覆盖之前的图像内容导致的丢帧,这种丢帧是内核驱动框架是知道的,本来应该重新设置 DMA 的目标地址的,但是因为队列中没有空闲的 buf 从而覆盖之前旧的 buf,也就是这样的丢帧,内核驱动是可以计数的,可以将该信息反馈到应用空间。

以上的情景在 camera 的相关内核中断是可以计数统计的,但本文探讨的是直接丢失 camera 中断的丢帧,也就是这个时候,中断计数也是没有办法确认是否存在丢帧的情况,而我们的项目需求是不可以不明不白的丢帧,允许应用没有及时处理图像从而导致图像内容被覆盖,但是不可以系统什么都不知道却丢失了图像数据。下面继续看看整个过程是怎样的。

发现问题

预览 camera 拍摄到的图像内容,仅通过肉眼是比较难发现是否丢帧的,那么我们是怎么发现有这个丢帧的操作的呢?

因为拍摄内容的特殊性,我们可以保证每帧图像拍摄到的内容都是不一样的,而且有规律可循的,我们在保证这样的一个前提下,发现有时候图像内容不是连贯的,但是系统没有任何的反馈(如果是覆盖丢帧,中断处理时将会有相应的信息),当存在系统没有信息提示,但是图像内容不连贯了,这个时候就怀疑我们接收端是否存在什么逻辑错误。

在这个问题中,我们的系统是和 MCU 配合使用的,我们将 sensor 配置为了 STROBE 输出,也就是在 sensor 进行曝光的时候,STROBE 将会输出为高电平,而其他情况将是低电平,MCU 检测该信号并进行相应的计数。同时,我们在 camera 中断中,将对 SOC 的一个 pin 进行翻转操作,帧头中断将 pin 置高,帧结束中断将 pin 置低,这样子,我们 SOC 也有一个帧信号输出。这样我们就可以使用示波器,一路接 sensor 的 STROBE 帧信号,一路接 SOC 的中断 pin 信号,然后运行应用程序,示波器查看两路信号是否是一一对应的,如果在某些情况下出现 SOC pin 翻转少了一次,那么就可以确认时接收端出现问题了。

实验结果发现,当图像内容不连贯时,SOC pin 翻转少了一次,同时我们还通过了 mipi 的一些相关寄存器发现,mipi 控制器是有接收到这帧的,而且 mipi 状态相关寄存器没有报错,也就是这帧图像数据是完整的,但是整个数据通路下来就是丢失了 camera 的中断,导致最终丢帧现象。

分析问题

从现象来看,SOC 是接收到该帧内容的,但是在最后 camera 中断中并没有表现出来,而且出现这样情况的时候,CPU 负载还是比较高的,而当 CPU 负载低的时候,是没有检测出问题的。同时如果相应的降低 sensor 输出的帧率,出现问题的概率又将大大减少。基于以上的情况,我们做出了以下的可能性判断:

  • camera 驱动框架存在问题,当高帧率高负载时处理不恰当导致丢失中断;
  • 在 CPU 负载高的时候,可能存在部分应用使用的驱动中存在长时间的关闭中断的状态,这样导致不能响应 camera 这边的中断;
  • CPU 负载高,导致一些线程,内核驱动等调度不及时,而新一帧图像的中断又到来了,从而覆盖了之前的中断导致现象为丢失中断;
定位问题

基于上面的一些分析判断,我们进行了以下的一些测试实验:

  1. 关于是否是其他的驱动关闭总中断,从而导致没有响应其他中断的。我们的实验操作如下:
    关闭、不使用系统中其他的外设,减少系统其他外设的中断,确认在应用运行的这个过程,仅有少数的驱动中断执行并确保不会长时间的关闭系统中断。
    实验测试发现,哪怕不使用其他的外设,减少系统的其他中断,还是存在 camera 中断丢失的情况,所以我们排除被关闭总中断从而丢失 camera 中断的可能。
  2. 设置系统应用线程的亲核性。
    测量应用运行过程中,各 CPU 的占用率,查看是否存在 CPU0 占用率较高的情况。因为 ARM 一般的都是通过 CPU0 响应系统 irq 中断的,如果 CPU0 占用率高,可能存在不能及时处理从而导致丢失中断的情况。将系统中比较耗 CPU 的线程通过 sched_setaffinity() 函数设置亲核性,将其迁移到除 CPU0 以外的核运行,保证 CPU0 可以及时的响应中断。
    实验测试发现,设置部分线程的亲核性之后,系统没有出现丢失 camera 中断的情况。因此我们推断是因为 CPU0 占用率高,导致不能及时响应中断从而导致丢失 camera 中断的情况出现。
  3. 将 camera 相关中断响应迁移到其他核。
    通过 echo 2 > /proc/irq/CAMERA_IRQ/smp_affinity 将 camera 的相关中断响应迁移到 CPU1,然后进行应用测试。这样可以排除是因为其他驱动中断关闭 CPU0 的中断从而导致的丢帧,如果在这样的情况下还是存在丢失中断的问题,那么需要检查 camera 驱动,确认是否存在逻辑漏洞,导致丢中断。
    实验测试发现,该实验是没有出现丢中断的情况。
解决问题

关于中断处理问题,后来发现在 linux 系统,应用跑在 CPU0 上,会有缺页中断异常,但它是没有关闭中断的,缺页异常优先级要高于 irq 异常,会有一定影响,但是影响不大。同时根据上面的一些测试结果,我们最终采取的方案是将比较耗 CPU 的线程都迁移到除 CPU0 的其他核上运行,如果后续测试发现还有丢失中断的情况,将会考虑设置线程亲核性 + 迁移中断响应的方式进行处理。
关于设置线程亲核性的问题,可以通过 cat /proc/PID/status 查看 Cpus_allowed_list: 1-3 信息来确认设置是否生效,上面信息代表着该线程在 CPU1~3 运行。
而查看中断是被哪个核响应的,可以 cat /proc/interrupts 获取相应的信息。

最后,如果本文对你有用,欢迎关注、点赞、收藏、分享,感谢支持!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章