將 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", "example_duration");
// Do some work
TRACE_DURATION_END("trace_category", "example_duration");
C++
TRACE_DURATION_BEGIN("trace_category", "example_duration");
// Do some work
TRACE_DURATION_END("trace_category", "example_duration");
荒漠油廠
duration_begin!(c"trace_category", c"example_duration");
// Do some work
duration_end!(c"trace_category", c"example_duration");
或者,您也可以定義時間長度事件,並在超出範圍時使用 RAII (資源取得即初始化) 自動關閉,如下所示:
C
{
TRACE_DURATION("trace_category", "example_duration_raii");
// Do some work
TRACE_DURATION(c"trace_category", "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", "example_duration_raii");
// Do some work
TRACE_DURATION(c"trace_category", "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"example_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 中,計數器事件如下所示:
流程事件
流程事件說明執行緒之間和程序之間的流程交接。這些事件必須封裝在時間長度事件中,代表流程交接發生的位置。每個流程事件也可以附加引數。流程開始 (TRACE_FLOW_BEGIN 或 flow_begin) 事件之後,可能會接著發生流程步驟 (TRACE_FLOW_STEP 或 flow_step) 事件。
Perfetto 需要追蹤記錄中的全域流程事件 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);
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!(async_id, c"trace_category", c"trace_async_name", "argument_1" => argument_1_value);
async_instant!(async_id, c"trace_category", c"trace_async_instant_name");
async_end!(async_id, c"trace_category", c"trace_async_name");
在 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);