Linux kernel 为什么sys_futex上的kretprobe的调用频率低于相应的kprobe?

Linux kernel 为什么sys_futex上的kretprobe的调用频率低于相应的kprobe?,linux-kernel,bpf,ebpf,kprobe,bcc-bpf,Linux Kernel,Bpf,Ebpf,Kprobe,Bcc Bpf,我正在跟踪各种内核函数和系统调用,并在它们之间建立模式,这些模式可用于某些性能评测 我注意到的一件事是,有时,即使在我的简单测试应用程序中,它会产生一些线程来使用互斥锁,我也不会得到任何调用kretprobe\uuuusys\ufutex,但我会得到很多调用kprobe\usys\ufutex 我假设这是因为,例如,一个线程正在调用sys\u futex,并将进入睡眠状态或可能终止,但我实际上看到相同的进程连续多次调用sys\u futex,而返回探测从未注意到任何东西 然后我假设问题出在如何过

我正在跟踪各种内核函数和系统调用,并在它们之间建立模式,这些模式可用于某些性能评测

我注意到的一件事是,有时,即使在我的简单测试应用程序中,它会产生一些线程来使用互斥锁,我也不会得到任何调用
kretprobe\uuuusys\ufutex
,但我会得到很多调用
kprobe\usys\ufutex

我假设这是因为,例如,一个线程正在调用
sys\u futex
,并将进入睡眠状态或可能终止,但我实际上看到相同的进程连续多次调用
sys\u futex
,而返回探测从未注意到任何东西

然后我假设问题出在如何过滤对
kprobe\uuuu sys\u futex的调用上,因此我用BCC/eBPF做了一个简单的示例来测试这一点:

#! /usr/bin/env python

from bcc import BPF

b = BPF(text="""
BPF_HASH(call_count, int, int);

int kprobe__sys_futex() {
  int zero = 0;
  call_count.lookup_or_init(&zero, &zero);
  bpf_trace_printk("futex start\\n");
  call_count.increment(zero);
  return 0;
}

int kretprobe__sys_futex() {
  int zero = 0;
  int *val_p = call_count.lookup(&zero);
  if (val_p != NULL) {
      int val = *val_p;
      val--;
      call_count.update(&zero, &val);
      bpf_trace_printk("futex calls with no return: %d\\n", val);
  } else { bpf_trace_printk("unexpected futex return\\n"); }
  return 0;
}
""")

b.trace_print()
我注意到,在所有类型的应用程序中(mysql服务器就是一个很好的例子,它即使在空闲时也会执行常规的futex操作——至少在我的机器上是这样),很多(通常是10+
futex start
s)都会在返回探测的消息之前打印出来

下面是上面程序的一个示例跟踪,我在写这篇文章时让它运行了几分钟:

... hundreds of lines of much the same as below
           gdbus-612   [001] .... 211229.997665: 0x00000001: futex start
  NetworkManager-541   [001] .... 211229.997667: 0x00000001: futex start
           gdbus-612   [001] .... 211229.997670: 0x00000001: futex start
          mysqld-697   [001] .... 211230.789205: 0x00000001: futex start
          mysqld-697   [001] .... 211230.789227: 0x00000001: futex start
          mysqld-703   [001] .... 211230.789251: 0x00000001: futex start
          mysqld-703   [001] .... 211230.789253: 0x00000001: futex start
          mysqld-704   [001] d... 211230.789258: 0x00000001: futex calls with no return: 3994
          mysqld-704   [001] .... 211230.789259: 0x00000001: futex start
          mysqld-704   [001] d... 211230.789260: 0x00000001: futex calls with no return: 3994
          mysqld-704   [001] .... 211230.789272: 0x00000001: futex start
          mysqld-713   [000] .... 211231.037016: 0x00000001: futex start
          mysqld-713   [000] .... 211231.037036: 0x00000001: futex start
         vmstats-895   [000] .... 211231.464867: 0x00000001: futex start
          mysqld-697   [001] .... 211231.790738: 0x00000001: futex start
          mysqld-697   [001] .... 211231.790784: 0x00000001: futex start
          mysqld-703   [001] .... 211231.790796: 0x00000001: futex start
          mysqld-703   [001] .... 211231.790799: 0x00000001: futex start
          mysqld-704   [001] d... 211231.790809: 0x00000001: futex calls with no return: 4001
          mysqld-704   [001] .... 211231.790812: 0x00000001: futex start
          mysqld-704   [001] d... 211231.790814: 0x00000001: futex calls with no return: 4001
如您所见,例如,pid 697似乎已经调用了四次sys_futex,而没有返回这个小轨迹

我不认为这是eBPF代码中的竞争条件,因为如果您禁用打印语句并且只定期打印,
sys\u write
,计数通常在零附近,这比
sys\u futex
(至少在我的系统工作负载上)发生的频率更高,因此,我预计任何种族状况都会恶化,而不是得到解决

我在VirtualBox中的Ubuntu18.04LTS上运行内核4.15.0-43-generic

很高兴提供更多可能有用的上下文


IOVisor邮件列表中有一个相关的线程:

这是bcc的已知限制(参见)。基本上,活动探测的最大数量对于跟踪上下文设置得太低,因此缺少一些返回探测

在bcc中,
maxactive
值(活动探测器的最大数量,请参阅下面的文档摘录)保留为默认值。由于Alban Crequy的Linux内核补丁(参见),因此在通过debugfs连接探测时,可以更改
maxactive
值。不过,新的API尚未通过bcc公开。本周我将尝试发送一个具有此效果的补丁

当探测函数执行时,其返回地址为 存储在kretprobe_实例类型的对象中。打电话之前 register_kretprobe(),用户设置 kretprobe结构,以指定指定 可以同时探测函数。寄存器_kretprobe() 预分配指定数量的kretprobe_实例对象

例如,如果函数是非递归的,并且使用 自旋锁保持,maxactive=1应该足够了。如果函数是 非递归且永远不能放弃CPU(例如,通过信号量
或者抢占),NR_CPU应该足够了。如果maxactive的内核模块代码与maxactive的内核模块代码没有相同的问题,那么它将有助于调试!对不起我现在正在回复你在邮件列表上的邮件;我不久前还想发送它,但我发现内核模块有时也会掉调用。我不完全相信这完全解释了为什么我经常运行,似乎几乎没有触发RetProbe,而有些则可靠地跟踪它们,但我刚刚意识到,这可能是由于系统中的许多线程在futex上重复睡眠数秒,而没有其他操作(看着你,mysql),每个线程都会永久性地消耗一个探测器。这就解释了为什么我也只能用sys_futex来观察这个问题(sys_write在我的系统上返回的速度太快,所以不会成为问题)。再次感谢您的时间和努力,帮助这一点!