我希望能够在不调用任何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(¤t->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(¤t->mm->mmap_sem); // Acquire read lock. Why?
return error;
}
最佳答案
您可能无法做您想做的事情(在用户空间中,如果不破解内核)。请注意,由于page cache,写入零页可能不会招致物理磁盘IO。
您可能想要用sparse file中的文件孔替换文件段(但这并不是您想要的),但是某些文件系统(例如VFAT)没有孔或稀疏文件。参见lseek(2)和SEEK_HOLE
,ftruncate(2)
关于c - 如何实现或仿真MADV_ZERO?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32321604/