RFC-0084:在 zx_info_task_runtime_t 新增更多指標

RFC-0084:在 zx_info_task_runtime_t 中加入更多指標
狀態已接受
領域
  • 核心
說明

將其他指標新增至 zx_info_task_runtime_t,以便對媒體效能問題進行偵錯。

問題
毛皮變化
  • 485181
作者
審查人員
提交日期 (年-月-日)2021-03-09
審查日期 (年-月-日)2021-04-06

摘要

ZX_INFO_TASK_RUNTIME 主題可讓您擷取 工作在 CPU 或佇列中執行所花費的時間。診斷時 排程瓶頸,建議新增其他精細執行階段 尤其是等待頁面錯誤 等待核心互斥鎖所花費的時間。

提振精神

即時工作設有期限。有時工作會因為工作而錯過期限 在核心中執行非預期長的時間如要對這些情況進行偵錯 會很有幫助。舉例來說 但花費 10 毫秒,但等待 11 毫秒,頁面發生錯誤時,我們就認定 網頁錯誤速度太慢,因此超過期限。

具體來說,我們希望改善媒體子系統產生的診斷資料,例如 audio_core。在 audio_core 中,每個混合器工作必須在 10 毫秒內完成。如果 工作耗時超過 10 毫秒,使用者將會聽到音訊不流暢的情形。最近我們 因網頁錯誤速度緩慢 (其中 audio_core 可執行) 而錯過期限 重新分頁) 和呼叫核心的堆積互斥鎖 這些問題無法用快照診斷,因此我們必須 是一項繁瑣的程序,但有時難以執行 在本機重現問題 (因為錯誤可能只會在有特定要求時觸發, 特定環境中的 App Engine 應用程式)。這些是高度優先的問題,而且 嚴重對媒體成效造成負面影響。

我們的目標是從核心匯出足夠的診斷資訊, 可以從快照診斷問題,不必深入瞭解 執行追蹤記錄本文件建議在 zx_info_task_runtime_t以更全面地回答以下問題:「為什麼這是什麼原因?」 「無法執行任務嗎?」

Zircon 執行緒期限的背景

Zircon 期限設定檔包含三個部分:經期、容量和期限。 為執行緒指派期限設定檔時,Zircon 會確保每個執行緒 period 則會在 每個期間的開頭。請參考以下示例:

  • 期間 = 10 毫秒
  • 容量 = 2 毫秒
  • 期限 = 5 毫秒

每 10 毫秒,執行緒就會在接下來的 5 毫秒內分配 2 毫秒的 CPU。另有 不符合期限的兩種做法:

  1. 這項工作已排定遲交。例如,如果下個經期是從時間開始 T,但工作必須安排在 T+4 毫秒後完成,因此這項作業不可能 使工作達到期限 (應該排定在 T+3 毫秒)。核心可以偵測這類錯過的期限 但在實務上 除非排程器發生錯誤或超額訂閱,否則一律不會發生這種狀況。

  2. 工作需要超過 2 毫秒才能完成。核心無法得知何時 原因是無法理解任務邊界舉例來說, 工作安排在 T+1 毫秒執行,執行總時間為 1 毫秒,接著封鎖 9 毫秒。 核心無法得知工作是否已超過其期限 (因為 或者工作要求 2 毫秒,但只需要 1 毫秒, 完成 (然後睡眠 9 毫秒,等待下一個經期)。

我們的目標是幫助診斷第二類錯過的期限。目前, 工作執行時間過長,可以查詢 ZX_INFO_TASK_RUNTIME 來瞭解 使用者空間在 CPU 上執行的時間。如果 cpu_time大於 任務的預期執行階段,該工作知道只是執行了過長而已。不過 如果 cpu_time 是總工作時間的一小部分,則工作 在核心中大部分的時間,可能遭阻斷而無法執行。目標 的用意是協助瞭解時間花費的時間

設計空間

我們的目標是回答「為何這項工作無法執行?」這個問題。我們必須 做一些決定:

  1. 我們的回答是否完整?具體而言, 為何工作遭封鎖,或僅有幾個重要原因?

  2. 我們應該在多精細的程度上回答這個問題。舉例來說 只會回報使用者層級可理解的簡單事件,例如 「在 zx_channel_read 遭到封鎖」或者包含層級較低的事件 是否與 Zircon 目前的實作相關?

  3. 如果我們回報 N 的統計資料,就必須要求 N 統計 是否彼此重疊,或者是否該開放它們互相重疊?

最簡單也最直接的做法是列舉幾個我們關注的事件 並產生這些事件的統計資料媒體子系統 頁面錯誤和核心鎖定爭用時,我們可能會產生 「網頁錯誤花費時間」的統計資料以及「在核心上遭到封鎖的時間」 鎖定」

除了這兩種廣告以外,您可能還無法掌握其他潛在的問題 統計資料。因此,完整的解決方案才有吸引力。列舉一個概念 讓執行緒可進入核心的所有可能方式包括 N 硬體 中斷 (計時器和裝置中斷) 和 K 軟體中斷 (系統) 呼叫與錯誤)。然後產生 N+K 統計資料, 幹擾。計時器會在執行緒進入核心時啟動,並在出現以下情況時停止: 控制項會傳回使用者空間執行緒。不過,使用者層級 「在 syscall X 花費的時間」,讓核心計算出此資訊 是多餘的。

