【发布时间】:2015-11-26 02:23:08
【问题描述】:
我希望能够在不调用任何 io 的情况下将文件内存映射范围归零(以便有效地顺序覆盖大文件而不会导致任何磁盘读取 io)。
执行std::memset(ptr, 0, length) 将导致从磁盘中读取尚未在内存中的页面,即使整个页面都被覆盖,从而完全破坏磁盘性能。
我希望能够执行madvise(ptr, length, MADV_ZERO) 之类的操作,它将范围归零(类似于FALLOC_FL_ZERO_RANGE),以便在访问指定范围时导致零填充页面错误而不是常规的io 页面错误。
很遗憾MADV_ZERO 不存在。尽管fallocate 中确实存在相应的标志FALLOC_FL_ZERO_RANGE,并且可以与fwrite 一起使用以达到类似的效果,但没有即时的跨进程一致性。
我猜一个可能的替代方案是使用MADV_REMOVE。但是,据我了解,这可能会导致文件碎片并在完成时阻止其他操作,这使我不确定其长期性能影响。我使用 Windows 的经验是,类似的 FSCTL_SET_ZERO_DATA 命令在调用时会导致显着的性能峰值。
我的问题是如何为共享映射实现或模拟MADV_ZERO,最好是在用户模式下?
1。 /dev/zero/
我已将其读取为 suggested,以 只需将 /dev/zero 读入所选范围。虽然我不太确定“读入范围”是什么意思以及如何去做。是不是就像从/dev/zero 进入内存范围的fread?不确定如何避免访问时出现常规页面错误?
对于 Linux,只需将
/dev/zero读入所选范围即可。这 内核已经针对匿名映射优化了这种情况。如果一般来说执行起来太难了,我
建议 MADV_ZERO 应该有这样的效果:和阅读一模一样
/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;
}
【问题讨论】:
-
很可能“只需将
/dev/zero读入选定范围”指的是following technique seen inshmem_zero_setup()within the Linux kernel。 -
@TheCodeArtist:不太清楚该怎么做...
-
从
do_mmap_pgoff()和flags = MAP_ANONYMOUS | MAP_SHARED | MAP_NORESERVE开始,然后按照代码路径直到shmem_zero_setup()以获得完整的图片。对于匿名映射,在没有文件支持的情况下,最初使用零页来优化读取。当然,这不是解决您问题的方法。它只是一个正确实现的示例,如果您想自己在内核中实现建议,可以参考它。 -
另一方面,如果你要将固定模式的块写入磁盘(即长零序列),为什么不打开
O_DIRECT | O_WRONLY、lseek()中的文件文件到适当的偏移量并简单地转储大块(磁盘块大小的倍数),直到len字节数被清零。显然这是works with a couple of alignment and offset restrictions onmmap()。你怎么看?... -
持久的IPC带回了一些昔日的美好回忆。我以完全相同的意图在玩 mmap-ed 文件。我使用 inotify 来监控 文件支持的“共享内存”。因为没有equivalent to
sync()that i could call to trigger a "inotification", i wrote one。 :P 在我的设计中,writer 线程将更新内存映射共享文件中的所有相关字段,最后触发一个msync(),reader 线程在该msync()上( s) 使用 inotify 等待将被解除阻塞。希望对您有所帮助...
标签: c linux shared-memory mmap fallocate