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

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

我目前需要保持超过200MB / s的读取速率,这些文件组合在一起。 磁盘处理这很好。 预计需求超过1 GB / s(目前超出磁盘范围)。

我们已经实现了两个不同的读取系统,都使用posix_advise :首先是一个mmap ed读取,我们映射整个数据集和按需阅读。 第二个是基于read() / seek()的系统。

这两个工作正常,但只适用于温和的情况下, read()方法更好地pipe理我们的整体文件caching,可以很好地处理100 GB的文件,但速度有限, mmap可以预caching数据,使持续数据速率超过200MB / s容易维护,但不能处理大的总数据集大小。

所以我的问题来到这些:

答:可以将read()types的文件I / O进一步优化,超出了Linux上的posix_advise调用,或者调整了磁盘调度程序,VMM和posix_advise调用是否如我们所期望的那样好?

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

Mmap-vs-reading-blocks与我正在工作的是类似的问题,并为此问题提供了一个很好的起点,以及mmap-vs-read中的讨论。

回读什么? 这个数据的最终目的是什么?

既然听起来你完全是IO界限, mmapread应该没什么区别。 有趣的部分在于如何将数据传送到接收器。

假设你把这些数据放在一个pipe道中,我build议你把每个文件的内容全部转储到pipe道中。 要使用零拷贝完成此操作,请尝试splice系统调用。 您也可以尝试手动复制文件,或者将cat的实例或其他可以缓冲大量当前文件的工具作为标准input,并将pipe道作为标准输出。

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

Update0

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

要回答你更具体的问题:

答:可以将read()types的文件I / O进一步优化,超出了Linux上的posix_advise调用,或者调整了磁盘调度程序,VMM和posix_advise调用是否如我们所期望的那样好?

就如何告诉内核从用户空间执行什么操作一样好。 其余的由你决定:缓冲,线程等,但这是危险的,可能是非生产性的猜测工作。 我只是把文件拼接成一个pipe道。

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

是。 下面的选项可能会给你带来令人惊叹的性能优势(并且可能使mmap值得使用超过阅读和testing):

  • MAP_HUGETLB使用“巨大页面”分配映射。

    这将减less内核中的分页开销,如果您将映射千兆字节大小的文件,这将是非常好的。

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

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

  • MAP_POPULATE填充(缺省)页面表的映射。 对于文件映射,这会导致文件上的预读。 以后访问映射不会被页面错误阻塞。

    这可能会给你提供足够的硬件资源,如果预取是有序的,而且是懒惰的。 我怀疑这个标志是多余的,VFS默认情况下可能会更好。

也许使用readahead系统调用可能会有帮助,如果你的程序可以预先预测它想要读取的文件片段(但这只是一个猜测,我可能是错的)。

而且我认为你应该调整你的应用程序,甚至是你的algorithm来读取大于几千字节的数据块。 不能超过半兆字节呢?

这里的问题似乎并不是使用哪个api。 使用mmap()或read()并不重要,光盘仍然需要查找指定的点并读取数据(尽pipeos有助于优化访问)。

如果读取非常小的块(几个字节),mmap()与read()相比具有优势,因为您没有为每个块调用os,从而变得非常缓慢。

我还build议像Basile那样连续读取2kb以上,这样光盘就不用经常去寻找了。