RFC-0010:zx_channel_iovec_t 支援 zx_channel_write 和 zx_channel_call

RFC-0010:zx_channel_write 和 zx_channel_call 支援 zx_channel_iovec_t
狀態已接受
領域
  • 核心
說明

這個 RFC 針對 zx_channel_write 和 zx_channel_call 導入一個新模式,會從多個記憶體區域複製輸入資料,而非從單一連續緩衝區中複製輸入資料。

問題
毛皮變化
  • 433621
作者
審查人員
提交日期 (年-月-日)2020-09-25
審查日期 (年-月-日)2020-10-06

摘要

這個 RFC 為 zx_channel_writezx_channel_write_etc、 複製輸入資料的來源 zx_channel_callzx_channel_call_etc 多個記憶體區域,而不是單一連續緩衝區。這個 允許簡訊資料 直接從多個 userspace 物件複製而來 包括處理、複製和版面配置步驟方法是更新現有的 系統呼叫以擷取 zx_channel_iovec_t 記憶體區域描述元陣列 當已指定選項時

提振精神

這個提案的主要動機是成效。

如為非線性化的網域物件,目前必須 (1) 分配 FIDL 繫結 緩衝區,以及 (2) 在標準版面配置中將物件複製到緩衝區中。之後 就會再次將緩衝區複製到核心中zx_channel_iovec_t允許 以便直接將物件複製到核心中以及 FIDL 訊息 資料再按照標準順序排列,只有 zx_channel_iovec_t 陣列必須反映所需順序。

設計

zx_channel_write 目前的簽名如下:

zx_status_t zx_channel_write(zx_handle_t handle,
                             uint32_t options,
                             const void* bytes,
                             uint32_t num_bytes,
                             const zx_handle_t* handles,
                             uint32_t num_handles);

輸入資料是 bytes 指向的連續位元組陣列。 zx_channel_write_etczx_channel_callzx_channel_call_etc後來 都是類似陣列事實上,這些陣列必須是連續的 同時免除不必要的負擔特別是針對含有外部元件的 FIDL 訊息, FIDL 編碼器必須分配一個緩衝區,並將資料移到合適的位置 。

zx_channel_iovec_t 提供替代路徑。zx_channel_write, zx_channel_write_etczx_channel_callzx_channel_call_etc 而是接收物件的位置和大小清單 複製作業會在核心內進行,避免發生額外的重複情形, 分配速度。

在 C++ 中定義 zx_channel_iovec_t 如下:

typedef struct zx_channel_iovec {
  void* buffer;            // User-space bytes.
  uint32_t capacity;       // Number of bytes.
  uint32_t reserved;       // Reserved.
} zx_channel_iovec_t;

每個 zx_channel_iovec_t 都會指向接下來要複製的 capacity 個位元組 buffer 傳送至核心訊息緩衝區。「reserved」必須指派給零。 只有在 capacity 為 0 時,buffer 欄位才會是空值。buffer 分 不能在多個 zx_channel_iovec_t 中重複

zx_channel_writezx_channel_write_etczx_channel_call 的簽名 或 zx_channel_call_etc 維持不變。不過,如果使用者指定 設為這些系統呼叫的 ZX_CHANNEL_WRITE_USE_IOVEC 選項,void* bytes 引數會被解譯為 zx_channel_iovec_t*。同樣地, 系統會將 num_bytes 引數解讀為 zx_channel_iovec_t 的數目 。

請注意,處理常式陣列的類型 (zx_handle_tzx_handle_disposition_t) 不相關,因為只有 bytes 陣列是 已變更。

zx_channel_iovec_t 陣列描述的訊息,且要傳送 否則無法在 全部。呼叫端無法再使用提供給 syscall 的帳號 也會對失敗和失敗情形發出請求

錯誤狀況

這些是 zx_channel_writezx_channel_write_etczx_channel_callzx_channel_call_etc 含有更新檔,因為 以及 Ivecs 介紹

ZX_ERR_OUT_OF_RANGE num_bytesnum_handles 大於 ZX_CHANNEL_MAX_MSG_BYTESZX_CHANNEL_MAX_MSG_HANDLES。 如果已指定 ZX_CHANNEL_WRITE_USE_IOVEC 選項, 如果 num_bytes 大於,就會產生 ZX_ERR_OUT_OF_RANGE ZX_CHANNEL_MAX_MSG_IOVEC 或生物容量的總和超過 ZX_CHANNEL_MAX_MSG_BYTES

