linuxdebug/Documentation/translations/zh_CN/mm/numa.rst

102 lines
7.7 KiB
ReStructuredText
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

:Original: Documentation/mm/numa.rst
:翻译:
司延腾 Yanteng Si <siyanteng@loongson.cn>
:校译:
始于1999年11月作者 <kanoj@sgi.com>
==========================
何为非统一内存访问(NUMA)
==========================
这个问题可以从几个视角来回答硬件观点和Linux软件视角。
从硬件角度看NUMA系统是一个由多个组件或装配组成的计算机平台每个组件可能包含0个或更多的CPU、
本地内存和/或IO总线。为了简洁起见并将这些物理组件/装配的硬件视角与软件抽象区分开来,我们在
本文中称这些组件/装配为“单元”。
每个“单元”都可以看作是系统的一个SMP[对称多处理器]子集——尽管独立的SMP系统所需的一些组件可能
不会在任何给定的单元上填充。NUMA系统的单元通过某种系统互连连接在一起——例如交叉开关或点对点
链接是NUMA系统互连的常见类型。这两种类型的互连都可以聚合起来以创建NUMA平台其中的单元与其
他单元有多个距离。
对于Linux感兴趣的NUMA平台主要是所谓的缓存相干NUMA--简称ccNUMA系统系统。在ccNUMA系统中
所有的内存都是可见的并且可以从连接到任何单元的任何CPU中访问缓存一致性是由处理器缓存和/或
系统互连在硬件中处理。
内存访问时间和有效的内存带宽取决于包含CPU的单元或进行内存访问的IO总线距离包含目标内存的单元
有多远。例如连接到同一单元的CPU对内存的访问将比访问其他远程单元的内存经历更快的访问时间和
更高的带宽。 NUMA平台可以在任何给定单元上访问多种远程距离的其他单元。
平台供应商建立NUMA系统并不只是为了让软件开发人员的生活变得有趣。相反这种架构是提供可扩展
内存带宽的一种手段。然而,为了实现可扩展的内存带宽,系统和应用软件必须安排大部分的内存引用
[cache misses]到“本地”内存——同一单元的内存,如果有的话——或者到最近的有内存的单元。
这就自然而然有了Linux软件对NUMA系统的视角:
Linux将系统的硬件资源划分为多个软件抽象称为“节点”。Linux将节点映射到硬件平台的物理单元
对一些架构的细节进行了抽象。与物理单元一样软件节点可能包含0或更多的CPU、内存和/或IO
总线。同样,对“较近”节点的内存访问——映射到较近单元的节点——通常会比对较远单元的访问经历更快
的访问时间和更高的有效带宽。
对于一些架构如x86Linux将“隐藏”任何代表没有内存连接的物理单元的节点并将连接到该单元
的任何CPU重新分配到代表有内存的单元的节点上。因此在这些架构上我们不能假设Linux将所有
的CPU与一个给定的节点相关联会看到相同的本地内存访问时间和带宽。
此外对于某些架构同样以x86为例Linux支持对额外节点的仿真。对于NUMA仿真Linux会将现
有的节点或者非NUMA平台的系统内存分割成多个节点。每个模拟的节点将管理底层单元物理内存的一部
分。NUMA仿真对于在非NUMA平台上测试NUMA内核和应用功能是非常有用的当与cpusets一起使用时
可以作为一种内存资源管理机制。[见 Documentation/admin-guide/cgroup-v1/cpusets.rst]
对于每个有内存的节点Linux构建了一个独立的内存管理子系统有自己的空闲页列表、使用中页列表、
使用统计和锁来调解访问。此外Linux为每个内存区[DMA、DMA32、NORMAL、HIGH_MEMORY、MOVABLE
中的一个或多个]构建了一个有序的“区列表”。zonelist指定了当一个选定的区/节点不能满足分配请求
时要访问的区/节点。当一个区没有可用的内存来满足请求时这种情况被称为“overflow 溢出”或
“fallback 回退”。
由于一些节点包含多个包含不同类型内存的区Linux必须决定是否对区列表进行排序使分配回退到不同
节点上的相同区类型或同一节点上的不同区类型。这是一个重要的考虑因素因为有些区如DMA或DMA32
代表了相对稀缺的资源。Linux选择了一个默认的Node ordered zonelist。这意味着在使用按NUMA距
离排序的远程节点之前,它会尝试回退到同一节点的其他分区。
默认情况下Linux会尝试从执行请求的CPU被分配到的节点中满足内存分配请求。具体来说Linux将试
图从请求来源的节点的适当分区列表中的第一个节点进行分配。这被称为“本地分配”。如果“本地”节点不能
满足请求,内核将检查所选分区列表中其他节点的区域,寻找列表中第一个能满足请求的区域。
本地分配将倾向于保持对分配的内存的后续访问 “本地”的底层物理资源和系统互连——只要内核代表其分配
一些内存的任务后来不从该内存迁移。Linux调度器知道平台的NUMA拓扑结构——体现在“调度域”数据结构
中[见 Documentation/scheduler/sched-domains.rst]——并且调度器试图尽量减少任务迁移到遥
远的调度域中。然而调度器并没有直接考虑到任务的NUMA足迹。因此在充分不平衡的情况下任务可
以在节点之间迁移,远离其初始节点和内核数据结构。
系统管理员和应用程序设计者可以使用各种CPU亲和命令行接口如taskset(1)和numactl(1),以及程
序接口如sched_setaffinity(2)来限制任务的迁移以改善NUMA定位。此外人们可以使用
Linux NUMA内存策略修改内核的默认本地分配行为。 [见
:ref:`Documentation/admin-guide/mm/numa_memory_policy.rst <numa_memory_policy>`].
系统管理员可以使用控制组和CPUsets限制非特权用户在调度或NUMA命令和功能中可以指定的CPU和节点
的内存。 [见 Documentation/admin-guide/cgroup-v1/cpusets.rst]
在不隐藏无内存节点的架构上Linux会在分区列表中只包括有内存的区域[节点]。这意味着对于一个无
内存的节点“本地内存节点”——CPU节点的分区列表中的第一个区域的节点——将不是节点本身。相反
将是内核在建立分区列表时选择的离它最近的有内存的节点。所以,默认情况下,本地分配将由内核提供
最近的可用内存来完成。这是同一机制的结果,该机制允许这种分配在一个包含内存的节点溢出时回退到
其他附近的节点。
一些内核分配不希望或不能容忍这种分配回退行为。相反,他们想确保他们从指定的节点获得内存,或者
得到通知说该节点没有空闲内存。例如当一个子系统分配每个CPU的内存资源时通常是这种情况。
一个典型的分配模式是使用内核的numa_node_id()或CPU_to_node()函数获得“当前CPU”所在节点的
节点ID然后只从返回的节点ID请求内存。当这样的分配失败时请求的子系统可以恢复到它自己的回退
路径。板块内核内存分配器就是这样的一个例子。或者,子系统可以选择在分配失败时禁用或不启用自己。
内核分析子系统就是这样的一个例子。
如果架构支持——不隐藏无内存节点那么连接到无内存节点的CPU将总是产生回退路径的开销或者一些
子系统如果试图完全从无内存的节点分配内存,将无法初始化。为了透明地支持这种架构,内核子系统可
以使用numa_mem_id()或cpu_to_mem()函数来定位调用或指定CPU的“本地内存节点”。同样这是同
一个节点,默认的本地页分配将从这个节点开始尝试。