在什么情况下大页面可以产生加速?

时间:2010-05-20 17:42:17

标签: performance x86 virtual-memory tlb

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

上面的Microsoft链接声明大页面“提高了转换缓冲区的效率,这可以提高频繁访问的内存的性能”。这对于预测大页面是否会改善任何特定情况并不是很有帮助。我对具体的,最好是量化的例子感兴趣,其中一些程序逻辑(或整个应用程序)使用大页面导致一些性能改进。有人有任何成功的故事吗?

我知道myself有一个特殊情况:使用大页面可以dramatically减少分支大进程所需的时间(大概是因为需要复制的TLB记录数减少了一个因素1000)的顺序。我很感兴趣的是,在不那么奇特的场景中,大页面是否也会带来好处。

5 个答案:

答案 0 :(得分:16)

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

为了使事情变得更复杂,4kB页面的TLB条目数通常大于2MB页面的条目数,但这种情况因处理器而异。在Level 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系统可以使用其中的176个2MB TLB条目映射352MB L1和L2 TLB。通过在大于2MB且小于64MB的内存范围内使用大页面进行随机访问,系统将获得显着的加速。对于更大的内存范围,AMD系统应该继续使用大页面显示出良好的性能。

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

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

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

注1:上面的数字实际上不是最差的情况。在虚拟机下运行会使这些数字变得更糟。在导致将各种级别的页表交换到磁盘的内存的环境中运行会使性能更多更糟。

注2:不幸的是,即使知道这种详细程度也是不够的,因为所有现代处理器都有额外的缓存用于页面翻译层次结构的上层。据我所知,这些在公开场合很难记录。

答案 1 :(得分:10)

我尝试设计一些代码,这些代码可以最大化TLB与4k页面的颠簸,以便检查大页面可能获得的增益。当libhugetlbfs的malloc(Intel i7,64bit Debian Lenny)提供2MByte页面时,下面的内容快2.6倍(比4K页面);希望明显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%,但是(疯狂猜测)英特尔的fancy prefetching hardware可能在访问可预测时帮助4K情况(我想我可以disable prefetching调查是否真的这样做。

答案 2 :(得分:3)

我看到一些HPC / Grid方案的改进 - 特别是在具有大量RAM的机器上具有非常大型模型的物理包。此外,运行模型的过程是机器上唯一活动的过程。我怀疑,虽然没有测量,但某些数据库功能(例如批量导入)也会受益。

就个人而言,我认为除非你有一个非常好的/已了解的内存访问配置文件并且它会进行大量的大内存访问,否则你不太可能看到任何重大改进。

答案 3 :(得分:3)

这是越来越深奥,但是当进行DMA内存传输时(从主机到Phi通过PCIe),巨大的TLB页面在英特尔至强融核(MIC)架构上产生了显着差异。 This Intel link describes how to enable huge pages。我发现增加的DMA传输大小超过8 MB,正常的TLB页面大小(4K)开始降低性能,一旦传输大小达到512 MB,从大约3 GB / s到小于1 GB / s。

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

答案 4 :(得分:2)

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