CQ9节拍

低延迟优化:理解大型页面(第1部分)
主题
发表

2022年11月28日

延迟通常是算法交易中的一个关键因素. 在CQ9,我们花了很多精力来减少交易堆栈的延迟. 低延迟优化可能是神秘的,但幸运的是有很多非常好的 指南文档 开始吧.

的作用是一个不常被深入讨论的重要方面 巨大的页面翻译暂存缓冲区 (TLB). 在这一系列的文章中,我们将解释它们是什么,为什么它们很重要,以及如何使用它们. 我们将重点关注在64位x86硬件上运行的Linux操作系统, 但大多数要点也适用于其他架构. 我们试图在提供最准确的信息和不挖掘细枝末节之间找到平衡. 

这一系列的文章是相对技术性的, 并且需要对操作系统(OS)概念(如内存管理)有一定的了解, 以及一些硬件细节,比如CPU缓存. 在第一篇文章中,我们将解释大型页面的好处. 在 第二个帖子,我们将解释如何在生产环境中使用它们.

内存管理101

硬件和操作系统以块的形式处理内存. 这些块被称为页. 例如, 当操作系统分配或交换内存时, 它是以页为单位的.

在64位x86架构上,默认页面大小为4千字节(KiB)。. 但是x86 64位cpu还支持另外两种页面大小,即Linux所称的大页面:2MiB和1GiB1. 为简单起见,本系列文章的重点是2MiB页面. 1GiB页面也很有帮助, 但是它们太大了,所以它们的用例往往更专业.

11GiB页面有时也被称为巨型页面

地址翻译的快速入门 

当常规程序运行时,它们使用 虚拟地址 访问内存. 这些地址通常只在当前进程中有效. 硬件和操作系统合作将这些地址映射到物理内存(RAM)中的实际物理地址。. 这种翻译是每页进行的(你可能已经看到为什么页面大小很重要了).

因为程序只能看到虚拟地址, 在每次访问内存时,硬件必须将程序可见的虚拟地址转换为物理RAM地址(如果虚拟地址确实由物理内存支持)。. 内存访问是指处理器对数据或指令的任何加载或存储,而不管它们是否被缓存.

这些翻译由操作系统存储在称为 页表 硬件也能理解吗. 对于每个由真实内存支持的虚拟页面, 页表中的条目包含相应的物理地址. 对于机器上运行的每个进程,页表通常是唯一的.

为什么访问页表可能会显著增加延迟

除非程序的分配器和/或操作系统设置为使用巨大的页面, 内存将由4KiB页面支持. x86上的页表使用多个层次结构级别. 因此, 在页表中查找4 kb页的物理地址至少需要3个相关的内存负载.2

2 4 .加载 5级分页 CPU支持并在Linux内核中启用

CPU缓存将用于尝试实现这些(类似于任何常规内存访问). 但是让我们想象一下,所有这些负载都是未缓存的,需要来自内存. 使用70ns作为内存延迟, 我们的内存访问已经有70*3=210纳秒的延迟——我们甚至还没有尝试获取数据!

输入翻译暂存缓冲区

CPU设计人员很清楚这个问题,并提出了一组优化来减少地址转换的延迟. 我们在这篇文章中关注的具体优化是 翻译暂存缓冲区 (TLB).

TLB是地址转换信息的硬件缓存. 它包含许多页表中最近访问的条目的最新副本(理想情况下,当前进程页表中的所有条目)。. 就像访问CPU缓存比访问内存快一样, 在TLB中查找条目比在页表中查找要快得多3. 当CPU找到它在TLB中寻找的翻译时,它被称为a TLB打击. 如果不是,它就是a TLB小姐.

但是,就像普通的CPU缓存一样,TLB的大小是有限的. 对于许多需要内存的进程,整个页表的信息将无法装入TLB.

3 取决于缓存的状态, 它的速度从3倍到80倍不等, 尽管这种延迟可以通过推测的页面遍历来隐藏.

TLB有多大?

The TLB structure is not completely straightforward; we’ll approximate it to a set of entries in the hardware. 一个不错的经验法则是,最近的服务器x86 cpu的TLB大约是每核1500-2000个条目(cpuid 例如,可用于为CPU显示此信息)。.

因此,对于使用4KiB页面的进程, TLB可以缓存翻译,覆盖2000 (TLB中的条目数)* 4KiB(页面大小)字节, i.e ~8MiB的内存值. 这比许多程序的工作集要小得多. 甚至CPU缓存通常也相当大!

现在, 让我们假设我们正在使用巨大的页面-突然我们的TLB可以包含2000*2MiB = ~4GiB的翻译信息. 这样好多了.  

大页面的其他好处

一个巨大的页面所覆盖的内存是4KiB页面的512倍. 这意味着对于相同的工作集,页表中的条目数量也比使用常规页面少512倍. 这不仅大大减少了页表所使用的内存量, 但也使表本身更容易缓存.

另外, 2MiB页表的格式比常规页表的格式更简单, 因此,查找需要减少一次内存访问.

因此, 即使程序因为一个大页面支持的地址而错过了TLB, 与查找普通页面相比,查找页表的速度要快得多(甚至快得多).

一个快速而肮脏的基准

如果没有一个完全人为的基准😀,任何CQ9优化的文章都是不完整的. 我们编写了一个简单的程序,分配一个32gb的双精度数字数组. 然后从这个数组中添加1.3亿个随机双精度(完整的源代码可用) 在这里). 第一次运行时, 程序在数组中生成一个随机的索引列表,然后将它们存储在一个文件中. 后续运行将读取该文件,因此每次运行时对内存的访问都是相同的.

我们在一台空闲的英特尔电脑上运行这个程序 阿尔德湖 机. 当使用大页面时,程序初始化部分的基准时间要快40%. 数组是线性初始化的, 对于硬件来说,哪种情况下加速不会太大. 然而,当进行随机访问来添加双精度数时,运行时间会减少4倍.5. 请注意,运行的秒数可能会随着程序的微小变化或使用不同的编译器而发生显著变化.  然而,对于大型页面的性能改进仍然非常明显.

当你不应该使用巨大的页面

巨大的页面应该被认为是一种优化. 就像任何其他优化一样,它们可能适用于您的工作负载,也可能不适用. 基准测试对于确定是否值得投入时间来设置它们非常重要. 在本系列的第二篇文章中, 我们将详细说明如何使用它们并列出一些重要的注意事项.

结论

对代码或数据的每次内存访问, 硬件将虚拟地址转换为物理地址. 使用巨大的页面可以显著加快翻译速度.

巨大的页面还允许TLB覆盖大量内存. 在理想的情况下, 我们希望我们的整个工作集可以被TLB翻译,而不需要访问页表. 这减少了内存访问的延迟, 并且还释放了CPU缓存中的一些空间(不再需要包含那么多缓存的页表条目)。.

如果你觉得这些内容很有趣,想了解更多CQ9激素替代疗法的知识,请查看我们的 网站 或者考虑申请 加入我们的团队!

现在我们已经介绍了大页面的优点,转到 第2部分 阅读更多CQ9实用性(和挑战)的内容!)在生产环境中使用巨大的页面.

进一步的阅读

每个程序员都应该知道的CQ9内存的事情

不要错过任何一个节拍

关注我们,了解CQ9在工程、数学和自动化方面的最新信息.