繁体   English   中英

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

[英]Why is a kretprobe on sys_futex called less often than a corresponding kprobe?

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

我注意到的一件事是,有时,即使在我的简单测试应用程序中,它会启动一些与一些互斥体一起玩的线程,我也不会收到任何对kretprobe__sys_futex调用,但我会得到很多kprobe__sys_futex

我认为这是因为例如一个线程正在调用sys_futex ,然后进入睡眠状态或可能终止,但我实际上看到相同的进程连续多次调用sys_futex而返回探测器从未注意到任何事情。

然后我假设问题在于我如何过滤对kprobe__sys_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-server,它即使在空闲时也会执行常规的 futex 操作 - 至少在我的机器上),许多(通常是 10+)个futex start在返回消息之前打印探测。

这是我在写这篇文章时运行了几分钟的上述程序的示例跟踪:

... 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_write的计数通常在零sys_write ,这比sys_futex发生的频率sys_futex (至少在我的系统的工作负载),所以我希望任何竞争条件都会加剧而不是解决。

我在位于 VirtualBox 的 Ubuntu 18.04 LTS 上运行内核 4.15.0-43-generic。

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

IOVisor 邮件列表中有一个相关主题: https ://lists.iovisor.org/g/iovisor-dev/topic/29702757

这是 bcc 的已知限制(参见iovisor/bcc#1072 )。 基本上,对于您的跟踪上下文,最大活动探测器数设置得太低,因此您会丢失一些返回探测器。

在 bcc 中, maxactive值(最大活动探测器数,请参阅下面的文档摘录)保留为其默认值。 由于 Alban Crequy的 Linux 内核补丁(参见iovisor/bcc#1072 ),通过 debugfs 附加探测器时可以更改maxactive值。 不过,这个新 API 还没有通过 bcc 公开。 本周我将尝试发送一个补丁来达到这个效果。

当被探测的函数正在执行时,它的返回地址存储在 kretprobe_instance 类型的对象中。 在调用 register_kretprobe() 之前,用户设置 kretprobe 结构体的 maxactive 字段以指定可以同时探测指定函数的多少个实例 register_kretprobe() 预先分配指定数量的 kretprobe_instance 对象。

例如,如果函数是非递归的并且在调用时持有自旋锁,则 maxactive = 1 就足够了。 如果函数是非递归的并且永远不能放弃 CPU(例如,通过信号量或抢占),NR_CPUS 应该就足够了。 如果 maxactive <= 0,则将其设置为默认值。 如果启用了 CONFIG_PREEMPT,则默认值为 max(10, 2*NR_CPUS)。 否则,默认值为 NR_CPUS。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM