避免優先順序反轉

本文說明 Android 音訊系統如何避免 優先順序反轉 並重點介紹可用的技巧

這些技術可能對高效能的開發人員有幫助 音訊應用程式、原始設備製造商 (OEM) 和正在導入音訊的 SoC 供應商 HAL。請注意,使用這些技術 保證能避免資料出現故障或其他故障 用於音訊情境以外的其他用途 實際結果可能會有差異,因此您應自行評估 評估和測試

背景

Android AudioFlinger 音訊伺服器和 AudioTrack/AudioRecord 為縮短延遲時間,我們正在重新建構用戶端導入作業。 這項研究是從 Android 4.1 開始,並持續進行改善 4.2、4.3、4.4 和 5.0。

為了縮短延遲時間,整個系統必須進行多項變更。一 將 CPU 資源指派給具有時效性的關鍵 產生更可預測的排程政策的執行緒。可靠的排程 可在靜止不動時,減少音訊緩衝區的大小和數量 避免效能不足或超支

優先順序反轉

優先順序反轉 是即時系統的故障模式 高優先順序工作在無限制的時間內遭到封鎖 以便讓低優先順序工作釋出資源,例如 受保護的州級資訊) Mutex

在音訊系統中,優先順序反轉通常會以 故障 (點擊、彈出、丟棄)、 重複音訊 循環緩衝區時 或延遲回應指令時

優先順序反轉的常見解決方法,是增加音訊緩衝區大小。 不過,這個方法會增加延遲時間,而且只會隱藏問題。 而不是解決問題建議您先瞭解和避免優先考慮優先順序 如下圖所示

在 Android 音訊實作中,優先順序反轉的情形 問題通常出現在這些地方因此你應該將注意力集中在此處:

  • AudioFlinger 的一般混音器執行緒和快速混音器執行緒之間的差異
  • 加快 AudioTrack 的運作速度。 快速混合器執行緒 (兩者的優先順序較高,但稍有不同) 不同的優先順序)
  • 達到快速的 AudioRecord 和 快速擷取執行緒 (與上一個類似)
  • 導入音訊硬體抽象層 (HAL) 實作程序,例如取消電話或回音取消
  • 核心音訊驅動程式中的介面
  • 音訊追蹤或 AudioRecord 回呼執行緒與其他應用程式執行緒 (無法由我們控制)

常見解決方案

一般解決方案包括:

  • 停用中斷
  • 優先順序繼承互斥鎖

在 Linux 使用者空間中,無法停用中斷功能,而且 不適用於對稱多處理器 (SMP)。

優先順序繼承 futexes (快速的使用者空間互斥鎖) 相對較重,因此不會用於音訊系統。 並仰賴信任的用戶端

Android 使用的技巧

實驗一開始為「嘗試鎖定」並設為逾時這些 Mutex Lock 的非阻斷式和受限的封鎖變化版本 作業。鎖定和鎖定時仍可正常運作,但用意是 通常很明顯的故障模式可處理: 如果 用戶端處於忙碌狀態,累計逾時時間 如果長時間不相關的鎖定 逾時。

我們也會使用 不可分割的運算 例如:

  • 增加
  • 位元「or」
  • 位元「and」

這些函式都會傳回先前值,並加入必要的 SMP 技術障礙缺點是可以需要無限次數的重試。 實務上,我們發現重試不是問題。

注意:原子運算及其與記憶體屏障之間的互動 因為無意間誤解及用錯。我們納入了這些方法 這篇文章有完整內容,但建議您也閱讀 Android SMP 入門課程

我們仍有並使用了大部分的上述工具,最近 新增了以下技術:

  • 使用非封鎖的單一讀取者 FIFO 佇列
  • 請嘗試 複製 而非 分享 介於 低優先順序模組
  • 在需要共用狀態時,請將狀態限制為 最大尺寸 字詞 能以不可分割的形式在單一匯流排作業中存取 不必重試
  • 如果是複雜的多字詞狀態,請使用狀態佇列。狀態佇列 基本上是非阻斷單一讀取器的單一寫入者 FIFO 用於狀態而非資料的佇列,但寫入者會收合 彼此相鄰的項目會推動一次推送。
  • 請留意 記憶體障礙 以便確認 SMP 的正確性。
  • 信任,但進行驗證。 分享時 州/省 程序 我們會假設狀態格式正確。舉例來說 在界限內。執行緒之間不需要進行這項驗證 在同一程序中,相互信任程序之間 通常都具有相同的 UID)。這類資訊也不需要共用 資料 例如 PCM 音訊發生毀損的情形。

非封鎖演算法

非阻塞演算法 是近期研究的科目 但只有單一讀取者 FIFO 佇列例外 但我們發現它們相當複雜且容易出錯

從 Android 4.2 開始,有一項非封鎖規則 單一讀取者/寫入者類別:

  • 架構/av/include/media/nbaio/
  • 架構/av/media/libnbaio/
  • 架構/av/services/audioflinger/StateQueue*

這些設計是針對 AudioFlinger 設計的,並非 一般用途尤其是會妨礙閱讀 難以偵錯您可以將此程式碼視為模型。但 可能會有錯誤且類別不保證一定 其他用途

針對開發人員,部分 OpenSL ES 應用程式程式碼範例應更新為 使用非阻塞演算法,或參照非 Android 的開放原始碼程式庫。

我們已發布一個專為 FIFO 實作的範例 應用方式。查看位於平台來源目錄中的檔案 frameworks/av/audio_utils:

工具

據我們所知, 找出優先反轉順序,特別是在事件發生前。只有部分通知 研究靜態程式碼分析工具能找出優先要務 若能存取整個程式碼集,則反轉。當然,如果 涉及任何使用者程式碼 (就像在本應用程式使用) 或是大型程式碼集 (例如 Linux 核心和裝置驅動程式) 靜態分析可能不切實際最重要的是 仔細閱讀程式碼,並 系統和互動情形例如 Systraceps -t -p 有助於在發生優先順序反轉後才查看 且不會事先告知您

最後一個字詞

完成上述討論後,別害怕互斥鎖。互斥鎖 正確使用和執行時,是您日常使用上的好幫手 執行一般非重要用途但介於 低優先順序工作和有時效性的系統互斥鎖 問題