特定のファイルに対するread
システムコールを追跡する必要があります。現在、strace
の出力を解析してこれを行っています。 read
はファイル記述子を操作するため、fd
とpath
の間の現在のマッピングを追跡する必要があります。さらに、トレース内の現在の位置を最新に保つために、seek
を監視する必要があります。
Linuxでアプリケーションごと、ファイルパスごとIOトレースを取得するためのより良い方法はありますか?
次のように、プロセスの起動後にfdを学習し、straceをアタッチできるように、ファイルが開かれるのを待つことができます。
strace -p pid -e trace = file -e read = fd
systemtap --Linux用の一種のDTrace再実装-ここで役立つ可能性があります。
Straceと同様に、fdしかありませんが、スクリプト機能を使用すると、fdのファイル名を簡単に維持できます(dupのような楽しいものがない限り)。 illustates itというサンプルスクリプト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]
}
ハッシュマップのサイズには制限があるため、特定の数のファイルまでしか機能しません。
open
、seek
、およびread
のオーバーロードは良い解決策だと思います。しかし、プログラムでstrace出力を解析および分析したい場合は、参考までに、以前に同様のことを行い、コードをgithubに配置しました: https://github.com/johnlcf/Stana/wiki
(他の人が実行したプログラムのstrace結果を分析する必要があるため、LD_PRELOADを実行するように依頼するのは簡単ではありません。)
おそらく、これを行うための最も醜い方法は、fanotifyを使用することです。 Fanotifyは、ファイルシステムイベントを安価に監視できるLinuxカーネル機能です。 PIDによるフィルタリングが許可されているかどうかはわかりませんが、PIDがプログラムに渡されるため、関心のあるものかどうかを確認できます。
素敵なコードサンプルは次のとおりです。 http://Bazaar.launchpad.net/~pitti/fatrace/trunk/view/head:/fatrace.c
ただし、現時点では文書化が不十分なようです。私が見つけたすべてのドキュメントは http://www.spinics.net/lists/linux-man/msg02302.html および http://lkml.indiana.edu/hypermail/ linux/kernel/0811.1/01668.html
Straceのようなコマンドラインユーティリティの解析は面倒です。代わりにptrace()システムコールを使用できます。見る man ptrace
詳細については。