使用MMU实现可调整大小的数组

时间:2017-01-06 03:23:26

标签: c++ list hardware-acceleration mmu

通常,列表既可以作为链接列表实现,也可以作为数组列表实现,这些列表在插入元素时很慢。

我想知道是否可以使用处理器的MMU更有效地实现列表,通过重新映射而不是在插入或删除元素时复制内存。这意味着数组中任何位置的索引和插入/删除都具有O(1),better than any other list implementation的速度。

我的问题是:

  • 程序是否实际上能够控制自己的虚拟内存,还是需要对操作系统进行更改?
  • 每个进程的页表条目数是否有限制?有更多条目,内存访问速度会变慢吗?
  • 更改页表条目的速度是否太慢,以至于仅对非常大的列表更有效?
  • 这种类型的列表是否存在任何实现?是的,是什么阻止人们更多地使用它们?

1 个答案:

答案 0 :(得分:19)

首先回答一些问题:

  • 是的,在许多操作系统上,程序可以显着控制其虚拟内存,例如,类似UNIX的操作系统上的mmap和Windows上的similar APIs。特别是Linux最近添加了several methods以允许从内核高级操作用户可见的缓冲区而无需复制 - 但其中一个有趣的是no longer for this world(至少在性能方面) 。
  • 通常,每个进程的页表条目数没有特定限制。当然,您可能会遇到其他限制,例如每进程内存限制,物理内存限制等。对于更多条目,访问内存通常不会变慢。当然,总共访问更多页面可能意味着访问速度较慢(例如,因为你超过了TLB的大小) - 但这并不直接是更多页面的功能。页表条目本身就位于RAM中,因此您可以拥有数百万条而没有问题。
  • 在现代操作系统上,更改页面表条目合理快。例如,在我的笔记本电脑上,更改页表条目似乎需要每页约120 ns(加上系统调用的一些固定开销)。
  • 是的,您可以在那里找到examples,但它们通常针对相当狭窄的情况。事实上,你可以看到马赫的libc试图使用MMU tricks来使用一个重要的例程than memcpy

讨论

使用MMU技巧的核心问题是(a)你只能“零复制”整个页面,这几乎意味着4K粒度或更大,以及类似的限制性对齐(b)即使{{1} } -type调用很快,高效的内存复制例程也是如此!

让我们首先看一下(a)。如果我理解正确,您希望通过使用MMU技巧来加速插入mmap之类的内容,以便在插入发生时移动需要移动的元素。问题是你只能在典型系统上移动0,4096,8192等字节!因此,如果您将一个4字节std::vector插入int,这有何帮助?您可以将vector<int>的底层存储分解为插入点处的两个部分并跟踪它,希望再次合并它们(例如,如果您插入4096字节的东西) - 但是你最终会得到一个不同的数据结构,具有不同的属性,而且无论如何MMU技巧都不是真正的基础。

这将我们带到(b)。理所当然地认为,在我的机器上,页面可以在~120 ns内重新映射(通过vector)。这看起来很快(当你考虑它涉及采用各种内核锁定,弄乱页面表,添加VMA等等时,它还不错) - 但复制内存非常快。在同一个盒子上,我可以以大约12 GB / s的速度复制内存中(即,往/来自任何缓存级别的RAM),而L1或L2中的副本可能以80-100 GB / s的速度复制。因此,复制4K页面需要介于41 ns(缓存)和340 ns(未缓存,RAM)之间。所以搞乱页面表并不是一个明确的胜利,即使它可能可能,特别是在缓存的情况下(缓存的情况可能是主导的情况,平均大多数工作负载)。

所以这些类型的技巧可能有意义,但仅限于特定情况,例如:

  • 您可以通过某种方式处理页面映射只能在页面粒度的块中移动/复制/移位的事实,例如,因为您的结构恰好是页面粒度的倍数,或者您使用批量插入是页面粒度等的倍数。
  • 您可以通过某种方式更快地映射页面:例如,使用2MB页面而不是4K页面,或者编写一些加速用例的内核端代码。
  • 你想要使用更简单的技巧,而不仅仅是移动内存,例如。使相同的数据同时出现在两个地方,实现COW结构,或类似的东西。

的realloc

MMU技巧的最常见且最有用的示例可能是mmap。在Linux和Windows(it seems?)上,realloc可以通过重新映射和扩展内存中的映射页面(也称为MMU技巧)来实现,这既避免了物理复制又需要暂时同时使用旧的分配区域和新区域立即“实时”(如果它们的总和接近物理内存的大小,则可能很难)。

特别是,最新版本的Linux可能会首先使用mremapreallocrealloc的堆区域(默认情况下,这种情况发生在大于128K的分配请求中,但当mmap的可用空间用尽时,也可能发生这种情况。