分頁數量上限

本文件將說明計算大小的最佳方法,以及 將元素加入向量時,其中的位元組和處理方式。這應該是 以便一次最大化可批次處理的元素數量 同時滿足管道寫入核心上限

摘要

如要透過管道盡可能提高處理量,批次處理大量回應是常見的做法 分為多個向量,例如使用分頁技術 API。由於管道的上限是 64K 和 64, 還有幾個關於元素數量的問題 以在向量中批次調度以最大化容量 (但目前仍在 位元組大小和處理計數門檻)。

以下金鑰的參考文件為 FIDL 線 format 規格。

以下提供多個範例,說明最大化分頁範圍的最佳做法:

藍牙 WatchPeers 方法

請考慮使用 WatchPeers 方法, fuchsia.bluetooth.sys.Access 通訊協定,定義如下:

WatchPeers() -> (vector<Peer>:MAX updated, vector<bt.PeerId>:MAX removed);

首先,要求或回應的前面會加上標頭,例如固定的 16 個位元組 sizeof(fidl_message_header_t)這裡定義

每個向量都有 16 個位元組的標頭 sizeof(fidl_vector_t),後面接著 內容。

由於 bt.PeerIdstruct{uint64} (在此定義),因此是 因此 8 個位元組,removed 向量的內容則是 元素 * 8 個位元組

接下來,我們需要預估 Peer 的大小,定義為 資料表。表格基本上是信封向量, 每個信封皆指向欄位內容。估算時的大小必須 完成兩個步驟:

  1. 判斷使用的最大欄位序數 (即 max_set_ordinal)
  2. 判斷每個欄位的大小

Peer 的大小是表格標題,即 sizeof(fidl_table_t)、16 個位元組,再加上最大集合序數 * 信封標頭 (16 個位元組),即 max_set_ordinal * sizeof(fidl_envelope_t),加上 內容,也就是加入每個欄位的內容。

欄位的大小相對容易,有許多是基本或包裝函式 因此會產生 8 個位元組 (因填充所致)。bt.Address 欄位 同時也是 8 個位元組,因為該指標的定義會減少為 struct{uint8; array<uint8>:6}string 欄位是位元組向量,即 sizeof(fidl_vector_t) + len(name),並填補至最接近的 8 個位元組邊界。

風景優美的 Enqueue 方法

請考慮使用 fuchsia.scenic.Session 通訊協定,定義如下:

Enqueue(vector<Command>:MAX cmds);

要求或回應前方會加上標頭,例如固定的 16 個位元組 sizeof(fidl_message_header_t),來自 zircon/fidl.h。 接著,向量有一個 16 個位元組的標頭 sizeof(fidl_vector_t),後面接著 也就是實際的指令因此 考量到每個指令的大小,固定大小為 32 一個位元組

指令是具有 24 字元的聯集 位元組標頭 (即 sizeof(fidl_xunion_t)),後面接著內容,也就是 8 也就是位元組對齊

Command 聯集內容的大小取決於所選的變化版本。這個 範例使用 input 類型的變數 fuchsia.ui.input.Command

input 變體 (風景版指令) 本身是聯集,會新增 另一個 24 位元組標頭,後面接著該聯集的內容,例如 send_pointer_input 類型 SendPointerInputCmd

SendPointerInputCmd 的簡化定義以及轉換原則 以下是透過此結構連接的類型:

type SendPointerInputCmd = struct {
    compositor_id uint32;
    pointer_event PointerEvent;
};

type PointerEvent = struct {
    event_time uint64;
    device_id uint32;
    pointer_id uint32;
    type PointerEventType;
    phase PointerEventPhase;
    x float32;
    y float32;
    radius_major float32;
    radius_minor float32;
    buttons uint32;
};

type PointerEventType = flexible enum {
    // members elided
};

type PointerEventPhase = flexible enum {
    // members elided
};

兩者都列舉 PointerEventTypePointerEventPhase 「default」uint32 的基礎表示法。個人中心 能將 SendPointerInputCmd 的大小減少為結構:

struct {
    uint32;   // 4 bytes, total 4
              // 4 bytes (padding due to increase in alignment), total 8
    uint64;   // 8 bytes, total 16
    uint32;   // 4 bytes, total 20
    uint32;   // 4 bytes, total 24
    uint32;   // 4 bytes, total 28
    uint32;   // 4 bytes, total 32
    float32;  // 4 bytes, total 36
    float32;  // 4 bytes, total 40
    float32;  // 4 bytes, total 44
    float32;  // 4 bytes, total 48
    uint32;   // 4 bytes, total 52
};

因此,SendPointerInputCmd 結構的大小為 52 個位元組。如要 結構體大小計算的相關資訊,請參閱「遺失的結構圖 打包

現在,您已調整指令的所有部分的大小,接下來請新增總大小:

  • fuchsia.ui.scenic.Command 的標題:24 個位元組,例如 sizeof(fidl_xunion_t)
  • 變化版本「input」的內容:
    • fuchsia.ui.input.Command 的標題:24 個位元組,例如 sizeof(fidl_xunion_t)
    • 變化版本「set_hard_keyboard_delivery」的內容:
    • 結構 SendPointerInputCmd:52 個位元組
    • 對齊 8 個位元組的邊框間距:4 個位元組

因此總大小為 104 個位元組。