| RFC-0035:自动流程跟踪 | |
|---|---|
| 状态 | 已拒绝 |
| 区域 |
|
| 说明 | 通过向 FIDL 绑定添加跟踪事件,我们可以在 Fuchsia 上实现跨进程的端到端流程,而无需手动滚动自定义 ID。 |
| 作者 | |
| 提交日期(年-月-日) | 2019-02-28 |
| 审核日期(年-月-日) | 2019-02-28 |
拒绝理由
没有响应的消息(无论是事件还是 fire-and-forget 调用)的交易 ID 设置为 0,因此无法使用建议的方案进行区分。
有些用途利用了 zx_channel_call(),该函数会在内核中分配交易 ID,并等待回复。 (此模式允许并发调用方依赖于内核同步,从而避免使用用户空间锁进行交易 ID 分配。) 同样,所提出的方案也无法区分这些情况。
预计内核跟踪支持会提供此审核所需的遥测数据,并且倾向于改进此机制,而不是在 FIDL 绑定中推送此数据。
最后,在 SDK 依赖项优先级顺序中,使用 FIDL 和 FIDL 绑定非常接近顶部,这是因为 FIDL 在 Fuchsia 上得到广泛使用。因此,在绑定中包含遥测数据和指标会使此类问题上升到该级别,而这是我们不希望看到的。可以设想一些构建和选择启用技巧,这些技巧需要纳入未来的提案中。
摘要
通过向 FIDL 绑定添加跟踪事件,我们可以在 Fuchsia 上跨进程实现端到端流程,而无需手动滚动自定义 ID。
设计初衷
有很多黑客技术可以在 Fuchsia 上跨进程边界启用流事件。 我们可以自动执行其中大部分操作,这样既不会使我们的 API 表面复杂化,也减少了手动工作量。
设计
Fuchsia FIDL 函数的标准属性,可向其各自生成的绑定添加流程开始/结束事件。
该属性用于设置轨迹记录的类别,并使用协议函数作为名称。 Fuchsia 上的跟踪目前仅支持一个类别,因此虽然该属性可能包含 N 个类别,但我们预计只会使用一个类别,并且会使用列表中的第一个类别。
protocol Example {
[Trace = "CATEGORY"]
ExampleFn(bool test) -> (bool status);
};
唯一的跨进程 ID 是指序号 ID、交易 ID(包含在每条消息中)和传输机制的 ID(对于 Zircon 渠道:发送进程渠道句柄的 koid 和接收进程句柄的相关 koid)与非加密哈希一起进行哈希处理。
通过 zx 通道的 FIDL 的稳定轨迹 ID 示例
我们建议组合使用以下几种标识符:
- FIDL 通道服务器端的 koid,可通过 zx_object_get_info() 获取,主题为
ZX_INFO_HANDLE_BASIC,使用服务器端的 koid 和客户端的相关 koid; - 交易型消息的方法序号(注意:这目前是一个 uint32 哈希值,很快将演变为 uint64 哈希值,请参阅 RFC-0029);
- 最后是事务性消息的事务性 ID。
这三个标识符的组装方式应尽可能减少可能出现的轨迹 ID 冲突,优先级如下:
- 两个具有相同序号的不同消息之间,以及同一客户端和服务器之间;
- 在两个具有不同序号的不同消息之间,以及在同一客户端和服务器之间;
- 两个不同的消息之间(具有不同的序号),以及不同的客户端和服务器之间。
目前,koid 分配大多是按顺序进行的。 因此,koid 的最低位将比最高位具有更多熵。 同样,交易 ID 是按顺序分配的,因此在最低位中提供更多熵。方法序号经过加密哈希处理,尽管最高位保留供系统使用,但可以安全地假设所有位都具有相同的熵。
因此,在当前条件下,合理的算法是使用 OR 运算符:
koid & OxFFFF << 48ordinal & 0xFFFFFFFF << 16transaction ID & 0xFF << 0
此外,系统还在 FIDL 绑定的接收端启动了轨迹时长。对于 C++/Rust 等语言,此操作通过 RAII 进行限定,并允许将该事件与另一个流程事件缝合在一起。
工效学设计
这使得我们的跟踪系统更易于使用,对于我们的基础设施来说也是一大优势。
文档和示例
应更新文档,以显示如何添加轨迹(如上所述)。
向后兼容性
此变更在 API 方面兼容,在 ABI 方面也兼容。
性能
当跟踪类别处于停用状态时,此操作会产生少量费用,在 dje@google.com 测试中(在 NUC 上)每项测试的费用不到 5 纳秒。我们还可以从 IR 中剥离跟踪注释,前提是需要更高的性能。
安全
无安全注意事项。
缺点、替代方案和未知因素
替代方案
内核轨迹机制
利用渠道读取和渠道写入时现有的 ktrace 流事件。
如果没有此功能,则可以尝试通过使用底层通道读取和写入上的现有 ktrace 流事件来实现此目的。 不过,这并不理想,因为这些渠道对于所有 FIDL 接口都是通用的,这意味着只能指定一个类别。这意味着,为了实际使用,用户必须启用通道读取和通道写入类别,这意味着所有通道读取和写入事件(而不仅仅是用于感兴趣的 FIDL 接口的事件)都会存在。 这会导致轨迹查看器输出难以读取,不必要地使用 ktrace 缓冲区,并且还依赖于 FIDL 实现细节。