24

我有几个关于mmapLinux 系统中的实现的问题,这些问题似乎没有太多记录:

使用 将文件映射到内存mmap时,您将如何处理预取此类文件中的数据?

即当您从映射区域读取数据时会发生什么?该数据是否已移至 L1/L2 缓存?它是直接从磁盘缓存中读取的吗?prefetchnta和类似的 ASM 指令是否适用于mmaped 区域?

实际mmap调用的开销是多少?它是相对于映射数据的数量还是常数?

希望有人对此有所了解。提前致谢。

4

4 回答 4

31

mmap 基本上是对虚拟内存子系统的编程访问。

例如,当您拥有 1G 文件并对其进行 mmap 映射时,您会得到一个指向“整个”文件的指针,就好像它在内存中一样。

但是,在这个阶段,除了为 VM 中的文件保留页面的实际映射操作之外,什么都没有发生。(当然,文件越大,映射操作的时间越长。)

为了开始从文件中读取数据,您只需通过 mmap 调用中返回的指针访问它。

如果您希望“预加载”文件的某些部分,只需访问您要预加载的区域。确保您访问了所有要加载的页面,因为 VM 只会加载您访问的页面。例如,假设在您的 1G 文件中,您有一个 10MB 的“索引”区域,您想在其中映射。最简单的方法是“遍历您的索引”或您拥有的任何数据结构,让 VM 页面根据需要在数据中。或者,如果您“知道”它是文件的“前 10MB”,并且您的 VM 的页面大小是 4K,那么您可以将 mmap 指针转换为 char 指针,然后遍历页。

void load_mmap(char *mmapPtr) {
    // We'll load 10MB of data from mmap
    int offset = 0;
    for(int offset = 0; offset < 10 * 1024 * 1024; offset += 4 * 1024) {
        char *p = mmapPtr + offset;
        // deref pointer to force mmap load
        char c = *p;
    }
}

至于 L1 和 L2 缓存,mmap 与此无关,这完全与您如何访问数据有关。

由于您使用的是底层 VM 系统,因此任何在 mmap'd 块中寻址数据的东西都可以工作(从汇编中)。

如果您不更改任何 mmap 数据,VM 将在需要新页面时自动清除旧页面。如果您确实更改了它们,那么 VM 将为您写回这些页面。

于 2009-04-15T15:34:08.987 回答
4

这与 CPU 缓存无关;它将它映射到虚拟地址空间,如果它随后被访问,或者被 mlock() 锁定,那么它将物理地带入内存。它在什么 CPU 缓存中或不在什么缓存中,你真的无法控制(至少,不是通过 mmap)。

通常需要触摸页面才能使其被映射,但如果您执行 mlock 或 mlockall,则会产生相同的效果(这些通常是特权)。

就开销而言,我真的不知道,你必须测量它。我的猜测是,不加载页面的 mmap() 或多或少是一个恒定的时间操作,但是随着页面的增加,将页面引入需要更长的时间。

最近版本的 Linux 还支持一个标志 MAP_POPULATE,它指示 mmap 立即加载页面(大概只有在可能的情况下)

于 2009-04-15T19:16:36.860 回答
2

回答 Ravi Phulsundar 先生的问题:

只要权限设置正确,多个进程可以映射同一个文件。查看 mmap 手册页只需传递MAP_SHARED标志(如果您需要映射一个非常大的文件,请使用 mmap2 代替):

地图

MAP_SHARED

与映射此对象的所有其他进程共享此映射。存储到区域相当于写入文件。在调用 msync(2) 或 munmap(2) 之前,该文件实际上可能不会被更新。

于 2009-04-30T09:48:44.013 回答
0

你使用 MAP_SHARED

于 2010-11-17T01:35:07.653 回答