Arm64内存页大小配置指南:提升性能的关键技巧

本文深入探讨Arm64架构中内存页大小的配置方法,分析4K、16K和64K页面的性能差异,并提供在Ampere CPU上配置大内存页的实用指南,帮助优化数据库、虚拟化及AI推理等内存密集型应用的性能。

Arm64内存页大小解析

Arm64架构与x86的一个关键区别在于能够将CPU内存管理单元(MMU)中的内存页大小配置为4K、16K或64K。本文总结了内存页大小的概念、在Linux系统上配置页大小的方法,以及何时在应用程序中使用不同页大小更有意义。

内存页大小介绍

正如我们在《诊断和修复Arm64原子操作的页错误性能问题》中讨论的,操作系统向应用程序呈现虚拟内存地址空间,并使用页表将物理内存页映射到虚拟内存地址。CPU随后提供一种称为转换后备缓冲区(TLB)的机制,确保最近访问的内存页可以通过L1或L2 CPU缓存更快地识别和读取。

x86架构上的物理内存页(称为颗粒)大小固定为4KB。然而,在像Ampere Altra®或AmpereOne®这样的ARM64系统上,开发人员可以将物理内存页的大小配置为4KB、16KB或64KB。

何时使用更大的页大小?

由于更改页大小会影响系统的内存效率和性能,因此了解何时使用更大的页大小以及所涉及的权衡非常重要。更大的页大小可能导致内存使用效率降低,因为页面可能未满。

例如,如果我们在内存中存储7KB的数据,在具有4KB内核页的系统上,这将使用两个4KB页面,总共8KB内存,效率为87.5%。然而,在具有64KB页的系统上,我们现在消耗一个64KB页面来存储7KB数据,单个分配的效率为11%。

但是,MMU和操作系统内核足够智能,可以使用先前已分配但未满的连续内存块进行未来的内存分配。如果同一进程稍后分配32KB内存,我们仍然只使用一个64KB页面,其中39KB被占用。使用4K页大小,我们现在将管理十个4KB页面。

第二个权衡是由于页表查找的缓存未命中导致的性能问题。每个缓存级别(L1、L2、系统级缓存)的TLB中存储的页表条目数量相对较少。

使用更大的页大小,这些TLB条目覆盖的物理内存量更大。例如,在Ampere Altra和Altra Max处理器上,L1数据TLB有48个条目,L2 TLB有1280个条目。

这意味着,对于4KB颗粒,L1 TLB可以缓存192KB物理内存的地址,L2 TLB可以存储覆盖5MB物理内存的页地址。

使用64KB页大小,L1数据TLB增加到3MB,L2 TLB增加到80MB。TLB中的每次缓存未命中都会增加页遍历时间,以找到与虚拟内存查找匹配的物理页,缓存一旦定位的页,并适当更新TLB。使用更大的页面,缓存未命中更少,内存密集型工作负载的性能更好。

您还可以通过拥有更大的连续内存区域来提高I/O性能。因此,在内存中或传输中有大量数据的数据密集型应用程序可以从更大的页大小中受益。其中一些应用程序包括:

  • 数据库:数据库系统倾向于在内存中存储大量信息用于缓存目的,并对大型数据集进行大量磁盘I/O。这两个特性使数据库服务器成为大内存页大小的理想候选。
  • 虚拟化基础设施:虚拟机(VM)包括一个磁盘映像,由操作系统内核和该VM所需的所有应用程序组成,大小从几百兆字节到几百千兆字节不等。因此,它们可以使用大量内存,并可以从更大的页大小中受益。
  • 持续集成的构建服务器:像构建Linux内核这样的任务处理数千个源文件,并在编译时使用大量RAM。作为高吞吐量工作负载,配置更大页大小的主机往往作为构建服务器表现更好。
  • 网络或I/O密集型应用程序:对于具有大量网络I/O和内存中数据处理的应用程序,如对象缓存、负载均衡器、防火墙或视频流,大内存页可以减少页错误,提高性能。
  • 内存密集型应用程序如AI推理:AI推理,执行训练模型如推荐引擎或LLM聊天机器人,是内存和CPU密集型工作负载,大内存页大小可以帮助提供高性能。

一般来说,这些类型应用程序使用更大页大小的性能取决于几个因素,包括所涉及的数据集和应用程序的内存访问模式。

如果您认为您的应用程序可以从更大的内存页中受益,您应该使用4K和64K页面对目标工作负载进行基准测试,并根据测试结果做出部署决策。

