非同步追蹤

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

必要條件

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

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

C

#include <lib/trace/event.h>

C++

#include <lib/trace/event.h>

荒漠油廠

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

新增非同步追蹤

如果作業橫跨多個執行緒,就會使用一組非同步追蹤函式。

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

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

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

讓我們看看運作方式。 首先,請宣告要保留隨機值的空間。這通常位於要求本身的內容結構中:

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

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

// 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() 相同,您會傳遞隨機值來識別這個特定流程。流程 ID 是不帶正負號的 64 位元整數。

然後,您可以選擇呼叫 TRACE_FLOW_STEP(),指出該流程中的追蹤作業。

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

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