另一個概念是產生統計資料「使用時 核心模式」和「在 X 上遭到封鎖的時間」,其中 X 是一組核心 例如「核心鎖定」或「管道」這個想法有膨脹的風險 而核心數量會隨著時間逐漸變動

我們要退一步,我們真正想要的是從外部裝置擷取追蹤記錄。 理想情況下,我們會持續將追蹤記錄錄製到圓形緩衝區中 緩衝處理完成後 TRACE_ALERT

設計

我們當然有理想的解決方案 設計與建構我們急需診斷效能降低的情況 。因此,我提議增加兩個目標指標,以解決我們的 立即問題:等待頁面錯誤而花費的時間 也就是等待核心鎖定所花費的時間。

關於上述設計空間相關問題:

  1. 我們不會追求完整性。

  2. 精細程度是任意選項 (我們會記錄任何我們認為所需的內容)

  3. 統計資料可能會以任意方式重疊

核心變更

// This struct contains a partial breakdown of time spent by this task since
// creation. The breakdown is not complete and individual fields may overlap:
// there is no expectation that these fields should sum to an equivalent
// "wall time".
typedef struct zx_info_task_runtime {
  // Existing fields
  zx_duration_t cpu_time;
  zx_duration_t queue_time;

  // New fields below here

  // The total amount of time this task and its children spent handling page faults.
  zx_duration_t page_fault_time;

  // The total amount of time this task and its children spent waiting on contended
  // kernel locks.
  zx_duration_t lock_contention_time;

} zx_info_task_runtime_t;

系統會依執行緒計算這兩個欄位,然後在程序之間加總 以及 cpu_timequeue_time 目前完成的工作。請注意, 媒體子系統不需要對個別程序和每項工作進行匯總,但 加入到這裡,以便與 zx_info_task_runtime_t

頁面錯誤和多個核心鎖定分成多種類型, page_fault_time 代表處理各種網頁所花費的總時間 也會發生故障藉由涵蓋所有網頁錯誤,我們不必說明 這可能不容易,因為核心可能會新增 導入作業會隨時間變化,並且移除特定類型的網頁錯誤, 支援新架構

lock_contention_time 可涵蓋所有意外鎖定。但所指稱的「困難」 保留刻意指定,因此核心可能會改進其實作方式 以便平衡評估爭用成本與 報告所需時間如需進一步討論,請參閱導入作業 (請見下文)。

使用者空間如何診斷未及時指定的期限

由於這些新欄位,使用者空間可以使用類似下方的程式碼來診斷 錯過的期限:

for (;;) {
  zx_object_get_info(current_thread, ZX_TASK_RUNTIME_INFO, &start_info, ...)
  deadline_task()
  if (current_time() > deadline) {
    zx_object_get_info(current_thread, ZX_TASK_RUNTIME_INFO, &end_info, ...)
    // ...
    // report stats from (end_info - start_info)
    // ...
  }
}