ZX_ERR_INVALID_ARGS bytes 是無效的指標,handles 是無效的指標,或 options 包含無效的選項位元。 如果已指定 ZX_CHANNEL_WRITE_USE_IOVEC 選項, 如果 buffer 欄位包含無效的指標,則為 ZX_ERR_INVALID_ARGS

對齊

指定的位元組沒有對齊限制 zx_channel_iovec_t。每個 zx_channel_iovec_t 都會在沒有邊框間距的情況下複製。

限制

現有限制的位元組數 (65536) 和帳號代碼 (64) 則訊息未變更請注意,這些限制適用於郵件,而非 zx_channel_iovec_t 個項目。

zx_channel_iovec_t 數量將限制為每個系統呼叫 8192。這個 數字來自對齊的 8 位元組內嵌 + 行中物件數 可容納 65536 位元組訊息,且每個內嵌 + 行出物件 可能使用了 zx_channel_iovec_t 項目。

實作

Syscall

  • 加入設計一節中定義的 zx_channel_iovec_t 類型。
  • 新增「ZX_CHANNEL_WRITE_USE_IOVEC
  • 顯示的 syscall 介面沒有變更 (zx_channel_iovec_t 陣列) 會傳入現有的 bytes 參數。

核心

收到 ZX_CHANNEL_WRITE_USE_IOVEC 選項後,核心將:

  • zx_channel_iovec_t 物件指向的資料複製到訊息 緩衝區。雖然複製作業通常會依序執行 zx_channel_iovec_t輸入的值,請自行選用。不過, 訊息必須按照 zx_channel_iovec_t 項目的順序排列。
  • 將訊息寫入該管道。

FIDL

這是針對執行系統呼叫的系統呼叫變更提案 發生在核心內,且 FIDL 繫結變更的細節 超出範圍不過,為了方便評估這個提案 請務必瞭解這對 FIDL 編碼的影響。

FIDL 繫結可選擇使用 zx_channel_iovec_t 支援, 新增對將 FIDL 物件編碼至 zx_channel_iovec_t 陣列的支援功能。

這個編碼路徑和現有的編碼路徑 zx_channel_iovec_t 可讓核心就地複製物件。主要 小工具就是使用指標採用 FIDL 編碼的訊息需要 已傳送至核心,並以 PRESENTABSENT 標記取代指標 輕鬆分配獎金但在許多情況下,物件仍需要 系統呼叫後的原始指標值,讓解構函式 物件。

這表示使用 zx_channel_iovec_t 的繫結會 有時候需要多做筆記,確保在物件內 正確清理資料

遷移

由於此功能採用的是預設停用選項,因此 並不會立即影響到現有使用者。來電網站可遷移至 請視需要使用這個選項

實際上,我們的目標是遷移可因應 享有 zx_channel_iovec_t 的好處。這個數量應會減少 這對 FIDL 使用者的影響

成效

實作原型並已完成基準測試。

這個原型在核心端導入了 zx_channel_write 選項 和有限的 FIDL 支援 (僅限內嵌物件和向量)。 郵件標頭,以及每個內嵌和離線物件 有 zx_channel_iovec_t 個項目。 使用包含 64 個項目的陣列,將 zx_channel_iovec_t 儲存在 核心和 FIDL 編碼

這些測量數據來自使用 Intel Core i5-7300U CPU (2.60GHz) 的機器。

位元組向量事件基準 (zx_channel_write、zx_channel_wait_async 和 zx_channel_read) 的轉換率有顯著的成長:

  • 4096 位元組向量:9398 ns ->4,495 奈秒
  • 256 位元組向量:8788 ns ->3794 奈秒

FIDL 編碼也展現了效能改善。

將位元組向量範例的時間編碼:

  • 4096 位元組向量:345 ns ->88 奈秒
  • 256 位元組向量:251 ns ->86 奈秒

Inline 物件也會顯示少量編碼的改善:

  • 有 256 uint8 欄位的結構:67 ns ->49 奈秒

安全性考量

由於這是現有系統呼叫的重大變更, 導入作業前必須先接受安全性審查。

隱私權注意事項

這不會對隱私權造成任何影響。

測試

每個變更圖層都會新增單元和整合測試。

