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 獲取相應的信息。

最後,如果本文對你有用,歡迎關注、點贊、收藏、分享,感謝支持!

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