Как отслеживать операции ввода-вывода для каждого файла в Linux?
мне нужно отслеживать read
системные вызовы для определенных файлов, и в настоящее время я делаю это, анализируя вывод strace
. С read
работает с файловыми дескрипторами, которые я должен отслеживать текущее сопоставление между fd
и path
. Кроме того, seek
должен контролироваться, чтобы сохранить текущую позицию в актуальном состоянии в трассировке.
есть ли лучший способ получить per-application, per-file-path IO traces в Linux?
6 ответов
во-первых, вам, вероятно, не нужно отслеживать, потому что отображение между fd
и path
доступна /proc/PID/fd/
.
во-вторых, возможно, вам следует использовать трюк LD_PRELOAD и перегрузку в C open
, seek
и read
системный вызов. Есть некоторые статьи здесь и здесь о том, как перегрузить malloc / free.
Я думаю, это не будет слишком отличаться, чтобы применить тот же трюк для этих системных вызовов. Это должно быть реализован на C, но он должен занимать гораздо меньше кода и быть более точным, чем разбор strace
выход.
вы можете подождать, пока файлы будут открыты, чтобы вы могли узнать fd и прикрепить strace после запуска процесса следующим образом:
strace-p pid - e trace=file-e read=fd
systemtap - своего рода переосмысление DTrace для Linux - может помочь здесь.
Как и в strace у вас есть только fd, но с возможностью сценариев легко поддерживать имя файла для fd (если только с забавными вещами, такими как dup). Существует пример скрипта iotime, который illustates его.
#! /usr/bin/env stap
/*
* Copyright (C) 2006-2007 Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Print out the amount of time spent in the read and write systemcall
* when each file opened by the process is closed. Note that the systemtap
* script needs to be running before the open operations occur for
* the script to record data.
*
* This script could be used to to find out which files are slow to load
* on a machine. e.g.
*
* stap iotime.stp -c 'firefox'
*
* Output format is:
* timestamp pid (executabable) info_type path ...
*
* 200283135 2573 (cupsd) access /etc/printcap read: 0 write: 7063
* 200283143 2573 (cupsd) iotime /etc/printcap time: 69
*
*/
global start
global time_io
function timestamp:long() { return gettimeofday_us() - start }
function proc:string() { return sprintf("%d (%s)", pid(), execname()) }
probe begin { start = gettimeofday_us() }
global filehandles, fileread, filewrite
probe syscall.open.return {
filename = user_string($filename)
if ($return != -1) {
filehandles[pid(), $return] = filename
} else {
printf("%d %s access %s fail\n", timestamp(), proc(), filename)
}
}
probe syscall.read.return {
p = pid()
fd = $fd
bytes = $return
time = gettimeofday_us() - @entry(gettimeofday_us())
if (bytes > 0)
fileread[p, fd] += bytes
time_io[p, fd] <<< time
}
probe syscall.write.return {
p = pid()
fd = $fd
bytes = $return
time = gettimeofday_us() - @entry(gettimeofday_us())
if (bytes > 0)
filewrite[p, fd] += bytes
time_io[p, fd] <<< time
}
probe syscall.close {
if ([pid(), $fd] in filehandles) {
printf("%d %s access %s read: %d write: %d\n",
timestamp(), proc(), filehandles[pid(), $fd],
fileread[pid(), $fd], filewrite[pid(), $fd])
if (@count(time_io[pid(), $fd]))
printf("%d %s iotime %s time: %d\n", timestamp(), proc(),
filehandles[pid(), $fd], @sum(time_io[pid(), $fd]))
}
delete fileread[pid(), $fd]
delete filewrite[pid(), $fd]
delete filehandles[pid(), $fd]
delete time_io[pid(),$fd]
}
он работает только до определенного количества файлов, потому что хэш-карта ограничена по размеру.
Я думаю, что перегрузка open
, seek
и read
является хорошим решением. Но просто FYI если вы хотите проанализировать и проанализировать вывод strace программно, я сделал что-то подобное раньше и поместил свой код в github:https://github.com/johnlcf/Stana/wiki
(Я сделал это, потому что мне нужно проанализировать результат strace программы, запущенной другими, что нелегко попросить их сделать LD_PRELOAD.)
вероятно, наименее уродливый способ сделать это-использовать fanotify. Fanotify-это средство ядра Linux, которое позволяет дешево смотреть события файловой системы. Я не уверен, что он позволяет фильтровать по PID, но он передает PID вашей программе, чтобы вы могли проверить, если это тот, который вас интересует.
вот хороший пример кода : http://bazaar.launchpad.net / ~pitti / fatrace / багажник / вид / голова: / fatrace.c
тем не менее, на данный момент это, похоже, недостаточно документировано. Все документы я могу найти http://www.spinics.net/lists/linux-man/msg02302.html и http://lkml.indiana.edu/hypermail/linux/kernel/0811.1/01668.html
синтаксический анализ utils командной строки, таких как strace, громоздок; вместо этого вы можете использовать ptrace() syscall. См.man ptrace
для сведения.