我正在写y.a.t. (还有另一个工具:))用于监视Linux上的磁盘使用情况。 我使用 python 3.3.2 和 psutil 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 :
DD
686339+1 records in
686339+1 records out
87851423 bytes (88 MB) copied, 1.21664 s, 72.2 MB/s
monitor.py:
1450778750.104943 OrderedDict([('read_count', 686352), ('write_count', 686343), ('read_bytes', 87920640), ('write_bytes', 87855104)])
BS = 4096
DD
21448+1 records in
21448+1 records out
87851423 bytes (88 MB) copied, 0.223911 s, 392 MB/s
monitor.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 :代码段中的拼写错误
答案 0 :(得分:2)
write_bytes
read_bytes
和write_bytes
对应/proc/<PID>/io
中的相同字段。引用documentation(强调我的):
read_bytes ---------- I/O counter: bytes read Attempt to count the number of bytes which this process really did cause to be fetched from the storage layer. Done at the submit_bio() level, so it is accurate for block-backed filesystems. write_bytes ----------- I/O counter: bytes written Attempt to count the number of bytes which this process caused to be sent to the storage layer. This is done at page-dirtying time.
如您所知,大多数(所有?)文件系统都是基于块的。这意味着如果你有一个程序,比如说,只向文件写入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:
$ cat /proc/3455/io rchar: 215317 wchar: 24 syscr: 66 syscw: 2 read_bytes: 0 write_bytes: 4096 cancelled_write_bytes: 0
这与你的dd
中的情况相同。
您已要求dd
写入87851423个字节。有多少4个KiB块是87851423个字节?
87851423 - (87851423 mod 4096) + 4096 = 87855104
不是偶然的87855104是psutil报告的数字。
read_bytes
read_bytes
怎么样?理论上我们应该read_bytes
等于write_bytes
,但实际上read_bytes
在第一次运行中显示16个块,在第二次运行中显示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\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 open("zero", 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\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\0"..., 1048576) = 1048576 open("/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 0 read(0, "# Locale name alias data base.\n#"..., 4096) = 2570 read(0, "", 4096) = 0 open("/usr/share/locale/en_US/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory) open("/usr/share/locale/en/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory) open("/usr/share/locale-langpack/en_US/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory) open("/usr/share/locale-langpack/en/LC_MESSAGES/coreutils.mo", O_RDONLY) = 0 +++ exited with 0 +++
如您所见,dd
正在打开并读取链接器,GNU C库和区域设置文件。它读取的字节数比您在上面看到的字节多,因为它还使用mmap
,而不只是read
。
重点是:dd
读取的文件比源文件多得多,因此read_bytes
远远高于write_bytes
。但为什么它不一致?
dd
读取的那些文件也被许多其他程序使用。即使您在执行drop_caches
之前dd
,也有可能某些其他进程可能会将其中一个文件重新加载到内存中。您可以尝试使用这个非常简单的C程序:
int main()
{
while(1) {
}
}
使用默认的GCC选项编译,除了打开链接器和GNU C库之外,该程序不执行任何操作。如果您尝试drop_caches
,多次执行该计划和cat /proc/<PID>/IO
,您会看到read_bytes
在不同的运行中会有所不同(除非您执行这些步骤非常快,在这种情况下某些其他程序将某些文件加载到缓存中的概率很低。