20

现代 x86 CPU 能够支持比传统 4K 更大的页面大小(即 2MB 或 4MB),并且有操作系统工具(LinuxWindows)可以访问此功能。

上面的微软链接指出大页面“提高了翻译缓冲区的效率,这可以提高频繁访问的内存的性能”。这对于预测大页面是否会改善任何给定情况并不是很有帮助。我对移动一些程序逻辑(或整个应用程序)以使用大页面导致一些性能改进的具体的、最好是量化的示例感兴趣。有人有成功案例吗?

我自己知道一个特殊情况:使用大页面可以显着减少分叉大型进程所需的时间(大概是因为需要复制的 TLB 记录的数量减少了大约 1000 倍)。我感兴趣的是大页面是否也可以在不那么奇特的场景中带来好处。

4

5 回答 5

18

当您对大内存区域进行大间隔随机访问时,性能的最大差异将出现——其中“大”意味着比 TLB 中所有小页面条目可以映射的范围大得多(通常在现代处理器中具有多个级别)。

更复杂的是,4kB 页面的 TLB 条目数通常大于 2MB 页面的条目数,但这因处理器而异。2 级 TLB 中可用的“大页面”条目的数量也有很多变化。

例如,在 AMD Opteron Family 10h Revision D(“Istanbul”)系统上,cpuid 报告:

  • L1 DTLB:4kB 页面:48 个条目;2MB 页面:48 个条目;1GB 页面:48 个条目
  • L2 TLB:4kB 页面:512 个条目;2MB 页面:128 个条目;1GB 页面:16 个条目

在 Intel Xeon 56xx(“Westmere”)系统上,cpuid 报告:

  • L1 DTLB:4kB 页面:64 个条目;2MB 页面:32 个条目
  • L2 TLB:4kB 页面:512 个条目;2MB 页面:无

两者都可以在遭受 2 级 TLB 未命中之前使用小页面映射 2MB (512*4kB),而 Westmere 系统可以使用其 32 个 2MB TLB 条目映射 64MB,而 AMD 系统可以使用其 L1 和 L2 中的 176 个 2MB TLB 条目映射 352MB TLB。通过使用大页面对远大于 2MB 且小于 64MB 的内存范围进行随机访问,这两种系统都将获得显着的加速。AMD 系统应该继续显示使用大页面来获得更大内存范围的良好性能。

在所有这些情况下,您要避免的是遍历 x86_64 分层地址转换的所有四个级别的最坏情况(注 1)。
如果地址转换缓存机制(注 2)都不起作用,则需要:

  • 5 次访问内存以加载映射在 4kB 页面上的数据,
  • 4 次访问内存以加载映射在 2MB 页面上的数据,以及
  • 3 次访问内存以加载映射在 1GB 页面上的数据。

在每种情况下,最后一次内存行程是为了获取请求的数据,而其他行程则需要获取页面翻译信息的各个部分。我见过的最好的描述是在 AMD 的“AMD64 架构程序员手册第 2 卷:系统编程”(出版物 24593)的第 5.3 节http://support.amd.com/us/Embedded_TechDocs/24593.pdf

注 1:上面的数字并不是最坏的情况。在虚拟机下运行会使这些数字变得更糟。在导致保存不同级别页表的内存被交换到磁盘的环境中运行会使性能变得更糟。

注 2:不幸的是,即使知道这一级别的细节还不够,因为所有现代处理器都有额外的缓存用于页面转换层次结构的上层。据我所知,这些在公共场合的记录非常差。

于 2012-03-12T21:20:05.067 回答
11

我试图设计一些代码来最大化 TLB 与 4k 页面的颠簸,以检查大页面的可能收益。当 libhugetlbfs 的 malloc (Intel i7, 64bit Debian Lenny) 提供 2MByte 页面时,以下内容的运行速度比 4K 页面快 2.6 倍;希望显而易见的是什么scoped_timerrandom0n做什么。

  volatile char force_result;

  const size_t mb=512;
  const size_t stride=4096;
  std::vector<char> src(mb<<20,0xff);
  std::vector<size_t> idx;
  for (size_t i=0;i<src.size();i+=stride) idx.push_back(i);
  random0n r0n(/*seed=*/23);
  std::random_shuffle(idx.begin(),idx.end(),r0n);

  {
    scoped_timer t
      ("TLB thrash random",mb/static_cast<float>(stride),"MegaAccess");
    char hash=0;
    for (size_t i=0;i<idx.size();++i) 
      hash=(hash^src[idx[i]]);
    force_result=hash;
  }

一个更简单的“直线”版本hash=hash^src[i]仅从大页面中获得 16%,但是(疯狂的猜测)当访问是可预测的时,英特尔的花哨的预取硬件可能有助于 4K 案例(我想我可以禁用预取来调查这是否属实)。

于 2010-05-21T18:43:03.887 回答
3

我已经看到一些 HPC/Grid 场景的改进——特别是物理包,在具有大量 RAM 的机器上具有非常非常大的模型。运行模型的进程也是机器上唯一活跃的东西。我怀疑,虽然没有测量,某些数据库功能(例如批量导入)也会受益。

就个人而言,我认为除非你有一个很好的分析/理解的内存访问配置文件并且它做了很多大的内存访问,否则你不太可能看到任何显着的改进。

于 2010-05-20T20:49:11.997 回答
3

这越来越深奥,但在进行 DMA 内存传输(通过 PCIe 从主机到 Phi)时,巨大的 TLB 页面对英特尔至强融核 (MIC) 架构产生了重大影响。此 Intel 链接描述了如何启用大页面。我发现在正常 TLB 页面大小 (4K) 的情况下,将 DMA 传输大小增加到 8 MB 以上会开始降低性能,一旦传输大小达到 512 MB,性能就会从大约 3 GB/s 降低到 1 GB/s 以下。

在启用巨大的 TLB 页面 (2MB) 后,对于 512 MB 的 DMA 传输,数据速率继续增加到超过 5 GB/s。

于 2014-10-15T23:46:30.420 回答
2

我在运行大进程的大量内存 (>=64GB) 的服务器上获得了约 5% 的加速。例如,对于一个 16GB 的 java 进程,这是 4M x 4kB 页面,但只有 4k x 4MB 页面。

于 2010-05-21T07:23:01.737 回答