linux - 正确使用 linux inotify - 每次都重新打开?

标签 linux redhat inotify

我正在调试客户在其生产系统中遇到的系统负载问题,他们制作了一个模拟负载的测试应用程序来重现该问题:

sexy graph

在这个特定的工作负载中,编码人员所做的其中一件事是:

while(1)
  initialize inotify
  watch a directory for events
  receive event
  process event
  remove watch
  close inotify fd

奇怪的是,高系统负载来自inotify fd的close():

inotify_init()                          = 4 <0.000020>
inotify_add_watch(4, "/mnt/tmp/msys_sim/QUEUES/Child_032", IN_CREATE) = 1 <0.059537>
write(1, "Child [032] sleeping\n", 21)  = 21 <0.000012>
read(4, "\1\0\0\0\0\1\0\0\0\0\0\0\20\0\0\0SrcFile.b8tlfT\0\0", 512) = 32 <0.231012>
inotify_rm_watch(4, 1)                  = 0 <0.000044>
close(4)                                = 0 <0.702530>
open("/mnt/tmp/msys_sim/QUEUES/Child_032", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 4 <0.000031>
lseek(4, 0, SEEK_SET)                   = 0 <0.000010>
getdents(4, /* 3 entries */, 32768)     = 88 <0.000048>
getdents(4, /* 0 entries */, 32768)     = 0 <0.000009>
write(1, "Child [032] dequeue [SrcFile.b8t"..., 37) = 37 <0.000011>
unlink("/mnt/tmp/msys_sim/QUEUES/Child_032/SrcFile.b8tlfT") = 0 <0.059298>
lseek(4, 0, SEEK_SET)                   = 0 <0.000011>
getdents(4, /* 2 entries */, 32768)     = 48 <0.000038>
getdents(4, /* 0 entries */, 32768)     = 0 <0.000009>
close(4)                                = 0 <0.000012>
inotify_init()                          = 4 <0.000020>
inotify_add_watch(4, "/mnt/tmp/msys_sim/QUEUES/Child_032", IN_CREATE) = 1 <0.040385>
write(1, "Child [032] sleeping\n", 21)  = 21 <0.000903>
read(4, "\1\0\0\0\0\1\0\0\0\0\0\0\20\0\0\0SrcFile.mQgUSh\0\0", 512) = 32 <0.023423>
inotify_rm_watch(4, 1)                  = 0 <0.000012>
close(4)                                = 0 <0.528736>

什么可能导致 close() 调用花费如此大量的时间?我可以确定两种可能的情况:

  • 每次关闭并重新初始化inotify
  • /mnt/tmp/msys_sim/SOURCES 中有 256K 个文件(平面),/mnt/tmp/msys_sim/QUEUES/Child_032 中的特定文件是硬链接(hard link)的到该目录中的一个。但是SOURCES从来没有被上述过程打开过

难道是inotify使用错误的神器?我可以指着什么说“你做的是错的!”?


perf top 的输出(我一直在寻找这个!)

Events: 109K cycles
 70.01%  [kernel]      [k] _spin_lock
 24.30%  [kernel]      [k] __fsnotify_update_child_dentry_flags
  2.24%  [kernel]      [k] _spin_unlock_irqrestore
  0.64%  [kernel]      [k] __do_softirq
  0.60%  [kernel]      [k] __rcu_process_callbacks
  0.46%  [kernel]      [k] run_timer_softirq
  0.40%  [kernel]      [k] rcu_process_gp_end

甜!我怀疑某处存在自旋锁,并且整个系统在发生这种情况时会高度延迟。

最佳答案

通常伪代码 inotify 循环看起来像这样:

initialize inotify
watch a directory | file for events

while(receive event) {
  process event
}

[ remove watch ]
close inotify fd

无需在每次循环时移除 watch 并重新初始化 inotify。

关于linux - 正确使用 linux inotify - 每次都重新打开?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20554806/

相关文章:

php - 显示子域根目录下域文件夹的内容

c - iNotify 如何检测移出

php - 如何在终端中使用 inotify-tools 获取递归目录路径

c - Linux 4.5 GPIO 中断通过 Xilinx Zynq 平台上的 Devicetree

r - R 中光栅处理的内存问题

redhat - 使用 RPM 卸载包时意外失败的依赖项

python - 在不同系统的无互联网机器上部署Python virtualenv

c - inotify API 与选择

c - C 中的 IPPROTO_TCP IP_TOS 的 setsockopt 失败

linux - 无法为安装在 linux redhat 服务器上的 R studio 安装 Devtools 包