我写了一个关于fwrite和mmap的比较的本科论文(“一项实验,以测量传统I/O和内存映射文件之间的性能折衷”)。首先,对于写入操作,你不必使用内存映射文件,特别是对于大文件。fwrite是完全可以的,并且几乎总是优于使用mmap的方法。mmap将为并行数据读取提供最大的性能提升;对于顺序数据写入,你真正受到的限制是硬件。
在我的示例中,
remapSize
是文件的初始大小,并且文件每次重新映射时增加的大小。
fileSize
跟踪文件的大小,
mappedSpace
表示当前mmap的大小(长度),
alreadyWrittenBytes
是已经写入文件的字节数。
下面是示例初始化代码:
void init() {
fileDescriptor = open(outputPath, O_RDWR | O_CREAT | O_TRUNC, (mode_t) 0600);
result = ftruncate(fileDescriptor, remapSize);
fsync(fileDescriptor);
memoryMappedFile = (char*) mmap64(0, remapSize, PROT_WRITE, MAP_SHARED, fileDescriptor, 0);
fileSize = remapSize;
mappedSpace = remapSize;
}
广告问题1:
我使用了一个“取消映射-重映射”机制。
取消映射
- 首先刷新(
msync
)
- 然后取消映射内存映射文件。
这可能看起来像下面这样:
void unmap() {
msync(memoryMappedFile, mappedSpace, MS_SYNC);
munmap(memoryMappedFile, mappedSpace)
}
对于Remap,您可以选择重新映射整个文件或仅重新映射新增的部分。
Remap基本上会:
重新映射整个文件的示例实现:
void fullRemap() {
ftruncate(fileDescriptor, mappedSpace + remapSize);
fsync(fileDescriptor);
memoryMappedFile = (char*) mmap64(0, mappedSpace + remapSize, PROT_WRITE, MAP_SHARED, fileDescriptor, 0);
fileSize += reampSize;
mappedSpace += remapSize;
}
小型remap的示例实现:
void smallRemap() {
ftruncate(fileDescriptor, fileSize + remapSize); // Make file bigger
fsync(fileDescriptor); // Flush file
remapAt = alreadyWrittenBytes % pageSize == 0
? alreadyWrittenBytes
: alreadyWrittenBytes - (alreadyWrittenBytes % pageSize); // Adjust remap location to pagesize
memoryMappedFile = (char*) mmap64(0, fileSize + remapSize - remapAt, PROT_WRITE, MAP_SHARED, fileDescriptor, remapAt); // Create memory-map
fileSize += remapSize;
mappedSpace = fileSize - remapAt;
}
有一个名为mremap函数
的函数存在,但它声明:
该调用是特定于Linux的,不应在旨在可移植的程序中使用。
关于问题二:
我不确定我是否正确理解了这一点。如果您想要告诉内核“现在加载下一页”,那么不,这是不可能的(至少据我所知)。但请参阅问题3以了解如何向内核提供建议。
关于问题三:
您可以使用带有标志MADV_SEQUENTIAL
的madvise
,但请记住,这并不强制内核预读,而仅仅是给出建议。
来自man的摘录:
这可能会导致内核大量预读
个人结论:
不要使用mmap
进行顺序数据写入。这只会导致更多的开销,并且会比使用fwrite
的简单写入算法产生更多“不自然”的代码。
对于大文件的随机访问读取,请使用mmap
。
这也是我在我的论文中获得的结果。我无法通过使用mmap
进行顺序写入来实现任何加速,事实上,它总是比这个目的慢。
mmap
确实没有中间缓冲区,并直接按请求写入数据(write
等也是如此),这是用户空间API通常避免的。这也允许更少的系统调用,而系统调用的开销很大。 - edmzmmap
дёЋfwrite
以及write
的基准数据吗? - Andrew Henlemmap
与fwrite
进行了比较,包括并行化和侧载等进一步参数。然而,论文目前尚未完全完成和发表,因此我不确定是否可以在此时发布结果。 - Markus Weninger