【问题标题】:Best way to watch process (and sub-processes) for file system read() I/O?观察文件系统 read() I/O 的进程(和子进程)的最佳方式?
【发布时间】:2009-09-17 15:27:47
【问题描述】:

我想开发一个这样工作的命令行程序:

myprogram /c [some_executable_here]

它启动了用户指定的命令并“监视”进程(和任何子进程)以进行读取 I/O,当该程序退出时,打印“读取”的文件列表(最终导致read() 系统调用)。

我最初的实施操作系统是 Windows,但我也想在 Linux 上做同样的事情。

到目前为止,我看到的所有类似 FileSystem watch 的 API 都面向监视目录(或单个文件),而不是进程,所以我不确定最好的方法是什么。

编辑:我正在寻找 代码 示例,说明如何最终实现此功能(或至少指向我可以遵循的 API 的指针)以在 Windows 和Linux。

另外需要明确的是,它不能使用诸如 OpendFilesView、procmon 或某些系统级工具中的 grepping 字符串之类的方法,这些工具无法从头到尾通过 ID(和任何子进程)明确识别进程其执行情况; IOW 通过搜索“foo.exe”并得到错误的结果,不会涉及任何时间问题和误报的可能性。

【问题讨论】:

  • 我删除了我的答案,因为 iotop 仅对会计有用。它无法知道哪些文件被更改(因为它使用内核的 I/O 记帐功能,而记帐是用于记帐的),因此对您没有用处。 gl :)

标签: filesystems kernel device-driver


【解决方案1】:

在 Linux 上,我肯定会使用strace——它简单而强大。例如:

$ strace -o/tmp/blah -f -eopen,read bash -c "cat ciao.txt"

运行请求的命令(包括它产生的子进程,由于-f)并留在/tmp/blah(在我的例子中为120行)详细说明这些进程进行的所有打开和读取调用,以及他们的结果。

之后您确实需要进行一些处理,以根据需要仅提取已成功读取的文件集;例如,使用 Python,您可以:

import re

linere = re.compile(r'^(\d+)\s+(\w+)\(([^)]+)\)\s+\=\s*(.*)$')

def main():
  openfiles = dict()
  filesread = set()
  with open('/tmp/blah') as f:
    for line in f:
      mo = linere.match(line)
      if mo is None:
        print "Unmatched line %r" % line
      pid, command, args, results = mo.groups()
      if command == 'open':
        fn = args.split(',', 1)[0].strip('"')
        fd = results.split(' ', 1)[0]
        openfiles[fd] = fn
      elif command == 'read':
        if results != '0':
          fd = args.split(',', 1)[0]
          filesread.add(openfiles[fd])
      else:
        print "Unknown command %r" % command
  print sorted(filesread)

这有点过于简单了(您需要查看其他一些系统调用,例如 dup &c),但我希望能说明所需工作的要点。在我的示例中,这会发出:

['/lib/libc.so.6', '/lib/libdl.so.2', '/lib/libncurses.so.5',
 '/proc/meminfo', '/proc/sys/kernel/ngroups_max',
 '/usr/share/locale/locale.alias', 'ciao.txt']

所以它也算作“读取”那些为获取动态库而完成的操作,而不仅仅是“数据文件”......在系统调用级别,几乎没有区别。我想如果你需要的话,你可以过滤掉非数据文件。

我发现strace 非常方便,如果我被要求在 Windows 上执行相同的工作,我的第一次尝试是使用StraceNT -- 不是 100% 兼容,当然还有底层系统调用names &c 不同,但我想我可以在我的 Python 代码中解释这些差异(准备和执行 strace 命令,并对结果进行后处理)。

不幸的是,据我所知,其他一些 Unix 系统只有在您是 root (超级用户)时才提供这种功能——例如在 Mac OS X 上,您需要通过 sudo 才能执行 dtracedtruss 等跟踪实用程序;我不知道strace 到 Mac 的直接端口,也不知道没有 root 权限执行此类任务的其他方法。

【讨论】:

    【解决方案2】:

    试试 "Process Monitor" (procmon.exe) 它允许指定一个过滤器(要监视的进程的名称)。然后它将列出所有文件和对所述文件的操作。

    在 Linux 上,尝试lsof 获取当前快照,尝试strace 进行持续监控。您必须使用 grep 过滤输出。

    所有这些工具都会检查进程结构(即操作系统用来管理进程的数据结构)并枚举其中提到的句柄/文件描述符。这不是文件系统 API 的功能,而是进程管理 API。

    [编辑] 请参阅this page 上的“它是如何工作的”部分,开始在 Windows 上编写您自己的工具。

    【讨论】:

    • 我知道 procmon 但它只适用于指定的时间段,而且,这是我想弄清楚如何用我自己的代码实现的东西。
    • OpenedFilesView v1.45 附带了如何在 Windows 上执行此操作的说明(请参阅我的编辑)
    • 该网页提到它使用“NtQuerySystemInformation API”并具有内核驱动程序(NirSoftOpenedFilesDriver.sys),但我看不到有关如何以编程方式执行此操作的其他信息。这对 Windows 来说是一个很好的线索,但不足以让我作为一个从未做过 Windows 内核驱动程序的开发人员开始。
    • 问作者,复用现有驱动?
    • 已发送。希望他回复。 :)
    【解决方案3】:

    一个选项 -d (--watchfd) was added in 2014 进入 pv 以密切关注 pid。

    易于记忆,有助于调试。

    pv --help
      -d, --watchfd PID[:FD]   watch file FD opened by process PID
    

    例如,通过他的名字来观察一个进程。

    pv -d `pgrep firefox`
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多