RFC-0077:改善 zx_clock_update 準確率

RFC-0077:提升 zx_clock_update 的準確度
狀態已接受
區域
  • Kernel
說明

zx_clock_update 的變更,可讓時鐘維護人員選擇提供更多資訊,並提高準確度。

問題
Gerrit 變更
作者
審查人員
提交日期 (年-月-日)2021-03-04
審查日期 (年-月-日)2021-03-18

摘要

zx_clock_update 系統呼叫用於在核心時鐘物件中設定時間,但目前的 API 設計會限制可達成的準確度。這項 RFC 說明 zx_clock_update 的變更,可讓時鐘維護人員選擇提供更多資訊,並提高準確度。

提振精神

核心時鐘物件會使用 zx_clock_update 系統呼叫更新。時鐘維護人員可以設定 ZX_CLOCK_UPDATE_OPTION_VALUE_VALID 並將新時間放在 zx_clock_update_args_v1_t.value 中,要求時鐘進行步進式變更。

這個 API 設計簡單易用,但設定新時鐘值時,可能會限制可達成的準確度:計算 zx_clock_update_args_v1_t.value 和呼叫 zx_clock_update 之間,使用者空間程序可能會遭到搶占,而這兩個事件之間每延遲 1 毫秒,時鐘就會出現 1 毫秒的誤差。這個錯誤會導致 UTC 整合發生問題,並造成許多測試失敗,尤其是在模擬器上,錯誤可能達到數百毫秒。請注意,zx_clock_update 也支援變更時鐘的速率,而不需設定新值,且這類僅限速率的更新較不容易發生錯誤。

這項 RFC 定義了 zx_clock_update 的新選項,可為世界標準時間和其他核心時鐘的未來使用者提供更準確的時鐘。

設計

總覽

「時鐘」是「時鐘單調」參考時間軸的「一維仿射轉換」,定義「參考」時間 (即裝置的單調時鐘) 應如何轉換為時鐘輸出的「合成」時間。時鐘維護人員要求變更時鐘時,實際上是在這個轉換中提供新的線段,如圖 1 所示。

圖 1:時鐘,代表從參考時間轉換為合成時間
這張圖呈現參考時間 (X 軸) 與合成時間 (Y 軸) 之間的關係,以多個線段表示,有些線段相鄰,有些則不相鄰。

在現有設計中,時鐘維護人員會使用 zx_clock_update_args_v1_t.rate_adjust 提供這條線段的漸層,並使用 zx_clock_update_args_v1_t.value 提供線段開頭的 Y 座標。核心會在處理系統呼叫時,將區段開頭的 x 座標設為單調時間。

如圖 2 所示,這項區段開始時間的定義是由不同實體設定的兩個座標,是時鐘錯誤的根本原因。

圖 2 - 計算和處理之間的延遲會導致時鐘錯誤
這張圖顯示參考時間 (x 軸) 和合成時間 (y 軸) 之間的預期和實際關聯,兩者差異即為時鐘錯誤。

我們建議變更 zx_clock_update 引數,讓時鐘維護者完整指定預期線條,而核心則決定套用變更的參考時間,也就是這條線上的起始位置。

API 變更

我們推出新的 zx_clock_update_args_v2_t 結構體,其中包含 zx_clock_update_args_v1_t 中的所有欄位,以及額外的 reference_value 欄位。我們也新增了 ZX_CLOCK_UPDATE_OPTION_REFERENCE_VALUE_VALID 選項。

為保持命名一致性,我們將 zx_clock_update_args_v1_t 中的 value 欄位重新命名為 zx_clock_update_args_v2_t 中的 synthetic_value,並將 ZX_CLOCK_UPDATE_OPTION_VALUE_VALID 重新命名為 ZX_CLOCK_UPDATE_OPTION_SYNTHETIC_VALUE_VALID

為方便起見,我們也定義了 ZX_CLOCK_UPDATE_OPTION_BOTH_VALUES_VALID,可用於設定 ZX_CLOCK_UPDATE_OPTION_REFERENCE_VALUE_VALIDZX_CLOCK_UPDATE_OPTION_SYNTHETIC_VALUE_VALID

行為變更

為求簡潔易讀,在本節和下一節中,我們會將 ZX_CLOCK_UPDATE_OPTION_X_VALID 簡稱為 X_VALID

設定 REFERENCE_VALUE_VALIDSYNTHETIC_VALUE_VALIDRATE_ADJUST_VALID 後,zx_clock_update 會在目前的參考時間開始新的線段,與由 zx_clock_update_args_v2_t.rate_adjust 決定的漸層相交於一點 (reference=zx_clock_update_args_v2_t.reference_valuesynthetic=zx_clock_update_args_v2_t.synthetic_value),如圖 3 所示。

圖 3 - 更新時鐘的值和速率
這張圖說明如何指定參考時間、合成時間和漸層,藉此更新時鐘。

如果已設定 REFERENCE_VALUE_VALIDSYNTHETIC_VALUE_VALID,但未設定 RATE_ADJUST_VALID,則 zx_clock_update 會在目前的參照時間啟動新的線段,並與先前時鐘速率決定的漸層相交於一點 (reference=zx_clock_update_args_v2_t.reference_valuesynthetic=zx_clock_update_args_v2_t.synthetic_value),如圖 4 所示。

圖 4 - 僅更新時鐘值
這張圖說明如何指定參考時間和合成時間,藉此更新時鐘。

如果已設定 REFERENCE_VALUE_VALIDRATE_ADJUST_VALID,但未設定 SYNTHETIC_VALUE_VALIDzx_clock_update 會在目前的參照時間啟動新的線段,與先前線段上的點在 reference=zx_clock_update_args_v2_t.reference_value 相交,並以 zx_clock_update_args_v2_t.rate_adjust 決定的漸層顯示,如圖 5 所示。

