概述
在v21.07 release发布版本中,SPDK提供了对BPF追踪(tracing)的支持。BPF追踪指一组定义在 SPDK 库的脚本和静态探针,为用户提供了检查 SPDK 应用程序的另一种方法。SPDK很久以前就建立过一个名为libtrace的追踪库。支持BPF追踪并不是要取代libtrace,而是要对它进行补充。
这两个库的功能略有不同:libtrace的开销很低,但灵活性较差。BPF追踪的成本较高(请求CPU核trap陷阱),但功能更全面,甚至可以动态链接,不必在代码中定义探针。
用户态追踪
首先,我们来探讨什么是BPF追踪,以及SPDK是如何利用它的。
BPF,即Berkeley Packet Filter(伯克利包过滤器),是一项最初为分析和过滤网络流量而开发的技术。用户可以借此在专门的BPF虚拟机的操作系统内核运行用户提供的程序。随后BPF在Linux中得到扩展(扩展后的BPF简称为eBPF),可支持更多用例,其中也包括追踪。
用户能够利用Linux 追踪子系统在程序的特定地方附加探针,一旦触发后会运行附加在该探针的eBPF程序[1]。在用户态应用程序中,BPF会放置一条指令(x86的int3指令),生成SIGTRAP,被CPU核捕获后,即触发执行eBPF程序。
SPDK使用BPF trace (https://github.com/iovisor/bpftrace) 来定义和附加探针。BPF追踪工具使用高级脚本语言(作者称是awk和C语言的结合)来描述特定探针被触发时的操作。
[1] eBPF介绍:https://lwn.net/Articles/740157/
探针可以分为静态定义和动态定义两种。静态探针也称为USDT(User Statically-Defined Tracing用户静态定义的探针),由程序员放置在代码的各个关键位置(使用一种SPDK_DTRACE_PROBE*宏)。动态探针可以在任何函数开始时启用,不需要更改代码或重新编译应用程序。但有一点需要注意:一些静态函数调用可能会使编译器产生inline,在这种情况下,不会照常执行探针追踪。
追踪工具和案例
为了编译静态探针,SPDK必须配置--with-usdt。我们在Ubuntu 20.04和Fedora 33的数据包版本追踪时都遇到了一些问题,因此建议从源码构建最新版本的bpftrace。可以使用scripts/bpftrace.sh来附加和显示追踪。运行scripts/bpftrace.sh需要两个参数:支持追踪的进程参数PID和支持附加的bpftrace脚本。这些脚本能够收集和显示各种不同的信息和统计数据。例如,可以输出某个函数每次被调用时的参数,计算某个代码路径被执行的次数,甚至可以创建并显示一组数据的直方图。SPDK 提供了几个可用脚本,位于 scripts/bpf 目录。
接下来我们来讨论scripts/bpf/send_msg.bt脚本,应该如何用它来检查SPDK应用程序呢?该脚本通过spdk_thread_send_msg()和spdk_for_each_channel()计算某函数的执行次数。脚本的内容简单明了:
uprobe:__EXE__:spdk_thread_send_msg {
@send_msg[usym(arg1)] = count();
}
uprobe:__EXE__:spdk_for_each_channel {
@for_each_channel[usym(arg1)] = count();
}
scripts/bpf/send_msg.bt脚本通过uprobe关键字定义了两个动态探针,分别为send_msg和for_each_channel,将每个函数的调用次数存在映射。第一个参数arg1是映射的密钥之一,在这两种探针下arg1指的都是待执行函数的指针。该脚本使用了两个辅助函数:usym()函数负责返回给定地址的符号名称,count()函数负责计算某个函数被调用的次数。有关可用函数和该脚本通用语法的更多信息,请参阅bpftrace手册[2]。
还有一个特殊变量是SPDK 特有的__EXE__。 scripts/bpftrace.sh 以可执行文件的名称来代替该变量(即符合 bpftrace预期)。__PID__变量由追踪进程的PID参数代替。这两个变量都提供了更便捷的方法,在不同的应用程序中可使用相同的脚本。更多细节请参阅SPDK文档(https://spdk.io/doc/usdt.html)。
脚本连接后就会开始运行,直到应用程序退出(或脚本停止)。这时,脚本会输出每个函数的名称,以及它被调用的次数。通过连接到一个NVMe/TCP目标,收集并输出了如下样本:
for_each_channel[nvmf_ctrlr_disconnect_io_qpairs_on_pg]: 1
@for_each_channel[_nvmf_tgt_add_transport]: 1
@for_each_channel[subsystem_state_change_on_pg]: 5
@send_msg[_nvmf_ctrlr_add_admin_qpair]: 1
@send_msg[_nvmf_subsystem_add_ctrlr]: 1
@send_msg[_nvmf_ctrlr_destruct]: 1
@send_msg[_finish_unregister]: 1
@send_msg[_nvmf_ctrlr_destruct]: 1
@send_msg[put_io_channel]: 4
@send_msg[_call_completion]: 7
@send_msg[_call_channel]: 7
@send_msg[nvmf_ctrlr_add_io_qpair]: 24
@send_msg[_nvmf_ctrlr_add_io_qpair]: 24
@send_msg[_nvmf_ctrlr_free_from_qpair]: 25
@send_msg[_nvmf_poll_group_add]: 25
@send_msg[_nvmf_transport_qpair_fini]: 25
[2]:https://github.com/iovisor/bpftrace/blob/master/man/adoc/bpftrace.adoc
其他可用的脚本可以用来追踪系统调用(syscalls.bt)、NVMeoF子系统的状态转换(nvmf.bt)、以及读取字节数的readv调用(readv.bt)。这些功能本身就提供了很多信息,同时也可以作为编写脚本的指南,追踪应用程序的不同属性。
SPDK和BPF追踪
如前所述,SPDK追踪库其中一个目的是将开销减至最小。这意味着每个追踪点只能记录最关键的数据。做到在I/O路径中放置追踪点,同时不对性能产生重大影响。但有了BPF追踪,我们可以把bpftrace探针放在对象创建的位置,收集其属性,然后用这些数据来辅助SPDK追踪。
例如,在NVMe/RDMA I/O路径中记录指针,指向可执行请求的qpair。然后可以用bpftrace来记录qpair的信息,比如它的队列ID、线程ID、子系统NQN和主机NQN,SPDK显示追踪时与指针一同显示。这就是scripts/bpf/trace.py脚本的功能。
实际操作步骤如下:首先,必须记录bpftraces(假设我们追踪的是基于NVMe/RDMA目标下的spdk_tgt应用程序)。
随后将其用于注解追踪,
将如下输出结果:
0 39100254.090 RDMA_REQ_COMPLETING id: r10 time: 49.692 qpair: 0x1178af0
0 39100320.354 RDMA_REQ_COMPLETED id: r10 time: 115.956 qpair: 0x1178af0
0 39100494.100 RDMA_REQ_NEW id: r11 qpair: 0x11790a0
0 39100494.454 RDMA_REQ_NEED_BUFFER id: r11 time: 0.354 qpair: 0x11790a0
0 39100494.684 RDMA_REQ_RDY_TO_EXECUTE id: r11 time: 0.584 qpair: 0x11790a0
0 39100500.546 RDMA_REQ_EXECUTING id: r11 time: 6.446 qpair: 0x11790a0
0 39100516.727 RDMA_REQ_EXECUTED id: r11 time: 22.627 qpair: 0x11790a0
0 39100516.903 RDMA_REQ_RDY_TO_COMPL id: r11 time: 22.803 qpair: 0x11790a0
0 39100517.333 RDMA_REQ_COMPLETING id: r11 time: 23.233 qpair: 0x11790a0
0 39100550.895 RDMA_REQ_COMPLETED id: r11 time: 56.795 qpair: 0x11790a0
转换到:
0 39100254.090 RDMA_REQ_COMPLETING id: r10 time: 49.692 qpair(ptr=0x1178af0, thread=2, qid=1, subnqn=nqn.2016-06.io.spdk:cnode0, hostnqn=nqn.2014-08.org.nvmexpress:uuid:8da29bed555a45e8b9bc378e115f4c2)
0 39100320.354 RDMA_REQ_COMPLETED id: r10 time: 115.956 qpair(ptr=0x1178af0, thread=2, qid=1, subnqn=nqn.2016-06.io.spdk:cnode0, hostnqn=nqn.2014-08.org.nvmexpress:uuid:8da29bed555a45e8b9bc378e115f4c2)
0 39100494.100 RDMA_REQ_NEW id: r11 qpair(ptr=0x11790a0, thread=2, qid=2, subnqn=nqn.2016-06.io.spdk:cnode0, hostnqn=nqn.2014-08.org.nvmexpress:uuid:8da29bed555a45e8b9bc378e115f4c2)
0 39100494.454 RDMA_REQ_NEED_BUFFER id: r11 time: 0.354 qpair(ptr=0x11790a0, thread=2, qid=2, subnqn=nqn.2016-06.io.spdk:cnode0, hostnqn=nqn.2014-08.org.nvmexpress:uuid:8da29bed555a45e8b9bc378e115f4c2)
0 39100494.684 RDMA_REQ_RDY_TO_EXECUTE id: r11 time: 0.584 qpair(ptr=0x11790a0, thread=2, qid=2, subnqn=nqn.2016-06.io.spdk:cnode0, hostnqn=nqn.2014-08.org.nvmexpress:uuid:8da29bed555a45e8b9bc378e115f4c2)
0 39100500.546 RDMA_REQ_EXECUTING id: r11 time: 6.446 qpair(ptr=0x11790a0, thread=2, qid=2, subnqn=nqn.2016-06.io.spdk:cnode0, hostnqn=nqn.2014-08.org.nvmexpress:uuid:8da29bed555a45e8b9bc378e115f4c2)
0 39100516.727 RDMA_REQ_EXECUTED id: r11 time: 22.627 qpair(ptr=0x11790a0, thread=2, qid=2, subnqn=nqn.2016-06.io.spdk:cnode0, hostnqn=nqn.2014-08.org.nvmexpress:uuid:8da29bed555a45e8b9bc378e115f4c2)
0 39100516.903 RDMA_REQ_RDY_TO_COMPL id: r11 time: 22.803 qpair(ptr=0x11790a0, thread=2, qid=2, subnqn=nqn.2016-06.io.spdk:cnode0, hostnqn=nqn.2014-08.org.nvmexpress:uuid:8da29bed555a45e8b9bc378e115f4c2)
0 39100517.333 RDMA_REQ_COMPLETING id: r11 time: 23.233 qpair(ptr=0x11790a0, thread=2, qid=2, subnqn=nqn.2016-06.io.spdk:cnode0, hostnqn=nqn.2014-08.org.nvmexpress:uuid:8da29bed555a45e8b9bc378e115f4c2)
0 39100550.895 RDMA_REQ_COMPLETED id: r11 time: 56.795 qpair(ptr=0x11790a0, thread=2, qid=2, subnqn=nqn.2016-06.io.spdk:cnode0, hostnqn=nqn.2014-08.org.nvmexpress:uuid:8da29bed555a45e8b9bc378e115f4c2)
目前,只有RDMA qpairs可供注解,但预计今后会添加更多注解。
结论
总而言之,现在SPDK可以使用更全面更有效的方法实现BPF追踪以检查应用程序。BPF追踪由一组bpftrace程序、定义在SPDK库的USDT探针和几个脚本组成,这些脚本能够简化BPF追踪,和常规的SPDK追踪代码结合使用。
原文链接如下:
https://spdk.io/news/2021/09/28/bpf_tracing_with_spdk/
学习更多dpdk视频
DPDK 学习资料、教学视频和学习路线图 :https://space.bilibili.com/1600631218
Dpdk/网络协议栈/ vpp /OvS/DDos/NFV/虚拟化/高性能专家 上课地址: https://ke.qq.com/course/5066203?flowToken=1043799
DPDK开发学习资料、教学视频和学习路线图分享有需要的可以自行添加学习交流q 君羊909332607备注(XMG) 获取
最后
以上就是爱听歌果汁为你收集整理的SPDK的BPF Tracing的全部内容,希望文章能够帮你解决SPDK的BPF Tracing所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复