將 Fuchsia 元件做為追蹤供應器進行檢測時,您可以建立及觀察各種事件類型。本文件將說明事件類型之間的差異、每種事件類型的最佳用途、如何在元件中使用事件,以及在追蹤事件中可使用的各種引數。
活動
Fuchsia 事件類型可以是下列任一類型:
- 即時事件:標示具有名稱、類別和選用引數的時間點。
- 持續時間事件會標示兩個時間點,可包含名稱、類別和選用的引數。
- 計數器事件:擷取數值樣本,這些樣本通常會在 Perfetto 中以堆疊面積圖的形式呈現。
- 資料流事件:說明執行緒和程序之間的流程移交。
- 非同步事件:可指定
id
,將不同執行緒的事件連結在一起,並將這些事件放置在單一軌道上。
追蹤事件最基本的形式,包含類別 (第一個參數) 和名稱 (第二個參數)。
追蹤記錄事件最多可接受 15 個引數。
使用追蹤事件時,請務必瞭解類別的運作方式。以下是與類別相關的幾個重要概念:
- 您可以使用類別將事件分組,以便一起啟用或停用。
- 類別通常是
[A-Za-z-_:]+
的短 ASCII 字串文字常值,例如gfx
或audio
。 - 類別為全域性質。建議您為這些元件設定命名空間。
- 系統預設不會啟用類別。如果您新增類別,請務必在使用
--categories #default,your_category
擷取追蹤記錄時指定該類別。 ffx trace
支援前置字串比對。如果您執行ffx trace start --categories your_component::*
,系統會啟用your_component::category1
、your_component::category2
和任何其他相關類別。
使用事件時,請務必在程式碼中加入相關程式庫:
{C}
#include <lib/trace/event.h>
C++
#include <lib/trace/event.h>
荒漠油廠
use fuchsia_trace::{ArgValue, Scope, ...};
您也可以參考 C++ 中簡單範例,瞭解如何使用追蹤提供者。
即時事件
這是最基本的事件。即時事件可標示具有名稱、類別和選用引數的時間點。
您可以選擇註冊類別,但大多數追蹤供應商都不會這麼做。
即時追蹤記錄至少會包含名稱和類別,以便區分:
{C}
TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD);
C++
TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD);
荒漠油廠
instant!(c"trace_category", c"trace_name", Scope::Thread);
您也可以建立包含其他引數的即時事件:
{C}
TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD, argument_1, argument_1_value, argument_2, "argument_2_string");
C++
TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD, argument_1, argument_1_value, argument_2, "argument_2_string");
荒漠油廠
instant!(c"trace_category", c"trace_name", Scope::Thread, argument_1 => argument_1_value, argument_2 => "argument_2_string");
在 Perfetto 中,即時事件會以小箭頭表示,如這張螢幕截圖所示。
時間長度事件
時間長度事件會標示兩個時間點,並可包含名稱、類別和選用引數。時間長度事件也可以在其他時間長度事件中巢狀,並堆疊在彼此之上。
時間長度追蹤記錄至少會包含名稱和類別,以便區分:
{C}
TRACE_DURATION_BEGIN("trace_category", "trace_name"); // Do some work TRACE_DURATION_END("trace_category", "trace_name");
C++
TRACE_DURATION_BEGIN("trace_category", "trace_name");
// Do some work
TRACE_DURATION_END("trace_category", "trace_name");
荒漠油廠
duration_begin!(c"trace_category", c"trace_name");
// Do some work
duration_end!(c"trace_category", c"trace_name");
或者,您也可以定義一段時間長度事件,並在該事件超出範圍時,使用 RAII (Resource acquisition is initialization) 自動關閉該事件,如下所示:
{C}
{ TRACE_DURATION("trace_category", "trace_duration_raii"); // Do some work TRACE_DURATION(c"trace_category", c"nested_duration", "argument_3", argument_3_value, "argument_4", argument_4_string); // nested_duration closes due to RAII // trace_duration_raii closes due to RAII }
C++
{
TRACE_DURATION("trace_category", "trace_duration_raii");
// Do some work
TRACE_DURATION(c"trace_category", c"nested_duration", "argument_3", argument_3_value, "argument_4", argument_4_string);
// nested_duration closes due to RAII
// trace_duration_raii closes due to RAII
}
荒漠油廠
{
duration!(c"trace_category", c"trace_duration_raii");
// Do some work
duration!(c"trace_category", c"nested_duration", argument_3 => argument_3_value, argument_4 => argument_4_string);
// nested_duration closes due to RAII
// trace_duration_raii closes due to RAII
}
在 Perfetto 中,巢狀的時間長度堆疊如下所示:
計數器事件
計數器事件會擷取數值樣本,這些樣本通常會在 Perfetto 中以堆疊面積圖呈現。使用計數器事件時,您可以使用 id
來區分系統程序中具有相同類別和名稱的多個計數器例項。您可以將 1 到 15 個數值引數與事件建立關聯,每個引數都會解讀為不同的時間序列。
以下範例顯示 counter_id
值和傳遞至計數器事件的資料序列:
{C}
trace_counter_id_t counter_id = 555; uint32_t data = get_some_data(); TRACE_COUNTER("trace_category", "trace_name", counter_id, "data_series", data);
C++
trace_counter_id_t counter_id = 555;
uint32_t data = get_some_data();
TRACE_COUNTER("trace_category", "trace_name", counter_id, "data_series", data);
荒漠油廠
let counter_id = 555;
let data = get_some_data();
counter!("trace_category", "trace_name", counter_id, "data_series" => data);
在 Perfetto 中,計數器事件如下所示:
Flow 事件
流程事件會說明執行緒之間和跨處理程序的流程移交作業。這些事件必須包含在代表流程移交位置的時間長度事件中。每個流程事件也可能會附加引數。資料流開始 (TRACE_FLOW_BEGIN
或 flow_begin
) 事件之後,可能會發生流程步驟 (TRACE_FLOW_STEP
或 flow_step
) 事件。
例如:
{C}
trace_flow_id_t flow_id = 555; TRACE_FLOW_BEGIN("trace_category", "trace_flow_name", flow_id, "argument_1", argument_1_value); TRACE_FLOW_STEP("trace_category", "trace_flow_step_name", flow_id); TRACE_FLOW_END("trace_category", "trace_flow_name", flow_id);
C++
trace_flow_id_t flow_id = 555;
TRACE_FLOW_BEGIN("trace_category", "trace_flow_name", flow_id, "argument_1", argument_1_value);
TRACE_FLOW_STEP("trace_category", "trace_flow_step_name", flow_id);
TRACE_FLOW_END("trace_category", "trace_flow_name", flow_id);
荒漠油廠
let flow_id = 555;
flow_begin!(c"trace_category", c"trace_flow_name", flow_id, "argument_1" => argument_1_value);
flow_step!(c"trace_category", c"trace_flow_step_name", flow_id);
flow_end!(c"trace_category", c"trace_flow_name", flow_id);
在 Perfetto 中,流程事件會以箭頭表示,例如:
非同步事件
在追蹤記錄中,即時和持續時間事件會放置在產生這些事件的執行緒軌上。使用多執行緒非同步或以執行緒集區為基礎的程式碼時,事件可能會在不同的執行緒上啟動及完成。非同步事件可讓您指定 id
,連結不同執行緒的事件,並將這些事件放在單一軌道上。
非同步開始 (TRACE_ASYNC_BEGIN
或 async_begin
) 事件可能會接續非同步即時 (TRACE_ASYNC_INSTANT
或 async_instant
) 事件,且必須與具有相同類別、名稱和 id
的非同步結束 (TRACE_ASYNC_END
或 async_end
) 事件相符。
非同步事件是指以非同步方式進行,且可能橫跨多個執行緒的工作。id
可協助將不同非同步作業的進度關聯起來,這些作業在同一個程序中具有相同的類別和名稱。同一個程序中具有相符類別和 ID 的非同步事件會彼此巢狀。
您可以將 0 到 15 個引數與非同步事件建立關聯,每個引數都會用於為非同步作業加上額外資訊的註解。您提供給相符的非同步開始、非同步即時和非同步結束事件的引數會在追蹤記錄中合併,因此不必重複提供。
{C}
trace_async_id_t async_id = 555; TRACE_ASYNC_BEGIN("trace_category", "trace_async_name", async_id, "argument_1", argument_1_value); TRACE_ASYNC_INSTANT("trace_category", "trace_async_instant_name", async_id); TRACE_ASYNC_END("trace_category", "trace_async_name", async_id);
C++
trace_async_id_t async_id = 555;
TRACE_ASYNC_BEGIN("trace_category", "trace_async_name", async_id, "argument_1", argument_1_value);
TRACE_ASYNC_INSTANT("trace_category", "trace_async_instant_name", async_id);
TRACE_ASYNC_END("trace_category", "trace_async_name", async_id);
荒漠油廠
let async_id = 555;
async_begin!(c"trace_category", c"trace_async_name", async_id, "argument_1" => argument_1_value);
async_instant!(c"trace_category", c"trace_async_instant_name", async_id);
async_end!(c"trace_category", c"trace_async_name", async_id);
在 Perfetto 中,非同步事件會放置在其專屬的命名軌跡上,而不會放置在事件發出的執行緒軌跡上。非同步事件如下所示:
引數
您可以在 Fuchsia 追蹤記錄中使用下列類型的事件:
- 空值引數
- 數值類型
- 字串類型
- 指標
- KOID
- 布林值
空值引數
空值引數只是名稱,沒有資料。
例如:
{C}
TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD, "SomeNullArg", TA_NULL());
C++
TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD, "SomeNullArg", nullptr);
荒漠油廠
instant!(c"trace_category", c"trace_name", Scope::Thread, c"SomeNullArg" => ());
數值類型
數字類型是任何 int
或 float
資料類型。
例如:
{C}
// Standard int types TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD, "Someuint32", TA_UINT32(2145)); TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD, "Someuint64", TA_UINT64(423621626134123415)); TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD, "Someint32", TA_INT32(-7)); TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD, "Someint64", TA_INT64(-234516543631231)); // Doubles TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD, "Somedouble", TA_DOUBLE(3.1415));
C++
// Standard int types
TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD, "Someuint32", 2145);
TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD, "Someuint64", 423621626134123415);
TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD, "Someint32", -7);
TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD, "Someint64", -234516543631231);
// Doubles
TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD, "Somedouble", 3.1415);
荒漠油廠
// Standard int types
instant!(c"trace_category", c"trace_name", Scope::Thread, c"Someuint32" => 2145);
instant!(c"trace_category", c"trace_name", Scope::Thread, c"Someuint64" => 423621626134123415);
instant!(c"trace_category", c"trace_name", Scope::Thread, c"Someint32" => -7);
instant!(c"trace_category", c"trace_name", Scope::Thread, c"Someint64" => -234516543631231);
// Doubles
instant!(c"trace_category", c"trace_name", Scope::Thread, c"Somedouble" => 3.1415);
字串類型
字串類型可以是任何 string
資料類型。
例如:
{C}
TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD, "ping", "pong");
C++
TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD, "ping", "pong");
荒漠油廠
instant!(c"trace_category", c"trace_name", Scope::Thread, "ping" => "pong");
指標
在 Perfetto 檢視器中,指標的格式為十六進位。當類型推論會解析為錯誤的資料類型時,您也可以明確指定追蹤引數類型。
例如:
{C}
TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD, "somepointer", &i, "someotherpointer", &i, TA_POINTER(0xABCD));
C++
TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD, "somepointer", &i, "someotherpointer", &i, 0xABCD);
荒漠油廠
let x: u64 = 123;
instant!(c"trace_category", c"trace_name", Scope::Thread, "SomeOtherPointer" => &x as *const u64);
KOID
KOID 是核心物件的 ID,並具有自己的資料類型,可與一般 u64
資料類型區分開。
例如:
{C}
TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD, "somekoid", TA_KOID(0x0012));
C++
TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD, "somekoid", TA_KOID(0x0012));
荒漠油廠
let koid: zx::Koid = vmo.get_koid()?;
instant!(c"trace_category", c"trace_name", Scope::Thread, "somekoid" => koid);
布林值
布林值會顯示為 true
或 false
。
例如:
{C}
TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD, "somebool", TA_BOOL(true)); TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD, "someotherbool", TA_BOOL(false));
C++
TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD, "somebool", true);
TRACE_INSTANT("trace_category", "trace_name", TRACE_SCOPE_THREAD, "someotherbool", false);
荒漠油廠
instant!(c"trace_category", c"trace_name", Scope::Thread, "somebool" => true);
instant!(c"trace_category", c"trace_name", Scope::Thread, "someotherbool" => false);