本文件說明在元素加入向量時,計算位元組大小和處理點大小的最佳方法。使用此方法時,為了盡可能提高一次可批次處理的元素數量,同時滿足管道寫入的核心上限。
摘要
為了透過管道最大化處理量,常見的做法是使用分頁 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.PeerId
是 struct{uint64}
(在這裡定義),因此是固定的 8 個位元組,因此 removed
向量內容便是元素數量 * 8 個位元組。
接著,我們需要估算 Peer
的大小,也就是定義為資料表。資料表基本上是「信封向量」,其中每個信封會指向欄位內容。估算大小必須在兩個步驟中完成:
- 判斷使用的最大欄位序數 (又稱
max_set_ordinal
) - 判斷每個顯示欄位的大小
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.h 的 sizeof(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
};
這兩個列舉的 PointerEventType
和 PointerEventPhase
預設都是 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 個位元組。