分頁數量上限

本文件說明在元素加入向量時,計算位元組大小和處理點大小的最佳方法。使用此方法時,為了盡可能提高一次可批次處理的元素數量,同時滿足管道寫入的核心上限。

摘要

為了透過管道最大化處理量,常見的做法是使用分頁 API 將大型回應當做多個元素向量進行批次處理。由於通道的上限是 64,000 個位元組和 64 個處理常式,因此您必須思考向量中有多少元素能批次處理最大容量 (但不超過位元組大小和處理次數門檻)。

以下金鑰的參考文件為 FIDL 傳輸格式規格。

以下各種範例將說明最大化分頁的最佳方式:

藍牙「WatchPeers」方法

假設 fuchsia.bluetooth.sys.Access 通訊協定的 WatchPeers 方法定義如下:

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 欄位的定義減少為 struct{uint8; array<uint8>:6},因此也是 8 個位元組。string 欄位是位元組向量 (例如 sizeof(fidl_vector_t) + len(name)),且會填充到最接近的 8 個位元組邊界。

顯示的 Enqueue 方法

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

Enqueue(vector<Command>:MAX cmds);

要求或回應的前面會加上標頭,即固定的 16 位元組或來自 zircon/fidl.hsizeof(fidl_message_header_t)。然後,向量有 16 個位元組的標頭 sizeof(fidl_vector_t),後面接著向量內容,也就是實際指令。因此在考量每個指令的大小之前,系統會先有 32 個位元組的固定大小。

指令是一種聯集,包含 24 個位元組的標頭 (即 sizeof(fidl_xunion_t)),後面接著內容 (已對齊 8 個位元組)。

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

風景優美指令的 input 變化版本本身是聯集,這會新增另一個 24 個位元組標頭,然後是該聯集的內容,例如 SendPointerInputCmd 類型的 send_pointer_input

以下提供 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 預設都是 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 個位元組。