| RFC-0114:在 FIDL 信封中內嵌小值 | |
|---|---|
| 狀態 | 已接受 |
| 區域 |
|
| 說明 | 這項 RFC 提議變更 FIDL 線路格式,將大小 <= 4 位元組的值內嵌至信封主體。 |
| Gerrit 變更 | |
| 作者 | |
| 審查人員 | |
| 提交日期 (年-月-日) | 2021-06-24 |
| 審查日期 (年-月-日) | 2021-07-21 |
摘要
這項 RFC 提議變更 FIDL 線路格式,將大小 <= 4 位元組的值內嵌至信封主體。
提振精神
這項變更的動機是改善 FIDL 資料表和聯集 (即目前使用封包的版面配置) 的效能。
FIDL 聯集和資料表會使用共用表示法,表示稱為封包的行外物件。已知編碼和解碼的額外負荷來源是行外指標。小型物件可直接放在信封內,避免產生額外費用。
此外,在某些情況下,您或許可以減少分配量。物件可以直接儲存在封包中,不必為物件分配行外位置,並從封包指向該位置。
設計
這項 RFC 設計以 RFC-0113 獲得核准為前提,該 RFC 導入了有效率的信封。
下列類型將使用新的內嵌值格式:
- bool
- float32
- uint8、uint16、uint32
- int8、int16、int32
- 具有 uint8、uint16、uint32、int8、int16、int32 版面配置的列舉
- 位元,版面配置為 uint8、uint16、uint32、int8、int16、int32
- 控制代碼、用戶端端點、伺服器端點
- 結構體 <= 4 個位元組
- 陣列 <= 4 位元組
如果日後新增的值類型大小 <= 4 個位元組,除非另有說明,否則也會使用內嵌值格式。
新格式可透過 C 結構表示法說明:
// An envelope corresponds to a union value or an entry in a table.
struct Envelope {
union {
// Inlined values have the same envelope structure for both wire and
// decoded formats.
InlinedValueEnvelope inlined_value_envelope;
// Out-of-line values have a different structure on the wire and in
// decoded format.
union OutOfLineEnvelope {
// Wire representation.
OutOfLineWireEnvelope out_of_line_wire_envelope;
// Decoded representation.
void* decoded_data;
};
};
};
struct InlinedValueEnvelope {
// A <= 4-byte value stored little-endian and 0-padded up to 4-bytes.
uint8_t value[4];
// Number of handles within the envelope.
uint16_t num_handles;
// Bit 0 of flags is 1 to indicate the inline representation is used and
// the envelope is present.
uint16_t flags;
};
struct OutOfLineWireEnvelope {
// Number of bytes recursively within the envelope.
uint32_t num_bytes;
// Number of handles recursively within the envelope.
uint16_t num_handles;
// Bit 0 of flags is 0 to indicate the out-of-line representation is used.
uint16_t flags;
}
線路表示法 InlinedValueEnvelope 和 OutOfLineWireEnvelope 都有重疊的 flags 欄位。flags 中的 LSB 會指出是否使用內嵌表單:1 代表內嵌,0 代表非內嵌。所有未使用的旗標位元「必須」為 0。
FIDL 中只有單一標準資料表示法。 大小最多 4 個位元組的值必須內嵌,超過 4 個位元組的值則必須使用行外表示法。如果收到錯誤表示法的值,系統「必須」觸發解碼錯誤。缺席信封會繼續使用零信封表示法,也就是一律以離線表示法表示。
實作
這項變更需要進行複雜的遷移作業。不過,這項遷移作業可以與其他線路格式遷移作業合併,因此實際成本會大幅降低。
效能
當欄位內嵌時,LLCPP 的編碼時間會大幅減少 (CL):
編碼時間 (以奈秒為單位),並設定所有欄位:
| # 欄位 | 使用前 | 使用後 |
|---|---|---|
| 1 | 178 ns | 147 奈秒 |
| 16 | 720 ns | 325 ns |
| 256 | 9396 ns | 2909 ns |
這張圖表顯示編碼時間與表格欄位數量的關係。 資料表中的所有欄位都已設定。
我們並未測量解碼時間,但預期也會有顯著改善,因為解碼演算法的步驟與編碼類似。
此外,繫結有時可避免為小值進行配置,進一步提升效能。
人體工學
這項 RFC 允許繫結避免為小值分配空間,但並未規定必須這麼做。如果繫結有所變更,處理這些型別的 API 可能會與處理其他需要分配空間型別的 API 不同。這種不一致性可能會導致人體工學設計不良,因此請務必避免。
回溯相容性
這項變更所需的遷移作業會破壞 ABI 相容性。
不過,變更生效後,類型變更不會影響 ABI 相容性。所有 <= 4 位元組型別都不保證在變更前後的型別變更具有 ABI 相容性。
這項變更「可能」會破壞來源相容性。RFC 並未要求進行來源相容性重大變更,但繫結「可能」會選擇進行來源相容性重大變更,以提升繫結效能或其他原因。
安全性考量
這不會影響安全性。
隱私權注意事項
這不會影響隱私權。
測試
我們會使用多種策略測試這項變更:
- 每個繫結中的自訂單元測試。
- GIDL 合規套件。
- FIDL 相容性測試。
說明文件
線路格式說明文件需要更新。
API 評量表必須記錄效能取捨,以利做出欄位大小決策。
缺點、替代方案和未知事項
缺點
這項提案的主要缺點是複雜度提高。現在有兩種值表示法,分別是內嵌和非內嵌,視類型而定,而切換行為的 4 位元組門檻可能會令人意外。
替代方案:8 位元組的內嵌值
這項 RFC 建議內嵌 4 位元組以下的值。這是因為系統似乎無法內嵌 8 位元組的值,至少在搭配有效率的封包實作時是如此。
這是因為繫結必須支援不明信封。收到不明信封時,系統不會知道類型資訊。因此,系統無法判斷是否指向行外物件,這會改變解碼器的行為。因此,值本身必須包含一些資訊,指出是否為行內或行外格式。
如果封包大小為 8 個位元組,而內嵌的值也是 8 個位元組,則無論值是內嵌或非內嵌格式,都沒有可儲存的備用位元。
因此,8 位元組內嵌值與有效率的信封不相容。您必須選擇不使用有效率的信封,或是減少可內嵌的值大小。由於這個方向最有可能大幅提升效能,因此這項 RFC 選擇了後者。
既有技術和參考資料
RFC-0113 導入了有效率的封包,這些封包是本 RFC 中所用封包結構的基礎。