但不打算加入裝置或系統層級的端對端測試,但 現有的測試涵蓋範圍有助於確保不會發生未預期的錯誤 以及遷移作業的間隔後

說明文件

系統呼叫說明文件需要更新,表示支援這項功能 而不是每個特徵的分數

無需變更整個架構的說明文件。

缺點、替代方案和未知

此提案的主要缺點是需要支援而變得更加複雜 核心中的選項,以及 FIDL 繫結的實際較為複雜性 使用 ZX_CHANNEL_WRITE_USE_IOVEC 選項,需要確保 如果物件經過變更,方便就位複製完成,就會正確清理。

限制

引數的 zx_channel_iovec_t 數量下限有上限 比 8192 更接近 16。這樣一來, 要複製到核心堆疊的 zx_channel_iovec_t 陣列。不過, 會導致實作策略無法指派一個zx_channel_iovec_t 每個離線 FIDL 物件的項目。

實務上,直接轉換使用者空間可能成效較佳。 是大量的zx_channel_iovec_t,至少要避免輪班 加入核心不過,為了精簡起見,我們建議使用 8192 限制,直到 如果需要進一步修正

如果實作層級,上限較高, zx_channel_iovec_t 陣列無法完全填滿核心堆疊。堆疊 緩衝區可用於一般情況,但需要複製到 有足夠的項目時,就會增加大型 (且速度較慢) 緩衝區。

向量化控點

帳號代碼可能相當於 zx_channel_iovec_t、 或在現有 zx_channel_iovec_t 中連同位元組一起納入。不過 帳號代碼通常會有 小型。為求簡單,帳號代碼會保留在專用陣列中。

支援單一寫入多則訊息

此 RFC 的前一個版本包含支援多重參數的 訊息。zx_channel_write

考慮以下三項提案:

  • 平面表示法:將 reserved 欄位重新用於 zx_channel_iovec_t,包含兩個 uint16_t 欄位:message_seq (這些欄位 ,zx_channel_iovec_t 是訊息的一部分) 和 handle_count (號碼 buffer 中位元組耗用的控制代碼)。序號為 受限於單調且無間斷。這項限制可啟用 提升核心實作效能,但日後可以縮減 可以視需要使用這個方法與此 RFC 和多重訊息支援 加到現有結構中
  • 陣列表示法:表示郵件有外部陣列, 每個訊息都有指向內部 iovecs 陣列的指標。這類似於 通常更熟悉 Linux syscall sendmmsg 的結構 使用者。雖然陣列陣列的表示法 有證據顯示,由於 間接 (請參閱 CL)。
  • 標頭前置字元表示法:緩衝區以標頭開頭, 後面接著 iovec 陣列標頭包含 16 個訊息描述元 每個欄位都只包含 uint16_t message_size 欄位。這個欄位 判定與zx_channel_iovec_t 撰寫新的電子郵件訊息此示意圖提供了階層結構,但不含 就不需要進行額外的重新導向和複製

在設計討論中,平板代表的原因是 以及效能屬性和簡易度傳達一則有關多重訊息的完整提案 支援服務不在此 RFC 範圍內,請注意,此 RFC 相容 平面式表示法

iovec 專屬系統呼叫

您不必為現有的系統呼叫新增選項 zx_channel_write_ioveczx_channel_write_etc_ioveczx_channel_call_iovec 可以建立 zx_channel_call_etc_iovec 個系統呼叫不過,您也可以選擇 最好避免系統呼叫次數和認知負載增加 使用者。

zx_channel_read 中的 zx_channel_iovec_t 支援

此 RFC 提議支援 zx_channel_iovec_t 進行管道寫入,但不支援 管道讀取這個程序之所以能有利於 在寫入端執行 iovecs - 避免使用 FIDL 線性化步驟 讓使用者在閱讀方面能有明顯的好處

Rust 繫結可能受益於讀取端 iovec 支援 將緩衝區分成多個小型緩衝區,每個緩衝區都有自己的 擁有權。這有助於建立類似 LLCPP 的繫結變化版本 也就是將緩衝區轉換為輸出物件不過 或是變更 Rust 繫結的短期計畫,以這種方式運作 延遲新增對 iovec 的支援, 表示不需要。

既有藝術品和參考資料

Fuchsia 目前有 zx_stream_readvzx_stream_writev 系統呼叫, 請使用向量化 ioLinux 也提供類似的 readvwritev 系統 讀取及寫入檔案描述元的呼叫。