【问题标题】:In what circumstances can large pages produce a speedup?在什么情况下大页面可以产生加速?
【发布时间】:2011-02-22 00:18:51
【问题描述】:

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

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

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

【问题讨论】:

    标签: performance x86 virtual-memory tlb


    【解决方案1】:

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

    为了使事情更复杂,4kB 页面的 TLB 条目数通常大于 2MB 页面的条目数,但这因处理器而异。 2 级 TLB 中可用的“大页面”条目的数量也存在很大差异。

    例如,在 AMD Opteron Family 10h Revision D(“伊斯坦布尔”)系统上,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 系统在使用大页面和更大的内存范围时应该会继续表现出良好的性能。

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

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

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

    的第 5.3 节

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

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

    【讨论】:

      【解决方案2】:

      我试图设计一些代码来最大化 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调查这是否属实)。

      【讨论】:

      • 硬件预取不会跨越 4k 页面边界,但是您可能在直线情况下看到的是页表访问是非常可预测的,因此当您错过TLB 可能会命中所有在 L1 中的页面(这些页面条目可能确实是通过预取引入的)。
      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

          【解决方案5】:

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

          【讨论】:

            猜你喜欢
            • 2016-05-19
            • 1970-01-01
            • 2019-03-26
            • 2017-11-30
            • 2012-10-21
            • 2017-03-25
            • 1970-01-01
            • 2012-02-24
            • 1970-01-01
            相关资源
            最近更新 更多