我希望能够在不调用任何io的情况下将文件内存映射范围归零(以便有效地顺序覆盖大文件而不会引起任何磁盘io读取)。

即使未覆盖整个页面,执行std::memset(ptr, 0, length)也会导致从磁盘读取页面,即使整个页面都被覆盖,也因此完全破坏了磁盘性能。

我希望能够执行类似madvise(ptr, length, MADV_ZERO)的操作,该操作将范围调零(类似于 FALLOC_FL_ZERO_RANGE ),以便在访问指定范围时引起零填充页面错误,而不是常规的io页面错误。

不幸的是MADV_ZERO不存在。即使对应的标记 FALLOC_FL_ZERO_RANGE 确实存在于 fallocate 中,并且可以与fwrite一起使用以实现类似的效果,尽管没有即时的跨进程一致性。

我猜一个可能的替代方法是使用 MADV_REMOVE 。但是,根据我的理解,这可能会导致文件碎片,并在完成时阻止其他操作,这使我不确定其对长期性能的影响。我在Windows上的经验是,调用类似的 FSCTL_SET_ZERO_DATA 命令可能会导致性能大幅提高。

我的问题是,最好在用户模式下,如何实现或仿真用于共享映射的MADV_ZERO

1. /dev/zero/

我已经读过它是从suggested,只需将/dev/zero读入所选范围即可。尽管我不太确定“读入范围”是什么意思以及如何去做。就像是从fread进入内存范围的/dev/zero一样吗?不确定如何避免访问时出现常规页面错误?



编辑:在线程后further有点,它实际上将无法正常工作。



2. MADV_REMOVE

在Linux(不是我希望在用户应用程序中)上实现它的一种猜测可能是通过简单地复制和修改MADV_REMOVE,即 madvise_remove 使用 FALLOC_FL_ZERO_RANGE 而不是 FALLOC_FL_PUNCH_HOLE 来实现的。尽管我对此感到有些困惑,但特别是因为我不太了解vfs_allocate周围的代码在做什么:

// madvice.c
static long madvise_remove(...)
  ...
  /*
   * Filesystem's fallocate may need to take i_mutex.  We need to
   * explicitly grab a reference because the vma (and hence the
   * vma's reference to the file) can go away as soon as we drop
   * mmap_sem.
   */
  get_file(f); // Increment ref count.
  up_read(&current->mm->mmap_sem); // Release a read lock? Why?
  error = vfs_fallocate(f,
            FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, // FALLOC_FL_ZERO_RANGE?
            offset, end - start);
  fput(f); // Decrement ref count.
  down_read(&current->mm->mmap_sem); // Acquire read lock. Why?
  return error;
}

最佳答案

您可能无法做您想做的事情(在用户空间中,如果不破解内核)。请注意,由于page cache,写入零页可能不会招致物理磁盘IO。

您可能想要用sparse file中的文件孔替换文件段(但这并不是您想要的),但是某些文件系统(例如VFAT)没有孔或稀疏文件。参见lseek(2)SEEK_HOLEftruncate(2)

关于c - 如何实现或仿真MADV_ZERO?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32321604/

10-16 20:40