除了使用生产风格的数据对目标应用程序进行4K和64K页面的基准测试外,您还可以使用“perf”工具评估更大页大小的潜在好处,通过测量TLB停滞(即TLB未命中导致CPU管道在等待从内存加载信息时停滞的频率)。

首先,检查内核是否支持AmpereONE及更新CPU上的TLB停滞计数器。

1
2
3
# perf list | grep end_tlb
stall_backend_tlb
stall_frontend_tlb

确认内核支持后,可以测量由于TLB未命中导致的管道停滞:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# perf stat -e instructions,cycles,stall_frontend_tlb,stall_backend_tlb ./a.out 
time for 12344321 * 100M nops: 3.7 s 
Performance counter stats for './a.out': 
12,648,071,049 instructions # 1.14 insn per cycle  
11,109,161,102 cycles  
1,482,795,078 stall_frontend_tlb  
1,334,751 stall_backend_tlb  
3.706937365 seconds time elapsed 
3.629966000 seconds user 
0.000995000 seconds sys

比率(stall_frontend_tlb + stall_backend_tlb)/cycles是通过使用更大内存页可以节省的时间的上限。

但是请注意,由于4K作为默认页大小已经很久,一些软件包可能会对您的系统做出该假设,导致内存使用效率低下。在现代软件堆栈中,这不是非常常见的情况,但建议在承诺使用更大页大小之前进行一些测试和基准测试。

在Ampere CPU上配置更大的页大小

更改内存页大小需要运行已编译支持所需大小的操作系统内核。对于流行的云操作系统,如Red Hat Enterprise Linux、Oracle Enterprise Linux、Suse Enterprise Linux或Canonical的Ubuntu,这些操作系统随附预构建的内核,支持Arm64上的4KB页大小和64KB页大小。

在Red Hat Enterprise Linux 9上使用64KB页内核:

  1. 安装kernel-64k包:
1
dnf –y install kernel-64k 
  1. 启用64K内核在启动时默认启动:
1
2
3
4
k=$(echo /boot/vmlinuz*64k)
grubby --set-default=$k \ 
     --update-kernel=$k \ 
     --args="crashkernel=2G-:640M" 

在Ubuntu 22.04上启动64KB内核:

  1. 安装默认包含64K内核的arm64+largemem ISO,或:
  2. 安装linux-generic-64k包,该包将向启动菜单添加64K内核选项,命令为:
1
sudo apt install linux-generic-64K
  1. 您可以通过使用以下命令更新grub2启动菜单,将64K内核设置为默认启动选项:
1
2
echo "GRUB_FLAVOUR_ORDER=generic-64k" | sudo tee
/etc/default/grub.d/local-order.cfg

在Oracle Linux上使用64KB页:

  1. 安装kernel-uek64k包:
1
sudo dnf install -y kernel-uek64k
  1. 在启动时将64K内核设置为默认:
1
sudo grubby --set-default=$(echo /boot/vmlinuz*64k)
  1. 重新启动系统后,您可以使用getconf验证是否正在运行64K内核,如下所述。

其他操作系统发行版的网站上可能提供类似的说明。

如果您正在构建自己的Linux内核,可以使用make menuconfig更改内核配置。在“Processor type and features”子菜单中,您将找到基于内核功能的ARM64 CPU功能寄存器配置选项,您可以将其更改为16K或64K。

或者,您可以直接更改内核配置文件.config,将CONFIG_ARM_PAGE_SHIFT的值从其默认值12(4K = 2^12字节)设置为14(16K = 2^14字节)或16(64K = 2^16字节)。然后,您可以通过在引导加载程序中为具有不同页大小的内核创建多个条目,并在启动时选择适当的内核,来选择在启动时引导哪个内核。

要验证当前Linux内核的内核页大小设置,您可以使用系统getconf实用程序。对于64K页大小,这些将显示以下内容:

1
2
$ getconf PAGESIZE 
65536 

结论

总结:更改云系统上的内核内存页大小可以对许多常见云工作负载的应用程序性能产生积极影响。如果您的应用程序包含大量磁盘、内存或网络I/O,通过在ARM主机上启用16K或64K页的内核,您可能能够显著提高性能。

然而,这不是万能的,您的体验可能有所不同。我们建议您使用合成和真实世界的基准测试进行测试,以查看更改页大小是否会对您的最终结果产生积极影响。

许多具有Arm64构建的常见Linux发行版已经在其发行版存储库中包含多个内核。通过安装这些内核包并在启动时引导它们,尝试更大内核以测试它们是否提供性能改进的成本相对较低。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计