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 會引入高效率的封套。

下列類型將採用新的內嵌值格式:

  • 布林值
  • float32
  • uint8、uint16、uint32
  • int8、int16、int32
  • 版面配置為 uint8、uint16、uint32、int8、int16、int32 的列舉
  • 位元,版面配置為 uint8、uint16、uint32、int8、int16、int32
  • handle、client_end、server_end
  • 結構體大小小於 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 個位元組的值則必須使用離線表示法。收到錯誤表示法的值時,必須觸發解碼錯誤。缺少的信封會繼續使用零信封表示法,也就是說,這些信封一律會以離線表示法表示。

實作

這項變更需要複雜的遷移作業。不過,這項遷移作業可與其他電報格式遷移作業結合,實際上可降低成本。

成效

當欄位內嵌時 (CL),LLCPP 的編碼時間會大幅縮短:

設定所有欄位後的編碼時間 (以奈秒為單位):

# 欄位 使用前 使用後
1 178 毫秒 147 奈秒
16 720 毫秒 325 毫秒
256 9396 秒 2909 毫秒

這張圖表顯示編碼時間與資料表欄數的關係。資料表中的所有欄位都已設定。

我們並未測量解碼時間,但由於解碼演算法會遵循與編碼相似的一系列步驟,因此也預期會大幅改善。

此外,在某些情況下,繫結可避免為小值進行配置,進而進一步提升效能。

人體工學

這份 RFC 允許繫結避免為小值進行配置,但並未規定必須如此。如果繫結確實有所變更,用於處理這些類型的 API 可能會與用於處理需要配置的其他類型的 API 不同。這種不一致性可能會導致人體工學變差,因此必須小心避免。

回溯相容性

這項變更所需的遷移作業會破壞 ABI 相容性。

不過,一旦變更生效,就不會影響類型變更的 ABI 相容性。所有 <= 4 位元組類型都無法保證在變更前後,類型變更的 ABI 相容性。

這項變更可能會導致來源不相容。RFC 並未要求進行任何破壞原始碼相容性的變更,但繫結可能會選擇進行破壞原始碼相容性的變更,以改善繫結效能或出於其他原因。

安全性考量

這不會影響安全性。

隱私權注意事項

這不會影響隱私權。

測試

我們會使用多種策略來測試變更:

  • 每個繫結中的自訂單元測試。
  • GIDL 合規套件。
  • FIDL 相容性測試。

說明文件

需要更新線路格式說明文件。

您必須在 API 評分標準中記錄效能取捨,以便做出欄位大小的決定。

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

缺點

這項提案的主要缺點是複雜度增加。目前有兩種值表示法,分別是內嵌和離線,取決於類型。您可能會訝異,切換行為有 4 個位元組的門檻。

替代做法:8 位元組內嵌值

這份 RFC 建議內嵌 4 個位元組以下的值。原因是,至少在與高效率信封搭配實作時,似乎無法內嵌 8 個位元組的值。

這是因為繫結項必須支援不明信封。不明信封抵達時,系統不會提供任何類型資訊。因此,我們無法得知該物件是否指向離線物件,而這會影響解碼器的行為。因此,值本身必須包含一些資訊,指出其是否以內嵌或離線格式結構化。

如果信封大小為 8 個位元組,而內嵌的值為 8 個位元組,如果值採用內嵌或離線格式,就沒有可儲存的備用位元。

因此,8 個位元組的內嵌值與高效信封不相容。您必須做出選擇,要嘛不使用效率高的封套,要嘛減少可內嵌的值大小。這份 RFC 選擇了後者,因為這個方向似乎最有可能帶來最顯著的效能改善。

既有技術與參考資料

RFC-0113 介紹了高效率的封套,這也是本 RFC 中所用封套結構的基礎。