同一地址空间,不同访问距离

非一致内存访问的英文名称是Non-uniform memory access。典型系统把处理器、内存控制器和内存组织在若干互联单元中:处理器访问附近内存走较短路径,访问远端内存则需经过节点间互联。这里的差别不仅可能表现为延迟,也可能表现为可用带宽。

以Linux主要支持的缓存一致性NUMA,即ccNUMA为例,各处理器可以访问系统各处内存,缓存一致性由硬件维持。共享地址空间回答“能否寻址”,一致性机制处理缓存副本的协调,NUMA则描述访问成本。它不是把几台独立机器的文件存储拼在一起,也不能仅凭一台机器有多个核心就断定它具有NUMA拓扑。

参考:[1] [3]

节点是放置工作的依据

Linux以节点抽象硬件资源,节点可以具有处理器、内存或其他资源,也可能没有本地内存。不同远端节点之间还可有不同距离,因此“本地与远端”不一定只有两档固定代价。软件看到的节点也并非总与一个处理器插槽简单一一对应,应以实际拓扑为依据。

默认本地分配会优先尝试为正在执行的处理器寻找附近内存,资源不足时可能回退到其他节点。因而“本地优先”不是“本地保证”。NUMA设计旨在扩展内存带宽,但要发挥优势,应用的数据分工须让相当多的内存访问留在工作线程附近。

参考:[1] [2] [3]

首次触碰为何重要

虚拟内存分配与物理页落实不一定同时发生。在采用首次触碰式延迟分配的情形中,申请一段地址空间并不立即决定全部物理页归属;首次真正触及页面、触发所需分配的线程及当时策略会影响放置。已有页面、显式内存策略和不同操作系统的接口行为,不能套用同一简化规则。

例如,两组线程分别长期处理大数组的前半与后半。若主线程先独自写遍数组,页面可能集中在主线程附近,另一组工作线程随后频繁访问远端内存。让各组在其工作节点上初始化自己的分区,可使首次分配更贴近后续使用。Intel手册以并行初始化展示这一思路;它是有条件的局部性技巧,不是任何负载都有效的保证。

参考:[3] [2]

线程与页面须共同安排

CPU亲和性限制线程可运行的处理器,内存策略控制页面从哪些节点分配,两者解决的问题不同。仅绑定线程,未必移动已分配的页面;只改变后续分配策略,也不意味着旧页自动迁移到新位置。Linux另有页面迁移机制,必须区分“设定策略”与“搬移现有数据”。

Linux提供绑定、偏好节点和交错分配等策略。交错分配按页把内存分布到指定节点,可以改变负载分布,却不能让每个访问者都只访问本地。选择策略时,应对照线程分工、共享数据范围及内存压力,而不是把绑核或本地化当作孤立开关。

参考:[2] [1]