非同步追蹤

本指南說明如何在程式碼中加入非同步追蹤功能。

必要條件

開始之前,請確認您已完成下列事項:

此外,請務必在程式碼中使用相關的程式庫:

C

#include <lib/trace/event.h>

C++

#include <lib/trace/event.h>

荒漠油廠

use fuchsia_trace::{ArgValue, Scope, ...};

新增非同步追蹤

當作業橫跨多個執行緒時,系統會使用一組非同步追蹤函式。

舉例來說,在多執行緒伺服器中,要求會由一個執行緒處理,然後在作業進行期間放回佇列。過了一段時間後,另一個執行緒會收到作業已完成的通知,並「接手」處理該要求。非同步追蹤的目標是讓這些不連續的追蹤事件產生關聯。

非同步追蹤會考量到相同的程式碼路徑會用於多個不同的處理流程。在先前的範例中,我們想瞭解特定函式執行的時間長度,或特定值在特定時間點的值。使用非同步追蹤功能時,我們會追蹤相同的資料,但會以邏輯處理流程為準,而非以程式位置為準的流程。

在佇列處理範例中,接收要求的程式碼會為每個要求加上「Nonce」標記,這是隨附於要求的專屬值。這個 Nonce 可透過 TRACE_NONCE() 產生,後者只會遞增全域計數器。

讓我們來看看運作方式。首先,您需要宣告一個可儲存 Nonce 的位置。這通常位於要求本身的結構體中:

typedef struct {
...
    // add the nonce to your context structure
    trace_async_id_t async_id;
} my_request_context_t;

收到要求後,您會擷取 Nonce,並開始非同步追蹤流程:

// a new request; start asynchronous tracing
ctx->async_id = TRACE_NONCE();
TRACE_ASYNC_BEGIN("category", "name", ctx->async_id, "key", TA_STRING("value"));

您可以使用 TRACE_ASYNC_INSTANT() 巨集定期記錄追蹤事件 (類似於我們在上述 TRACE_INSTANT() 巨集中所做的操作):

TRACE_ASYNC_INSTANT("category", "name", ctx->async_id, "state", TA_STRING("phase2"));

並透過 TRACE_ASYNC_END() 清理:

TRACE_ASYNC_END("category", "name", ctx->async_id);

請勿將這裡的「async」用法與程序中執行的非同步迴圈混淆,兩者並無關聯。

流程追蹤

非同步追蹤功能適用於同一個程序內的追蹤,但可能會透過不同的執行緒進行。

有一種稱為「流程」追蹤的較高層級追蹤機制,可用於處理程序或抽象層之間。

您可以呼叫 TRACE_FLOW_BEGIN() 來標示「流程」的開始。就像 TRACE_ASYNC_BEGIN() 一樣,您可以傳入 Nonce 來識別這個特定流程。流量 ID 為未經簽署的 64 位元整數。

接著,您可以 (選用) 呼叫 TRACE_FLOW_STEP(),指出該資料流中的追蹤作業。

完成後,請使用 TRACE_FLOW_END() 結束流程。

舉例來說,您可以在用戶端和伺服器之間使用流程,追蹤從用戶端到伺服器,再回到用戶端的端對端要求。