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 - 時鐘做為從參考時間轉換為合成時間的轉換函式
在現有設計中,時鐘維護者會使用 zx_clock_update_args_v1_t.rate_adjust
提供此線段的漸層,並使用 zx_clock_update_args_v1_t.value
提供線段起點的 y 座標。當核心處理系統呼叫時,會將區段開頭的 x 座標設為單調時間。
這個定義的區段起點,以及由不同實體設定的兩個座標,是時鐘錯誤的根本原因,如圖 2 所示。
圖 2 - 計算和處理之間的延遲導致時鐘錯誤
我們建議變更 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_VALID
和 ZX_CLOCK_UPDATE_OPTION_SYNTHETIC_VALUE_VALID
。
行為變更
為方便您閱讀本節和下一節的內容,我們將 ZX_CLOCK_UPDATE_OPTION_X_VALID
簡寫為 X_VALID
。
當 REFERENCE_VALUE_VALID
、SYNTHETIC_VALUE_VALID
和 RATE_ADJUST_VALID
都已設定時,zx_clock_update
會在目前的參考時間開始新的線段,並與 zx_clock_update_args_v2_t.rate_adjust
決定的漸層相交會於點 (reference=zx_clock_update_args_v2_t.reference_value
、synthetic=zx_clock_update_args_v2_t.synthetic_value
),如圖 3 所示。
圖 3 - 同時更新時鐘的值和速率
當 REFERENCE_VALUE_VALID
和 SYNTHETIC_VALUE_VALID
已設值,但 RATE_ADJUST_VALID
未設值時,zx_clock_update
會在目前的參考時間開始新的線段,並與以先前時脈速率決定的漸層相交,如圖 4 所示。reference=zx_clock_update_args_v2_t.reference_value
synthetic=zx_clock_update_args_v2_t.synthetic_value
圖 4 - 僅更新時鐘值
當 REFERENCE_VALUE_VALID
和 RATE_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_VALID
或 SYNTHETIC_VALUE_VALID
,zx_clock_update
會傳回 ZX_ERR_INVALID_ARGS
錯誤。
如果未設定 REFERENCE_VALUE_VALID
,zx_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
錯誤:
- 已設定
SYNTHETIC_VALUE_VALID
,但未設定REFERENCE_VALUE_VALID
。 RATE_ADJUST_VALID
和REFERENCE_VALUE_VALID
都已設定。
請注意,這表示您無法在同一個 zx_clock_update
呼叫中同時變更 ZX_CLOCK_OPT_MONOTONIC
時鐘的速率和偏移量。
實作
這項異動將分四個階段實施:
- 定義
zx_clock_update_args_v2_t
、ZX_CLOCK_UPDATE_OPTION_REFERENCE_VALUE_VALID
和ZX_CLOCK_UPDATE_OPTION_BOTH_VALUES_VALID
; - 更新
clock.cc
和相關單元測試,以便接受zx_clock_update_args_v2_t
; - 更新特定語言的包裝函式 (例如 Rust 的
fuchsia-zircon
),以便使用zx_clock_update_args_v2_t
並公開新功能。 - 更新 Timekeeper,以便在設定世界標準時間時提供參考值,並縮小可接受的測試誤差時間範圍。
成效
由於 zx_clock_update
系統呼叫並未大量使用,且變更幅度不大,因此這項變更對效能影響極小。
如果設定 ZX_CLOCK_UPDATE_OPTION_REFERENCE_VALUE_VALID
,zx_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 - 以合成偏移為基礎的替代解決方案
這樣一來,您就能在 API 中進行較小的變更,完全指定新行。不過,這對時鐘維護人員來說不夠直覺,且需要更複雜的計算才能正確使用。我們認為,在 Fuchsia 的生命週期中,這個替代方案會產生更多錯誤。
既有技術與參考資料
kernel_objects/clock 可提供使用者空間時鐘的運作概況。
UTC 同步處理演算法總結了目前的 UTC 同步處理設計。
「Zircon Syscalls Struct Evolution」是 Google 內部於 2019 年 5 月發布的文件,討論了 syscall 結構體的演進歷程,可能對有權存取的讀者有所助益。