LWN:user event,不过还未完工!

关注了就能看到更多这么棒的文章哦~

User events — but not quite yet

By Jonathan Corbet
April 18, 2022
DeepL assisted translation
https://lwn.net/Articles/889607/

ftrace 和 perf 子系统让开发者可以看到内核的工作细节,通过利用现有的 tracepoint,开发者如果感兴趣的话就可以看到代码中的特定位置正在发生什么。其实并不是系统中所有让人感兴趣的 event 都发生在内核中,尽管内核开发者可能不太喜欢这个想法。管理员往往也想看看用户空间的进程,如果有一种机制可以同时追踪内核和用户空间的事件,他们会更加高兴。由 Beau Belgrave 开发并在 5.18 合并窗口中加入的 user-events 子系统就提供了这种能力,但用户几乎肯定还要再等待一个内核周期才能真正用上它。

kernel tracepoint 是位于代码中一些特定位置的 hook。它们的设计理念是在未激活使用时只会带来尽可能少地额外开销,毕竟大多数情况下都是不需要使用的。当一个 tracepoint 被激活时,它会产生一个针对被监控事件的结构化数据流(a stream of structured data);用户空间可以通过一些各自不同的接口来读取到这些数据。用户空间通过打开感兴趣的 tracepoint,就可以收集到要分析特定情况所需的数据,而不会拖累内核的整体速度。

The user-events ABI

Belgrave 在用户空间也实现了类似于内核空间的 tracepoint 的机制,在 5.18 版本中合并了进来,但是还需要更多的工作来完全支持,尽管今后会提供的库可能可以减少一些复杂度。第一步是打开一个添加到 tracefs 内核文件系统的新文件:

/sys/kernel/debug/tracing/user_events_data

然后,程序需要注册它希望提供给系统的每个 event。这是通过填写这个结构来完成:

struct user_reg {
    u32 size;
    u64 name_args;
    u32 status_index;
    u32 write_index;
};

前两个成员是输入参数,后两个是由内核设置的。size 参数应该只是 user_reg 结构本身的 size,这有助于确保在未来的内核版本中该结构变大时有更好的兼容性。event 是本身由 name_args 描述的,这是一个指向字符串的指针,它使用了这个 patch set 中添加的特殊格式。第一个 token 是 event 的名称,这一行字符串里余下的部分描述了该 event 报告出来的数据。因此,一个报告了名为 level 的整数值以及名为 badness 的 20 个字符的字符串的 event 可以被描述为:

my-event u32 level; char[20] badness

然后用 DIAG_IOCSREG 命令字在先前打开的 user_events_data 文件上进行 ioctl() 操作,来把这个结构注册进去。注册成功后,内核将在 status_index 和 write_index 中存储两个索引值,其用途将在下文中介绍。

等 event 被注册进来之后,它将显示在 tracefs 的 user_events 子系统下。这意味着它可以被激活使用了,并且可以使用任意的常用用户空间工具来收集其数据。但为了达到这个目的,在需要的时候,应用程序首先必须提供这些数据。

要做到这一点,程序应该同时打开另外的新增 tracefs 文件:

/sys/kernel/debug/tracing/user_events_status

然后用 mmap()调用将该文件映射到自己程序的地址空间里。

就类似对应的内核机制一样,user-event 机制设计成了在没有人对事件感兴趣的情况下要将其开销最小化。所以实现 event 的程序只有在被明确要求时才会提供数据。上面刚刚 map 进来的 user_events_status 文件将包含一个字节的内容,表明该 event 是否处于激活状态,其索引是注册时存储在 status_index 字段中的值。如果该字节为零,则表示该 event 未被激活,程序不应输出任何数据,一般情况下都应该是这样的。

当有人开始监控这个事件时,相关的字节就不再是 0 了。事实上,它是一个 bitmask,给出了关于 event 如何被 attach 的信息。其中一个 bit 对应于 ftrace,而另一个 bit 则对应于 perf。当程序看到这个非 0 字节时,它应该要把跟该 event 相关的数据写入一开始打开的 user_events_data 文件。写入数据的前四个字节应该是内核在注册时存储在 write_index 中的值,后续内容将是上面描述的数据。通常情况下,需要调用 writev() 来把相关 bit 数据来组装好。

这就完成了相关的 API 介绍了。更多信息可以在相关的文档 commit 以及示例程序中找到。另外,肯定还有一种将 BPF 程序 attach 到 user event 的方法,但该功能在文档中没有详细描述。

Concerns

在这些代码被合并之后,Linux Trace Toolkit(LTTng)的开发者 Mathieu Desnoyers 发表了一些对新接口的批评。基于字节的 status 机制在他看来效率比较低下,为每个 event 提供一个单独的 bit,可以使其更紧凑,从而更好地利用 cache。关于表明事件是如何被 attach 的多个 bit 的信息,对于被 trace 追踪的应用程序来说没有什么实际价值,无论如何都是应该产生相同的数据的。

他还有一些其他的担心。如果包含了将要写入 event 数据的 page 被迫离开内存,由此产生的 page fault 将导致 writev()失败,如果没有积极的应对措施的话,event data 就会丢失。整个机制是围绕着通过内核访问 tracing data 而建立的,只有在使用纯用户空间的 tracer(如 LTTng)时,它才会增加开销。此外也有一些实施细节方面的问题。

Desnoyers 还让 BPF 的维护者 Alexei Starovoitov 注意到了这个设施,他一直没有意识到这一点。他对他所看到的内容不是很满意,他要求立即删除 BPF 机制。"给 user_events 添加一个 bpf 接口是绝对不应该的"。他在随后的讨论中重申了这一立场。

Belgrave 很快按照要求发布了一个删除 BPF 功能的 patch。但看起来这还并不足以让这个功能在 5.18 中启用。tracing 部分的维护者 Steven Rostedt 表示同意 Desnoyers 的观点,说他正在考虑将整个机制标记为 "broken(无法使用)",以便解决这些问题。在想象中,Belgrave 能在这个开发周期内解决所有的问题,但其实很可能不会发生,这类工作不应该在合并窗口关闭后进入 mainline。所以,用户有可能要等到 5.19 版本才能使用新的 user-events tracing 机制。

全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~

92e463c5f349d52da7771d8934599dea.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值