【问题标题】:Reading binary files, Linux Buffer Cache读取二进制文件,Linux Buffer Cache
【发布时间】:2009-08-10 13:15:41
【问题描述】:

我正忙着写一些东西来测试 Linux 上磁盘 IO 的读取速度。

目前我有这样的东西来读取文件:

编辑将代码更改为:

  const int segsize = 1048576;
  char buffer[segsize];
  ifstream file;
  file.open(sFile.c_str());
  while(file.readsome(buffer,segsize)) {}

对于 150GB 的 foo.dat,我第一次读入它大约需要 2 分钟。 但是,如果我在第一次运行后 60 秒内运行它,则运行大约需要 3 秒。这怎么可能?当然,唯一可以这么快读取的地方是 RAM 中的缓冲区缓存,而文件太大而无法放入 RAM。

这台机器有 50GB 的内存,驱动器是一个 NFS 挂载,所有默认设置。请让我知道我在哪里可以确认这个文件实际上是以这种速度被读取的?我的代码错了吗?第一次读取文件时似乎花费了正确的时间。

编辑添加: 发现我的文件只读取到一个随机点。我设法通过将 segsize 从 1048576 更改为 1024 来解决此问题。我不知道为什么更改此设置允许 ifstream 读取整个文件而不是在随机点停止。

感谢您的回答。

【问题讨论】:

  • 为什么你认为整个文件必须适合缓存?
  • 第一次读取文件时,几乎完全是IO绑定,130s WALL,3s CPU,第二次读取文件时,CPU和WALL时间几乎一模一样,表示足够接近没有 IO。

标签: c++ linux io


【解决方案1】:

在 Linux 上,您可以这样做以进行快速吞吐量测试:

$ dd if=/dev/md0 of=/dev/null bs=1M count=200
200+0 records in
200+0 records out
209715200 bytes (210 MB) copied, 0.863904 s, 243 MB/s

$ dd if=/dev/md0 of=/dev/null bs=1M count=200
200+0 records in
200+0 records out
209715200 bytes (210 MB) copied, 0.0748273 s, 2.8 GB/s

$ sync && echo 3 > /proc/sys/vm/drop_caches

$ dd if=/dev/md0 of=/dev/null bs=1M count=200
200+0 records in
200+0 records out
209715200 bytes (210 MB) copied, 0.919688 s, 228 MB/s

echo 3 > /proc/sys/vm/drop_caches 会正确刷新缓存

【讨论】:

  • 请注意,如果数据没有被修改,那么在删除缓存之前同步并不是绝对必要的 - drop_caches 不会删除脏(或映射)数据。
  • 请注意,这需要超级用户权限。
【解决方案2】:
  • in_avail 不给出文件的长度,而是给出可用内容的下限(特别是如果缓冲区已被使用,它会返回缓冲区中可用的大小)。它的目标是在不阻塞的情况下知道可以读取的内容。

  • unsigned int 很可能无法容纳超过 4GB 的长度,因此读取的内容很可能在缓存中。

  • 如果您使用大文件,C++0x Stream Positioning 可能会引起您的兴趣

【讨论】:

  • 嗨,关于 unsigned int 的要点。我已经编辑了我的代码以反映您所说的内容。我仍然遇到同样的问题。事实上,我还编写了一个 perl 脚本,它只读取整个文件并获得相似(两个部分都较慢)的结果。第一次运行仍然超过 2 分钟,第二次运行 3 秒。
【解决方案3】:

in_avail 返回流读取缓冲区中可读取的下限,而不是文件的大小。要通过流读取整个文件,只需保持 调用流的 readsome() 方法并检查使用 gcount() 方法读取了多少 - 当它返回零时,您已经读取了所有内容。

【讨论】:

  • 如果 showmanyc()(如果缓冲区为空,则为 in_avail 调用的虚拟成员)返回 0,该算法将停止。但 showmanyc() 可以在不到达文件末尾的情况下返回 0。 (Linux 版本的 filebuf 返回文件大小,Solaris 和 AIX 返回 0)
【解决方案4】:

第一次读取文件时似乎花费了正确的时间。

在第一次读取时,您在大约 2 分钟内读取了 150GB。这相当于每秒大约 10 吉比特。这是您所期望的(基于您的 NFS 挂载的网络)吗?

【讨论】:

  • 事实证明这是正确的答案,之所以有这种差异是因为我正在阅读的所有内容都将其放入缓存中。问题是我没有将“所有内容”读入缓存。例如,在读取 10gb 文件时。我读取大小并将 .readsome() 读取的所有内容加起来,我得到了很大的不同。 Size = 10819423232 Read = 2229490000 有人知道为什么 readsome() 会提前停止吗?
  • 理智地检查你的数字总是好的。您是否需要编写自己的程序来执行此操作?如果我想测量读取 1MB 块中的大文件的时间,我会使用 dd...
【解决方案5】:

一种可能性是文件可能至少部分稀疏。稀疏文件具有真正为空的区域——它们甚至没有分配给它们的磁盘空间。这些稀疏区域也不会消耗太多缓存空间,因此读取稀疏区域基本上只需要时间将它们正在读入的用户空间页面清零。

您可以通过ls -lsh 查询。第一列将是磁盘大小 - 如果它小于文件大小,则文件确实是稀疏的。要对文件进行去稀疏化,只需写入文件的每一页即可。

如果您想测试真实的磁盘速度,一种选择是使用 open(2) 的 O_DIRECT 标志来绕过缓存。请注意,所有使用 O_DIRECT 的 IO 都必须是页面对齐的,并且某些文件系统不支持它(特别是它不能在 NFS 上工作)。此外,除了基准测试之外,这对其他任何事情都是一个坏主意。在 this thread 中查看 Linus 的一些咆哮。

最后,要删除 linux 系统上的所有缓存进行测试,您可以这样做:

echo 3 > /proc/sys/vm/drop_caches

如果您在客户端和服务器上都这样做,您将强制文件内存不足。当然,这会对当时运行的其他任何东西产生负面的性能影响。

【讨论】:

    猜你喜欢
    • 2017-10-11
    • 1970-01-01
    • 1970-01-01
    • 2011-05-04
    • 2017-10-01
    • 2011-09-03
    • 2016-01-15
    • 1970-01-01
    相关资源
    最近更新 更多