圖 5 - 僅更新時脈速率
這張圖說明如何指定參考時間和更新後的速率,藉此更新時鐘。

如果設定 REFERENCE_VALUE_VALID,但未設定 RATE_ADJUST_VALIDSYNTHETIC_VALUE_VALIDzx_clock_update 會傳回 ZX_ERR_INVALID_ARGS 錯誤。

如果未設定 REFERENCE_VALUE_VALIDzx_clock_update 會按照現有行為,在目前的參考時間啟動新的線段,並在設定 SYNTHETIC_VALUE_VALID 時將合成時間變更為 zx_clock_update_args_v2_t.synthetic_value,以及在設定 RATE_ADJUST_VALID 時根據 zx_clock_update_args_v2_t.rate_adjust 變更漸層。

連續和單調時鐘

時鐘可能在建立時設定了 ZX_CLOCK_OPT_MONOTONIC 和/或 ZX_CLOCK_OPT_CONTINUOUS 選項,因此可套用的更新有限。

ZX_CLOCK_OPT_CONTINUOUS時鐘不會接受任何時間步進變更。從圖 4、5 和 6 可以看出,REFERENCE_VALUE_VALID 一律會在合成值中引入不連續性,因此為 ZX_CLOCK_OPT_CONTINUOUS 時鐘設定 REFERENCE_VALUE_VALID 一律會導致 ZX_ERR_INVALID_ARGS 錯誤。

如果時鐘具有 ZX_CLOCK_OPT_MONOTONIC 但沒有 ZX_CLOCK_OPT_CONTINUOUS,則只有在時間步進變更會導致合成值增加時,才會接受這類變更。部分時鐘更新可能會導致競爭條件,視要求到達核心的時間而定,要求可能會獲得接受或遭到拒絕。舉例來說,在 RFC 推出前,如果呼叫程序在計算 zx_clock_update_args 和呼叫 zx_clock_update 之間遭到搶占超過 5 毫秒,系統就會拒絕將單調時鐘設為未來 5 毫秒的要求。

這種不確定性並不理想,因此在 ZX_CLOCK_OPT_MONOTONIC 時鐘上發出以下 zx_clock_update 要求時,會因 ZX_ERR_INVALID_ARGS 錯誤而失敗:

  1. 已設定 SYNTHETIC_VALUE_VALID,但未設定 REFERENCE_VALUE_VALID
  2. RATE_ADJUST_VALIDREFERENCE_VALUE_VALID 都已設定。

請注意,這表示您無法在同一個 zx_clock_update 呼叫中,同時變更 ZX_CLOCK_OPT_MONOTONIC 時鐘的速率和偏移。

實作

這項異動將分四個階段實施:

  1. 定義 zx_clock_update_args_v2_tZX_CLOCK_UPDATE_OPTION_REFERENCE_VALUE_VALIDZX_CLOCK_UPDATE_OPTION_BOTH_VALUES_VALID
  2. 更新 clock.cc 和相關聯的單元測試,以接受 zx_clock_update_args_v2_t
  3. 更新語言專屬的包裝函式 (例如 Rust 的 fuchsia-zircon),以使用 zx_clock_update_args_v2_t 並公開新功能。
  4. 更新 Timekeeper,在設定世界標準時間時提供參考值,並縮小允許的測試錯誤範圍。

效能

由於 zx_clock_update syscall 的使用量不高,且變更幅度不大,因此這項異動對效能的影響極小。

如果設定 ZX_CLOCK_UPDATE_OPTION_REFERENCE_VALUE_VALIDzx_clock_update_args 會增加 8 個位元組,且核心在處理 zx_clock_update 時會執行更多整數算術指令。

安全性考量

這項變更不會改變時鐘維護者與時鐘使用者之間的關係,因此不會影響安全性。

隱私權注意事項

這項異動不會改變時鐘維護者與時鐘使用者之間的關係,因此不會影響隱私權。

測試

kernel-clocks.cc 中的單元測試會擴大範圍,涵蓋這項新行為。系統會更新 Timekeeper,使用明確的單調時間設定世界標準時間,因此現有的世界標準時間單元和整合測試會提供額外的測試涵蓋範圍。

說明文件

zx_clock_update 參考說明文件將更新,說明這項新行為。

缺點、替代方案和未知事項

較簡單的替代方案是保留現有的 zx_clock_update_args_v1_t 結構體,但導入額外的 ZX_CLOCK_UPDATE_OPTION_ZERO_VALUE_VALID 選項來變更其解讀方式。設定 ZX_CLOCK_UPDATE_OPTION_ZERO_VALUE_VALID 時,核心會將 zx_clock_update_args_v1_t.value 解讀為對應於 monotonic=0 的合成時間,並確保新線段通過點 (monotonic=0, synthetic=zx_clock_update_args_v1_t.value),如圖 6 所示。

圖 6 - 以合成偏移為基礎的替代解決方案
這張圖顯示 x 軸上的參考時間和 y 軸上的合成時間,並說明如何使用 x=0 上的位置和漸層進行設定。

這項做法的效果是透過 API 的微小變更,完整指定新行。不過,這種格式對時鐘維護人員來說較不直覺,且需要更複雜的計算才能正確使用。我們認為,在 Fuchsia 的生命週期中,這個替代方案會產生更多錯誤。

既有技術和參考資料

kernel_objects/clock 提供使用者空間時鐘運作的總覽。

世界標準時間同步演算法 總結目前的世界標準時間同步設計。

「Zircon Syscalls Struct Evolution」是 2019 年 5 月的 Google 內部文件,討論了系統呼叫結構的演變,可能對有權存取該文件的讀者有所幫助。