RFC-0077:改善 zx_clock_update 準確率

RFC-0077:改善 zx_clock_update 的準確度
狀態已接受
區域
  • 核心
說明

變更 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 會在目前的參考時間開始新的線段,並與以先前時脈速率決定的漸層相交,如圖 4 所示。reference=zx_clock_update_args_v2_t.reference_valuesynthetic=zx_clock_update_args_v2_t.synthetic_value

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

REFERENCE_VALUE_VALIDRATE_ADJUST_VALID 已設定,但 SYNTHETIC_VALUE_VALID 未設定時,zx_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 系統呼叫並未大量使用,且變更幅度不大,因此這項變更對效能影響極小。

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

安全性考量

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

隱私權注意事項

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

測試

kernel-clocks.cc 中的單元測試會擴充,以涵蓋這項新行為。Timekeeper 將更新為使用明確的單調時間設定世界標準時間,以便現有的 UTC 單位和整合測試提供額外的測試涵蓋率。

說明文件

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 可提供使用者空間時鐘的運作概況。

UTC 同步處理演算法總結了目前的 UTC 同步處理設計。

「Zircon Syscalls Struct Evolution」是 Google 內部於 2019 年 5 月發布的文件,討論了 syscall 結構體的演進歷程,可能對有權存取的讀者有所助益。