RFC-0114:在 FIDL 信封內內嵌小型值

RFC-0114:在 FIDL 信封中內嵌小值
狀態已接受
區域
  • 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;
}

線路表示法 InlinedValueEnvelopeOutOfLineWireEnvelope 都有重疊的 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 中所用封包結構的基礎。