實作

page_fault_time 會計算所有頁面錯誤處理常式花費的總時間。 在目前的實作中,這包括 vmm_page_fault_handlervmm_accessed_fault_handler

lock_contention_time 會計算 Mutex::AcquireContendedMutexBrwLock::Block。這個方法 存取目前的Threadcurrent_ticks()。實作方式 不會遮住旋轉鎖頭雖然旋轉鎖可能很常發生,但我們會忽略旋轉 因為如要測量旋轉鎖的爭用情形,可能會暫時鎖定 。

為了盡可能減少額外負荷,我們會將這些時間長度記錄為滴答聲, 則會在 zx_object_get_info 系統呼叫期間轉譯為 zx_duration_t。 其他實作細節會沿用 《cpu_time》和《queue_time》。原型導入網址為 fxrev.dev/469818。

成效

我們將執行 Zircon Mutex 基準測試,確認沒有任何迴歸問題。我們會 這些基準測試是在原始硬體 (x86 和 ARM) 上執行。此外,如要驗證 虛擬化環境內不會有迴歸 為 QEMU (x86 和 ARM) 基準。

回溯相容性

zx_info_task_runtime_t 結構會進行版本管理,與先前版本相似 完成其他 zx_info_* 結構體的作業 (例如,請參閱 fxrev.dev/406754)。

安全性考量

ZX_INFO_TASK_RUNTIME」是一個側邊管道,可能會洩露 已檢查工作。舉例來說,page_fault_time 可用於測量工作的 記憶體存取模式為了緩解這種外洩事件, 「ZX_INFO_TASK_RUNTIME」主題已有 ZX_RIGHT_INSPECT。具有 即可假設使用者擁有工作私人資料的存取權。

ZX_INFO_TASK_RUNTIME 可能也會洩露其他工作的間接資訊。適用對象 舉例來說,如果工作知道自己的 page_fault_time,系統或許能推斷出 「其他」工作的記憶體存取模式。同樣地,如果工作知道 進而推斷出如何 也會使用共用核心資源未來我們可能會在 使用低解析度計時器zx_info_task_runtime_t。這不一定 可以防止時間攻擊,但可以限制其有效性。

另一項防護是限制特殊開發人員可以存取「zx_info_task_runtime_t」 建構應用程式不過,這樣會大幅限制這項功能的實用性: 所以在開發環境中,我們通常無法重現效能錯誤。 我們需要可以在正式版本中啟用的解決方案。

為避免這個側邊管道完全採用,我們需要區隔指標報表 和指標檢查拆分為不同的功能。舉例來說 將追蹤記錄持續錄製到環形緩衝區中,然後將該緩衝區上傳至 或是他造訪 YouTube 數據分析的 TRACE_ALERT、 那麼無需提供觸發 TRACE_ALERT 的任務 就能排除側邊管道。稍早提過 這樣的解決方案需要很長的時間來設計及建構 需要立即解決問題

隱私權注意事項

無。

說明文件

Zircon syscall 說明文件需要更新,加入新的 zx_info_task_runtime_t 欄位。

既有藝術品和參考資料

在 Linux 中,最為相關的前項是 getrusage,這是回報使用者的資訊 以及系統 CPU 作業時間和頁面錯誤數、I/O 作業和環境切換。 Windows 的 GetThreadTimes 會回報使用者和系統 CPU 作業時間。硬體 效能計數器 (例如 x86 上的 RDPMC) 會提供類似的資訊,以及 擁有 類似的安全疑慮

測試

我們會透過 audio_core 記錄新的執行階段資訊,以手動方式進行測試 (我們也已經完成原型導入作業:請參閱 fxrev.dev/469819)。

我們會更新 cpu_timequeue_time 的現有測試,以測試舊的 zx_info_task_runtime_t 的新版本,將會命名 zx_info_task_runtime_v1_t。此外,Zircon 的 abi_type_validator.h ,以便驗證新舊 ABI。如此能確保 ABI 保有回溯相容性

要為這項功能新增整合測試並不容易,因為 沒有 API 可強制核心進行鎖定爭用或觸發頁面錯誤 (除程序終止區隔錯誤以外)。