RFC-0035:自动流跟踪 | |
---|---|
状态 | 已拒绝 |
区域 |
|
说明 | 通过向我们的 FIDL 绑定添加跟踪事件,可以在 Fuchsia 上跨进程实现端到端流程,而无需手动创建自定义 ID。 |
作者 | |
提交日期(年-月-日) | 2019-02-28 |
审核日期(年-月-日) | 2019-02-28 |
拒绝理由
没有响应的消息(无论是事件还是火花式调用)的交易 ID 均设为 0,因此无法使用所提议的方案进行区分。
有些使用 zx_channel_call(),该函数会在内核中分配事务 ID,并等待回复。(这种模式允许并发调用方依赖于内核同步,从而避免为事务 ID 分配使用用户空间锁。) 同样,提议的方案无法区分这些情况。
内核跟踪支持预计会提供此审核所需的遥测功能,并且最好改进此机制,而不是在 FIDL 绑定中推送此机制。
最后,由于 Fuchsia 上广泛使用 FIDL,因此在 SDK 依赖项的优先级顺序中,使用 FIDL 和使用 FIDL 绑定非常接近顶部。因此,在绑定中添加遥测数据和指标会对该订单引发此类疑虑,而我们不希望出现这种情况。我们可以想象出一些 build 和选择接受的欺骗手段,这些手段需要在未来的提案中加以考虑。
摘要
通过向我们的 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),这些 ID 使用非加密哈希函数进行哈希处理。
通过 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 << 48
ordinal & 0xFFFFFFFF << 16
transaction ID & 0xFF << 0
系统还会在 FIDL 绑定的接收端启动轨迹时长。对于 C++/Rust 等语言,此操作使用 RAII 进行作用域限定,并允许将事件与其他流事件拼接。
工效学设计
这使得我们的跟踪系统变得更加易于使用,这对我们的基础架构来说也是一大胜利。
文档和示例
应更新文档,以显示如何添加轨迹(如上所述)。
向后兼容性
此更改与 API 兼容且与 ABI 兼容。
性能
停用跟踪类别后,这项功能会产生少量开销,每项 dje@google.com 测试的开销不到 5 纳秒(在 NUC 上)。如果需要更高的性能,我们还可以从 IR 中剥离跟踪注解。
安全
无安全影响。
缺点、替代方案和未知情况
替代方案
内核跟踪机制
在通道读取和通道写入中利用现有的 ktrace 流事件。
如果没有此功能,则可以尝试通过对底层通道读写使用现有的 ktrace 流事件来实现此目的。不过,这并不理想,因为通道对所有 FIDL 接口都是通用的,这意味着只能指定一个类别。这意味着,为了实际使用,用户必须启用通道读取和通道写入类别,这意味着系统会显示所有通道读取和写入事件(而不仅仅是用于感兴趣的 FIDL 接口的事件)。这会导致轨迹查看器输出难以阅读、不必要地使用 ktrace 缓冲区,并且还依赖于 FIDL 实现细节。