read
特定のファイルのシステム コールを追跡する必要があります。現在、 strace
. はファイル記述子で動作するため、 とread
の間の現在のマッピングを追跡する必要がfd
ありpath
ます。さらに、seek
トレースで現在の位置を最新に保つために監視する必要があります。
Linux でアプリケーションごと、ファイルパスごとの IO トレースを取得するより良い方法はありますか?
read
特定のファイルのシステム コールを追跡する必要があります。現在、 strace
. はファイル記述子で動作するため、 とread
の間の現在のマッピングを追跡する必要がfd
ありpath
ます。さらに、seek
トレースで現在の位置を最新に保つために監視する必要があります。
Linux でアプリケーションごと、ファイルパスごとの IO トレースを取得するより良い方法はありますか?
ファイルが開かれるのを待って、プロセスの起動後に fd を学習し、次のように strace を添付できます。
strace -p pid -e トレース=ファイル -e 読み取り= fd
systemtap - Linux 向けの一種の DTrace 再実装 - がここで役立つ可能性があります。
strace と同様に、fd しかありませんが、スクリプト機能を使用すると、fd のファイル名を簡単に維持できます (dup のような楽しいものを使用しない限り)。それを示すサンプルスクリプト iotime があります。
#! /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]
}
ハッシュ マップのサイズは制限されているため、特定の数のファイルまでしか機能しません。
fd
まず、との間のマッピングpath
は で使用できるため、おそらく追跡する必要はありません/proc/PID/fd/
。
次に、C で LD_PRELOAD トリックとオーバーロードopen
、seek
およびread
システム コールを使用する必要があるかもしれません。malloc/free をオーバーロードする方法に関する記事があちこちにあります。
これらのシステム コールに同じ種類のトリックを適用しても、さほど変わらないと思います。C で実装する必要がありますが、strace
出力を解析するよりもはるかに少ないコードで正確に実行できるはずです。
オーバーロードは良い解決策open
だseek
と思います。read
しかし、参考までに、strace の出力をプログラムで解析および分析したい場合は、以前に同様のことを行い、コードを github に置きました: https://github.com/johnlcf/Stana/wiki
(他の人が実行したプログラムのstrace結果を分析する必要があるため、LD_PRELOADを実行するように依頼するのは簡単ではありません。)
Probably the least ugly way to do this is to use fanotify. Fanotify is a Linux kernel facility that allows cheaply watching filesystem events. I'm not sure if it allows filtering by PID, but it does pass the PID to your program so you can check if it's the one you're interested in.
Here's a nice code sample: http://bazaar.launchpad.net/~pitti/fatrace/trunk/view/head:/fatrace.c
However, it seems to be under-documented at the moment. All the docs I could find are http://www.spinics.net/lists/linux-man/msg02302.html and http://lkml.indiana.edu/hypermail/linux/kernel/0811.1/01668.html
strace のようなコマンドライン ユーティリティの解析は面倒です。代わりに ptrace() syscall を使用できます。詳細man ptrace
については、を参照してください。