加速文件I/O:mmap()与read()

Bil*_* N. 44 c c++ file-io mmap

我有一个Linux应用程序,并行读取150-200个文件(4-10GB).每个文件依次以小的,可变大小的块读取,每个块通常小于2K.

我目前需要从文件集中保持超过200 MB/s的读取速率.磁盘处理这个很好.预计需要超过1 GB/s(目前不在磁盘范围内).

我们已经实现了两个不同的读取系统,它们都大量使用posix_advise:首先是mmaped读取,其中我们映射整个数据集并按需读取.第二个是基于read()/ seek()的系统.

两者都运行良好但仅适用于中等情况,该read()方法更好地管理我们的整体文件缓存并且可以很好地处理100 GB的文件,但是速率受限,mmap能够预先缓存数据使得持续数据速率超过200MB/s易于维护,但无法处理较大的总数据集大小.

所以我的问题来自于:

答:可以在Linux read()posix_advise调用之外进一步优化类型文件i/o ,或者调整磁盘调度程序,VMM和posix_advise调用是否符合我们的预期?

B:有没有系统的方法让mmap更好地处理非常大的映射数据?

Mmap-vs-reading-blocks 与我正在工作的问题类似,并且提供了一个关于这个问题的良好起点,以及mmap-vs-read中的讨论.

Mat*_*ner 14

回读一下?这些数据的最终目的地是什么?

因为它听起来像你完全是IO绑定,mmap并且read应该没有区别.有趣的部分是如何将数据传输到接收器.

假设您将此数据放入管道,我建议您将每个文件的内容全部转储到管道中.要使用零拷贝执行此操作,请尝试splice系统调用.您也可以尝试手动复制文件,或者cat使用当前文件作为stdin并且将管道作为stdout强制缓冲的实例或其他工具.

if (pid = fork()) {
    waitpid(pid, ...);
} else {
    dup2(dest, 1);
    dup2(source, 0);
    execlp("cat", "cat");
}
Run Code Online (Sandbox Code Playgroud)

Update0

如果您的处理与文件无关,并且不需要随机访问,则需要使用上面列出的选项创建管道.您的处理步骤应接受来自stdin或管道的数据.

要回答您更具体的问题:

答:可以读取()类型文件i/o除了在Linux上的posix_advise调用之外进一步优化,或者调整了磁盘调度程序,VMM和posix_advise调用是否达到了我们的预期效果?

就告诉内核从用户空间做什么而言,这是一样好的.剩下的由您自己决定:缓冲,线程等等,但它是危险的,可能是非生产性的猜测工作.我只是把文件拼接成一个管道.

B:有没有系统的方法让mmap更好地处理非常大的映射数据?

是.在下面的选项可能会给你真棒性能优势(而且可能使MMAP值得使用比读,以测试):

  • MAP_HUGETLB 使用"大页面"分配映射.

    这将减少内核中的分页开销,如果您要映射千兆字节大小的文件,这将是很好的.

  • MAP_NORESERVE 不要为此映射保留交换空间.保留交换空间时,可以保证可以修改映射.如果没有保留交换空间,如果没有可用的物理内存,则可能在写入时获得SIGSEGV.

    如果实际上没有足够的物理内存+交换来完成整个映射,这将防止内存不足,同时保持实现简单.**

  • MAP_POPULATE 填充(prefault)页表以进行映射.对于文件映射,这会导致对文件进行预读.以后访问映射不会被页面错误阻止.

    这可能会为您提供足够的硬件资源,并且如果预订是有序的,则是懒惰的.我怀疑这个标志是多余的,VFS默认情况下可能做得更好.


Bas*_*tch 4

如果您的程序可以提前预测它想要读取的文件片段,那么使用预读系统调用可能会有所帮助(但这只是一个猜测,我可能是错的)。

我认为你应该调整你的应用程序,甚至你的算法,以读取比几千字节大得多的数据块。不能是半兆字节吗?