什么是NUMA

NUMA balance的背景

在NUMA(None Uniform Memory Access)之前是UMA(Uniform Memory Access), UMA 架构下,CPU 和内存之间的通信全部都要通过前端总线,总线模型保证了 CPU 的所有内存访问速率都是一致的,不必考虑不同内存地址之间的差异。此时提高性能的方式,就是不断地提高 CPU、前端总线和内存的工作频率。但是因为物理条件的限制,不断提高工作频率的路子走不下去了,CPU 性能的提升开始从提高主频转向增加 CPU 数量(多核、多 CPU)。越来越多的 CPU 对前端总线的争用,使前端总线成为了瓶颈。为了消除 UMA 架构的瓶颈,NUMA架构诞生了。在 NUMA 架构下,CPU与CPU之间通过核间互连总线连接,内存的访问速率出现了本地和远程的区别,访问远程内存的延时会明显高于访问本地内存。
linux在2.4就支持了NUMA架构,但是存在性能问题,任务运行的CPU和需要访问的数据不在同一节点上,访问延迟会影响发挥CPU的性能。之后厂商一方面提高核间互连总线的速率来消除NUMA的差异,目前x86和arm64上访问非本节点带宽达到本节点带宽的80%,另一方面软件进行优化,争取使CPU访问本节点内存。
在2012年左右,Peter Zijlstra 和 Andrea 分别提交了NUMA优化的patch,中间的过程略过,最终有了现在的numa balance的功能。

numa balance的终极目标: 任务访问本节点内存。实现上将其拆分成两个小目标:

如果任务访问的大部分内存不在本节点,那么把任务迁移到该节点的CPU上运行;
如果任务访问的大部分数据都在本节点,那么将其他节点上的数据迁移到该节点上。

基本原理

numa balance功能的基本实现过程

周期性扫描task的地址空间并且修改页表项为PAGE_NONE(没有读/写/执行权限,但是有对应的物理地址),之后访问该数据时会发生page fault。
在page fault中,重新修改页表为正确的权限使得后面能够继续执行
在page fault中会追踪两个数据: page被哪个节点和任务访问过,任务在各个节点上发生的缺页情况
根据历史记录,决定是否迁移页和任务迁移
对于单进程单线程的程序来说比较简单,进程没有共享的数据或者非常少,选择一个合适的节点运行就可以了;对于单进程多线程来说,就比较复杂了,线程间共享数据是不确定的,CPU的繁忙程度也是不固定的,特别是对于线程池的方式没有办法采用固定的配置。

总体而言需要解决几个问题:

扫描尽量不要影响系统正常的性能,因为它会强制触发page fault, 所以必须对扫描周期和一次性扫描的页范围进行限制,特别是扫描周期会根据缺页的历史统计进行动态调整。
决定是否迁移页
决定是否迁移线程到不同的节点上

posted @ 2022-07-13 12:03  無心的Man  阅读(772)  评论(0编辑  收藏  举报