前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >结合例子学习eBPF与bcc:kretprobe与Tracepoint

结合例子学习eBPF与bcc:kretprobe与Tracepoint

作者头像
AshinZ
发布2023-11-01 17:12:00
2930
发布2023-11-01 17:12:00
举报

在前面的文章中,我们学习了如何通过追踪kprobe,今天我们来学习更多的追踪机制:

  • kretprobe:类似于kprobe,但是是追踪其返回值或输出值;
  • Tracepoint:静态的追踪点,在内核中已编译好;

vfsreadlat

首先我们借助vfsreadlat来学习kretprobe的使用。kretprobekprobe可以看成是一对兄弟,kprobe在内核函数开始的时候执行,而kretprobe则在内核函数结束的时候执行,例如对于内核函数blk_mq_start_request

k[ret]probe

我们在kprobe挂载的函数start会在内核函数开始执行前执行,而在kretprobe挂载的函数end则会在内核函数结束后执行。前者可以探测内核函数的输入值,而后者则探测内核函数的返回值或者输出值。

让我们来看看vfsreadlat,首先是vfsreadlat.c

vfsreadlat.c

可以看出在do_entry函数中,我们记录了pid和它对应的时间;在do_return函数中,我们基于pid来计算时间的差值。

这是eBPFC代码,我们需要在bcc文件中引入它:

代码语言:javascript
复制
b = BPF(src_file = "vfsreadlat.c")

如下就是全部的vfsreadlat.py

vfsreadlat.py

我们重点关注其中的挂载语句:

attach

正如我们前文所说的,这里的流程是这样的:

vfsreadlat流程

小结一下:**kprobe在内核函数进入前执行,kretprobe在内核函数返回后执行**。

urandomread

这一小节我们要学习的是Tracepoint的使用,Tracepointkprobe类似,也可以追踪内核的一些信息,但是Tracepoint是预制好的hook,已经提前在内核中编译好了,我们只需要直接使用就行。

先看代码:

urandonread

可以看到我们直接在C中用TRACEPOINT_PROBE宏来进行了声明,这个宏指向的目标是内核断点 random:urandom_read,这个断点已经在内核中静态编译好了,如果我们在这里加入了这个宏,那么运行到randon:urandon_read的时候就会运行这个宏的内容。我们可以通过perf list命令来查看Tracepoint的列表:

Tracepoint

这里宏的参数做了自动填充,我们可以用args->xxx来访问结构体变量。参数的内容可以通过/sys/kernel/debug/tracing/events/xxx/xxx/format来访问,例如random:urandom_read就是/sys/kernel/debug/tracing/events/random/urandom_read/format

random:urandom_read

这个程序的流程如下图所示:

urandom_read

Tracepointhook总是存在的,如果我们给它挂载了东西,它就会执行,反之则不会。

disksnoopTracepoint

现在我们尝试用block:block_rq_issueblock:block_rq_complete这两个Tracepoint来改写disksnoop。前者表示的是磁盘请求开始,后者则是结束。我们需要输出请求的大小和延时。

我们首先查看Tracepoint的结构体:

block:block_rq_issue

block:block_rq_compelete

从这两个结构体中我们可以看出,请求的大小只在block_rq_issue的时候记录,所以我们需要有一个地方存储它。此外我们还需要考虑如何计算时间,我们需要记录下请求开始的时间和请求结束的时间,这里的问题在于我们该用什么作为哈希表的key。在这里我们使用args->dev作为keydev表示块设备的设备号。

「这里如果用pid作为key将会出现没有输出的情况。」这是因为在block_rq_issue的时候,我们通过bpf_get_current_pid_tgid获取到的是pid,但是在block_rq_complete的时候,此时运行的进程并不一定是发出请求的那个进程,所以无法保持一致性。

基于args->dev作为key,我们可以快速的编写如下的C代码:

disksnoop

接着通过编写前端代码我们就可以进行数据的输出了,运行结果如下:

运行disksnoop

小结

今天我们学习了:

  • k[ret]probe是动态追踪,我们可以在内核函数的开头和结尾进行追踪,相对更灵活;但是其开销也更大;
  • Tracepoint则更像是静态的,已经存在于内核中的hook点,不够灵活,但是相对固定,在不同版本的操作系统中变化不大,开销也更小;

disksnoopTracepoint

disksnoopTracepoint

本文参与?腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-08-28,如有侵权请联系?cloudcommunity@tencent.com 删除

本文分享自 程栩的性能优化笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • vfsreadlat
  • urandomread
  • disksnoopTracepoint
  • 小结
    • disksnoopTracepoint
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
    http://www.vxiaotou.com