gpt4 book ai didi

c - `mmap()` 手动并发预故障/分页

转载 作者:太空狗 更新时间:2023-10-29 12:10:00 24 4
gpt4 key购买 nike

我正在尝试微调 mmap() 以对可能非常大的文件执行快速写入或读取(通常不是两者)。写入和读取在一次通过时大部分将是连续的,然后在以后的通过中可能非常稀疏。不需要多次访问内存区域。

换句话说,可以将其视为具有一些异步修复的损失的文件传输。

正如预期的那样,mmap() 性能的主要限制似乎是它在大文件上生成的次要页面错误的数量。此外,我怀疑 Linux 内核页面到磁盘的惰性导致了一些性能问题。即,任何最终对 mmaped 内存执行大量写入的测试程序在执行所有写入以终止/munmap 内存后似乎需要很长时间。

我希望通过在执行几乎顺序的访问和调出不再需要的页面的同时对页面进行预故障来抵消这些错误的成本。但我对这种方法和我对该问题的理解有三个主要问题:

  1. 是否有一种直接的(最好是 POSIX [或至少 OSX] 兼容的)方法来执行部分预故障?我知道 MAP_POPULATE 标志,但这似乎试图将整个文件加载到内存中,这在许多情况下是无法容忍的。此外,这似乎会导致 mmap() 调用阻塞,直到预故障完成,这也是无法容忍的。我对手动替代方案的想法是生成一个线程,以尝试读取内存中的下一个 N 页以强制进行预取。但实际上,带有 MADV_SEQUENTIALmadvise 可能已经这样做了。
  2. msync() 可用于将更改刷新到磁盘。然而,定期这样做真的有用吗?我的想法是,如果程序经常处于磁盘 IO 的“空闲”状态并且能够承受一些磁盘写回,它可能会有用。话又说回来,内核很可能比以往的应用程序更好地处理它。
  3. 我对磁盘 IO 的理解准确吗?我的假设是预故障和读/写页面可以由不同的线程或进程同时完成;如果我错了,那么手动预故障根本就没有用。类似地,如果 msync() 调用阻塞了所有磁盘 IO,包括文件系统缓存和原始文件系统,那么使用它来刷新整个磁盘的动机也不大在程序终止时缓存。

最佳答案

It appears, as expected, that the main limitation of mmap()'s performance seems to be the number of minor page faults it generates on large files.

这并不特别令人惊讶,我同意。但这是无法避免的成本,至少对于与您实际访问的映射文件区域对应的页面而言。

Furthermore, I suspect the laziness of the Linux kernel's page-to-disk is causing some performance issues. Namely, any test programs that end up performing huge writes to mmaped memory seem to take a long time after performing all writes to terminate/munmap memory.

这是有道理的。同样,这是不可避免的成本,至少对于脏页而言是这样,但您可以对何时产生这些成本施加一些影响。

I was hoping to offset the cost of these faults by concurrently prefaulting pages while performing the almost-sequential access and paging out pages that I won't need again. But I have three main questions regarding this approach and my understanding of the problem:

  1. Is there a straightforward (preferably POSIX [or at least OSX] compatible) way of performing a partial prefault? I am aware of the MAP_POPULATE flag, but this seems to attempt loading the entire file into memory,

是的,这与其文档一致。

which is intolerable in many cases. Also, this seems to cause the mmap() call to block until prefaulting is complete,

这也是记录在案的。

which is also intolerable. My idea for a manual alternative was to spawn a thread simply to try reading the next N pages in memory to force a prefetch.

除非在您最初 mmap() 文件和您想要开始访问映射之间有延迟,否则我不清楚为什么您会期望它提供任何改进。

But it might be that madvise with MADV_SEQUENTIAL already does this, in effect.

如果您想要 POSIX 兼容性,那么您正在寻找 posix_madvise()。我确实建议使用此功能,而不是尝试推出您自己的用户空间替代方案。特别是,如果您使用 posix_madvise() 在部分或所有映射区域上断言 POSIX_MADV_SEQUENTIAL,那么有理由希望内核会提前读取以加载页面在需要它们之前。此外,如果您使用 POSIX_MADV_DONTNEED 建议,那么根据内核的判断,您可能会更早地同步到磁盘并减少整体内存使用。如果有用,您也可以通过此机制传递其他建议。

  1. msync() can be used to flush changes to the disk. However, is it actually useful to do this periodically? My idea is that it might be useful if the program is frequently in an "Idle" state of disk IO and can afford to squeeze in some disk writebacks. Then again, the kernel might very well be handling this itself better than the ever application could.

这是要测试的东西。但是请注意,msync() 支持异步 同步,因此您不需要 I/O 空闲。因此,当您确定已完成给定页面时,您可以考虑使用 msync() 标记 MS_ASYNC 来请求内核安排同步。这可能会减少取消映射文件时产生的延迟。您必须尝试将它与 posix_madvise(..., ..., POSIX_MADV_DONTNEED) 结合使用;它们可能会或可能不会相互补充。

  1. Is my understanding of disk IO accurate? My assumption is that prefaulting and reading/writing pages can be done concurrently by different threads or processes; if I am wrong about this, then manual prefaulting would not be useful at all.

一个线程应该有可能预置页面(通过访问它们),而另一个线程读取或写入其他已经出错的页面,但我不清楚为什么你期望这样一个预置线程能够提前运行做读写的人。如果它有任何影响(即如果内核不自行预故障)那么我预计预故障页面比读取或写入每个字节一次更昂贵。

Similarly, if an msync() call blocks all disk IO, both to the filesystem cache and to the raw filesystem, then there also isn't as much of an incentive to use it over flushing the entire disk cache at the program's termination.

代表您的程序需要执行的磁盘读取和写入次数最少。对于任何给定的映射文件,它们都将在同一 I/O 设备上执行,因此它们都将相对于彼此进行序列化。如果您受 I/O 限制,那么第一近似值是,执行这些 I/O 操作的顺序对整体运行时间无关紧要。

因此,如果运行时是您所关心的,那么 posix_madvise()msync() 可能都没有多大帮助,除非您的程序花费其运行时间的很大一部分是在独立于访问映射文件的任务上进行的。如果您确实发现自己并非完全受 I/O 限制,那么我的建议是先看看 posix_madvise() 能为您做什么,然后尝试异步 msync() 如果你需要更多。我倾向于怀疑用户空间预故障或同步 msync() 是否会带来胜利,但在优化中,测试总是比(仅)预测更好。

关于c - `mmap()` 手动并发预故障/分页,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47677137/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com