异步跟踪

本指南介绍了如何向代码添加异步跟踪。

前提条件

在开始之前,请确保您已完成以下操作:

此外,请确保在代码中使用相关库:

C

#include <lib/trace/event.h>

C++

#include <lib/trace/event.h>

Rust

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”用法与进程中运行的 async 循环混淆;它们并不相关。

流程跟踪

异步跟踪旨在在同一进程内进行跟踪,但可能通过不同的线程进行跟踪。

有一种更高级别的跟踪机制,称为“流程”跟踪,旨在用于进程或抽象层之间。

您可以调用 TRACE_FLOW_BEGIN() 来标记“流程”的开始。 与 TRACE_ASYNC_BEGIN() 一样,您需要传入一个 nonce 来标识此特定流程。流程 ID 是一个无符号 64 位整数。

然后,您可以(选择性地)调用 TRACE_FLOW_STEP() 来指示该流程中的跟踪操作。

完成后,您可以使用 TRACE_FLOW_END() 结束流程。

例如,流程可用于客户端和服务器之间,以跟踪从客户端到服务器再返回到客户端的端到端请求。