0

Linux でディスクの使用状況を監視するために、yat (yet-another-tool :)) を作成しています。私はpython 3.3.2psutil 3.3.0を使用しています。

私が監視しているプロセスは、非常に基本的なことを行います。dd ツールを使用しブロックサイズを変更します(128、512、1024、4096)。

#!/bin/bash
dd if=./bigfile.txt of=./copy.img bs=4096

bigfile.txt:

$ stat bigfile.txt 
     File: ‘bigfile.txt’
     Size: 87851423     Blocks: 171600     IO Block: 4096   regular file

また、モニターのスニペットは次のとおりです。

def poll(interval, proc):
    d_before = proc.io_counters()
    time.sleep(interval)
    tst = time.time()
    d_after = proc.io_counters()

    usage = OrderedDict.fromkeys(d_after.__dict__.keys())
    for k, v in usage.items():
        usage[k] = d_after.__dict__[k] - d_before.__dict__[k]

    return tst, usage

実行するたびに、キャッシュをクリアします (stackoverflow で何度も提案されているように)。

rm copy.img && sudo sh -c "echo 3 > /proc/sys/vm/drop_caches"

私の質問は: 数字が一致しないのはなぜですか?

bs=128 :

日:

686339+1 records in
686339+1 records out
87851423 bytes (88 MB) copied, 1.21664 s, 72.2 MB/s

モニター.py:

1450778750.104943 OrderedDict([('read_count', 686352), ('write_count', 686343), ('read_bytes', 87920640), ('write_bytes', 87855104)])

bs=4096

日:

21448+1 records in
21448+1 records out
87851423 bytes (88 MB) copied, 0.223911 s, 392 MB/s

モニター.py:

1450779294.5541275 OrderedDict([('read_count', 21468), ('write_count', 21452), ('read_bytes', 88252416), ('write_bytes', 87855104)])

bsのすべての値にまだ違いがあります。

特定の読み取り/書き込みがカウントされないという問題ですか? psutil は追加の作業を実行しますか? たとえば、bs=4096の場合、psutil で 400993 バイト (読み取り用) と 3681 (書き込み用) が報告されるのはなぜですか?

私は何か大きなものを見逃していますか?

どうもありがとう。

EDIT : 更新として、測定のタイミングの粒度、つまり time.sleep(interval) 呼び出しは関係ありません。さまざまな値を試し、psutil によって報告された読み取りと書き込みの合計数を合計しました。違いは残ります。

EDIT2:スニペットコードのタイプミス

4

1 に答える 1

3

write_bytes

read_bytesとはのwrite_bytes同じフィールドに対応します/proc/<PID>/ioドキュメントの引用(強調鉱山):

read_bytes
----------

I/O カウンター: 読み取りバイト数このプロセスが実際に引き起こしたバイト数
を数えてみます。
ストレージ層からフェッチされます。submit_bio() レベルで行われるので、
ブロックでバックアップされたファイルシステムに対して正確です。


write_bytes
-----------

I/O カウンター: 書き込まれたバイト数このプロセスによって送信されたバイト数の
カウントを試みます
ストレージ層。これはページダーティ時に行われます。

ご存じのとおり、ほとんどの (すべて?) ファイルシステムはブロックベースです。これは、たとえばファイルに 5 バイトだけを書き込むプログラムがある場合、ブロック サイズが 4 KiB の場合、4 KiB が書き込まれることを意味します。

を信頼できない場合はdd、簡単な Python スクリプトを試してみましょう。

with open('something', 'wb') as f:
    f.write(b'12345')
input('press Enter to exit')

このスクリプトは 5 バイトしか書き込まないはずですが、 を調べる/proc/<PID>/ioと、4 KiB が書き込まれていることがわかります。

$ 猫/proc/3455/io
rchar: 215317
wchar: 24
syscr: 66
システム: 2
read_bytes: 0
write_bytes: 4096
キャンセルされた_書き込み_バイト: 0

ddこれは、あなたのケースで起こっていることと同じです。

dd87851423 バイトの書き込みを要求しました。87851423 バイトは 4 KiB ブロックの何個ですか?

87851423 - (87851423 mod 4096) + 4096 = 87855104

87855104 が psutil によって報告される数値であることは偶然ではありません。

read_bytes

どうread_bytesですか?read_bytes理論上はと等しいはずですがwrite_bytes、実際にread_bytesは最初の実行で 16 個のブロックが追加され、2 回目の実行で 97 個のブロックが追加されています。

まず、dd実際にどのファイルが読み取られているかを見てみましょう。

$ strace -e trace=open,read -- dd if=/dev/zero of=zero bs=1M count=2
 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`\v\ 2\0\0\0\0\0"..., 832) = 832
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
open("/dev/zero", O_RDONLY) = 3
オープン (「ゼロ」、O_WRONLY|O_CREAT|O_TRUNC、0666) = 3
read(0, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ 0\0\0\0\0\0\0\0\0\0"..., 1048576) = 1048576
read(0, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ 0\0\0\0\0\0\0\0\0\0"..., 1048576) = 1048576
open("/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 0
read(0, "# ロケール名エイリアス データベース。\n#"..., 4096) = 2570
読み取り (0、""、4096) = 0
open("/usr/share/locale/en_US/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (そのようなファイルまたはディレクトリはありません)
open("/usr/share/locale/en/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (そのようなファイルやディレクトリはありません)
open("/usr/share/locale-langpack/en_US/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (そのようなファイルやディレクトリはありません)
open("/usr/share/locale-langpack/en/LC_MESSAGES/coreutils.mo", O_RDONLY) = 0
+++ は 0 +++ で終了しました

ご覧のとおりdd、リンカー、GNU C ライブラリ、およびロケール ファイルを開いて読み取ります。mmapだけでなくも使用しているため、上記よりも多くのバイトを読み取っていますread

要点はdd、ソース ファイルよりも多くのファイルを読み取るため、read_bytesが よりもはるかに大きいことは許容されwrite_bytesます。しかし、なぜ矛盾しているのでしょうか。

によって読み取られるこれらのファイルは、dd他の多くのプログラムでも使用されます。を実行するdrop_caches直前ddであっても、他のプロセスがこれらのファイルの 1 つをメモリにリロードする可能性があります。この非常に単純な C プログラムで試すことができます。

int main()
{
    while(1) {
    }
}

デフォルトの GCC オプションでコンパイルされたこのプログラムは、リンカと GNU C ライブラリを開く以外は何もしません。drop_cachesプログラムをcat /proc/<PID>/IO複数回実行しようとすると、実行read_bytesごとに変化することがわかります (手順を非常に高速に実行する場合を除きます。この場合、他のプログラムが一部のファイルをキャッシュにロードした可能性は低くなります)。 )。

于 2015-12-26T10:28:30.850 に答える