转载:

http://www.ibm.com/developerworks/cn/linux/l-numa/

Linux 的 NUMA 技术

吴庆波 ( wqb123@263.net)国防科技大学计算机学院

简介: NUMA(Non-Uniform Memory Access Architecture)系统在市场上的应用越来越广泛,许多厂商都成功推出了基于NUMA架构的服务器,本文重点讨论了当前Linux的NUMA技术,主要包括:存储管理、NUMA调度和用户层的API,并在SGI的Altix 350系统上进行了NUMA基本测试,对进行Linux NUMA技术的研究具有参考价值。

一、引言

随着科学计算、事务处理对计算机性能要求的不断提高,SMP(对称多处理器)系统的应用越来越广泛,规模也越来越大,但由于传统的SMP系统中,所有处理器都共享系统总线,因此当处理器的数目增大时,系统总线的竞争冲突加大,系统总线将成为瓶颈,所以目前SMP系统的CPU数目一般只有数十个,可扩展能力受到极大限制。NUMA技术有效结合了SMP系统易编程性和MPP(大规模并行)系统易扩展性的特点,较好解决了SMP系统的可扩展性问题,已成为当今高性能服务器的主流体系结构之一。目前国外著名的服务器厂商都先后推出了基于NUMA架构的高性能服务器,如HP的Superdome、SGI的Altix 3000、IBM的 x440、NEC的TX7、AMD的Opteron等。随着Linux在服务器平台上的表现越来越成熟,Linux内核对NUMA架构的支持也越来越完善,特别是从2.5开始,Linux在调度器、存储管理、用户级API等方面进行了大量的NUMA优化工作,目前这部分工作还在不断地改进,如新近推出的2.6.7-RC1内核中增加了NUMA调度器。本文主要从存储管理、调度器和CpuMemSets三个方面展开讨论。

回页首

二、NUMA存储管理

NUMA系统是由多个结点通过高速互连网络连接而成的,如图1是SGI Altix 3000 ccNUMA系统中的两个结点。

图1 SGI Altix3000系统的两个结点

NUMA系统的结点通常是由一组CPU(如,SGI Altix 3000是2个Itanium2 CPU)和本地内存组成,有的结点可能还有I/O子系统。由于每个结点都有自己的本地内存,因此全系统的内存在物理上是分布的,每个结点访问本地内存和访问其它结点的远地内存的延迟是不同的,为了减少非一致性访存对系统的影响,在硬件设计时应尽量降低远地内存访存延迟(如通过Cache一致性设计等),而操作系统也必须能感知硬件的拓扑结构,优化系统的访存。

目前IA64 Linux所支持的NUMA架构服务器的物理拓扑描述是通过ACPI(Advanced Configuration and Power Interface)实现的。ACPI是由Compaq、Intel、Microsoft、Phoenix和Toshiba联合制定的BIOS规范,它定义了一个非常广泛的配置和电源管理,目前该规范的版本已发展到2.0,3.0o版本正在制定中,具体信息可以从 http://www.acpi.info网站上获得。ACPI规范也已广泛应用于IA-32架构的至强服务器系统中。

Linux对NUMA系统的物理内存分布信息是从系统firmware的ACPI表中获得的,最重要的是SRAT(System Resource Affinity Table)和SLIT(System Locality Information Table)表,其中SRAT包含两个结构:

  • Processor Local APIC/SAPIC Affinity Structure:记录某个CPU的信息;
  • Memory Affinity Structure:记录内存的信息;

SLIT表则记录了各个结点之间的距离,在系统中由数组node_distance[ ]记录。

Linux采用Node、Zone和页三级结构来描述物理内存的,如图2所示,

图2 Linux中Node、Zone和页的关系

2.1 结点

Linux用一个struct pg_data_t结构来描述系统的内存,系统中每个结点都挂接在一个pgdat_list列表中,对UMA体系结构,则只有一个静态的pg_data_t结构contig_page_data。对NUMA系统来说则非常容易扩充,NUMA系统中一个结点可以对应Linux存储描述中的一个结点,具体描述见linux/mmzone.h。

typedef struct pglist_data {
zone_t node_zones[MAX_NR_ZONES];
zonelist_t node_zonelists[GFP_ZONEMASK+1];
int nr_zones;
struct page *node_mem_map;
unsigned long *valid_addr_bitmap;
struct bootmem_data *bdata;
unsigned long node_start_paddr;
unsigned long node_start_mapnr;
unsigned long node_size;
int node_id;
struct pglist_data *node_next;
} pg_data_t;

下面就该结构中的主要域进行说明,

说明
Node_zones 该结点的zone类型,一般包括ZONE_HIGHMEM、ZONE_NORMAL和ZONE_DMA三类
Node_zonelists 分配时内存时zone的排序。它是由free_area_init_core()通过page_alloc.c中的build_zonelists()设置zone的顺序
nr_zones 该结点的 zone 个数,可以从 1 到 3,但并不是所有的结点都需要有3 个 zone
node_mem_map 它是 struct page数组的第一页,该数组表示结点中的每个物理页框。根据该结点在系统中的顺序,它可在全局mem_map 数组中的某个位置
Valid_addr_bitmap 用于描述结点内存空洞的位图
node_start_paddr 该结点的起始物理地址
node_start_mapnr 给出在全局 mem_map 中的页偏移,在free_area_init_core()计算在 mem_map 和 lmem_map 之间的该结点的页框数目
node_size 该 zone 内的页框总数
node_id 该结点的 ID,全系统结点 ID 从 0 开始

系统中所有结点都维护在 pgdat_list 列表中,在 init_bootmem_core 函数中完成该列表初始化工作。

2.2 Zone

每个结点的内存被分为多个块,称为zones,它表示内存中一段区域。一个zone用struct_zone_t结构描述,zone的类型主要有ZONE_DMA、ZONE_NORMAL和ZONE_HIGHMEM。ZONE_DMA位于低端的内存空间,用于某些旧的ISA设备。ZONE_NORMAL的内存直接映射到Linux内核线性地址空间的高端部分,许多内核操作只能在ZONE_NORMAL中进行。例如,在X86中,zone的物理地址如下:

类型 地址范围
ZONE_DMA 前16MB内存
ZONE_NORMAL 16MB - 896MB
ZONE_HIGHMEM 896 MB以上

Zone是用struct zone_t描述的,它跟踪页框使用、空闲区域和锁等信息,具体描述如下:

typedef struct zone_struct {
spinlock_t lock;
unsigned long free_pages;
unsigned long pages_min, pages_low, pages_high;
int need_balance;
free_area_t free_area[MAX_ORDER];
wait_queue_head_t * wait_table;
unsigned long wait_table_size;
unsigned long wait_table_shift;
struct pglist_data *zone_pgdat;
struct page *zone_mem_map;
unsigned long zone_start_paddr;
unsigned long zone_start_mapnr;
char *name;
unsigned long size;
} zone_t;

下面就该结构中的主要域进行说明,

说明
Lock 旋转锁,用于保护该zone
free_pages 该zone空闲页总数
pages_min,

pages_low,

pages_high

Zone的阈值
need_balance 该标志告诉kswapd需要对该zone的页进行交换
Free_area 空闲区域的位图,用于buddy分配器
wait_table 等待释放该页进程的队列散列表,这对wait_on_page()和unlock_page()是非常重要的。当进程都在一条队列上等待时,将引起进程的抖动
zone_mem_map 全局mem_map中该zone所引用的第一页
zone_start_paddr 含义与node_start_paddr类似
zone_start_mapnr 含义与node_start_mapnr类似
Name 该zone的名字。如,“DMA”,“Normal”或“HighMem”
Size Zone的大小,以页为单位

当系统中可用的内存比较少时,kswapd将被唤醒,并进行页交换。如果需要内存的压力非常大,进程将同步释放内存。如前面所述,每个zone有三个阈值,称为pages_low,pages_min和pages_high,用于跟踪该zone的内存压力。pages_min的页框数是由内存初始化free_area_init_core函数,根据该zone内页框的比例计算的,最小值为20页,最大值一般为255页。当到达pages_min时,分配器将采用同步方式进行kswapd的工作;当空闲页的数目达到pages_low时,kswapd被buddy分配器唤醒,开始释放页;当达到pages_high时,kswapd将被唤醒,此时kswapd不会考虑如何平衡该zone,直到有pages_high空闲页为止。一般情况下,pages_high缺省值是pages_min的3倍。

Linux存储管理的这种层次式结构可以将ACPI的SRAT和SLIT信息与Node、Zone实现有效的映射,从而克服了传统Linux中平坦式结构无法反映NUMA架构的缺点。当一个任务请求分配内存时,Linux采用局部结点分配策略,首先在自己的结点内寻找空闲页;如果没有,则到相邻的结点中寻找空闲页;如果还没有,则到远程结点中寻找空闲页,从而在操作系统级优化了访存性能。

回页首

三、NUMA调度器

NUMA系统中,由于局部内存的访存延迟低于远地内存访存延迟,因此将进程分配到局部内存附近的处理器上可极大优化应用程序的性能。Linux 2.4内核中的调度器由于只设计了一个运行队列,可扩展性较差,在SMP平台表现一直不理想。当运行的任务数较多时,多个CPU增加了系统资源的竞争,限制了负载的吞吐率。在2.5内核开发时,Ingo Molnar写了一个多队列调度器,称为O(1),从2.5.2开始O(1)调度器已集成到2.5内核版本中。O(1)是多队列调度器,每个处理器都有一条自己的运行队列,但由于O(1)调度器不能较好地感知NUMA系统中结点这层结构,从而不能保证在调度后该进程仍运行在同一个结点上,为此,Eirch Focht开发了结点亲和的NUMA调度器,它是建立在Ingo Molnar的O(1)调度器基础上的,Eirch将该调度器向后移植到2.4.X内核中,该调度器最初是为基于IA64的NUMA机器的2.4内核开发的,后来Matt Dobson将它移植到基于X86的NUMA-Q硬件上。

3.1 初始负载平衡

在每个任务创建时都会赋予一个HOME结点(所谓HOME结点,就是该任务获得最初内存分配的结点),它是当时创建该任务时全系统负载最轻的结点,由于目前Linux中不支持任务的内存从一个结点迁移到另一个结点,因此在该任务的生命期内HOME结点保持不变。一个任务最初的负载平衡工作(也就是选该任务的HOME结点)缺省情况下是由exec()系统调用完成的,也可以由fork()系统调用完成。在任务结构中的node_policy域决定了最初的负载平衡选择方式。

Node_policy 平衡方式 注释
0(缺省值) do_execve() 任务由fork()创建,但不在同一个结点上运行exec()
1 do_fork() 如果子进程有新的mm结构,选择新的HOME结点
2 do_fork() 选择新的HOME结点

3.2 动态负载平衡

在结点内,该NUMA调度器如同O(1)调度器一样。在一个空闲处理器上的动态负载平衡是由每隔1ms的时钟中断触发的,它试图寻找一个高负载的处理器,并将该处理器上的任务迁移到空闲处理器上。在一个负载较重的结点,则每隔200ms触发一次。调度器只搜索本结点内的处理器,只有还没有运行的任务可以从Cache池中移动到其它空闲的处理器。

如果本结点的负载均衡已经非常好,则计算其它结点的负载情况。如果某个结点的负载超过本结点的25%,则选择该结点进行负载均衡。如果本地结点具有平均的负载,则延迟该结点的任务迁移;如果负载非常差,则延迟的时间非常短,延迟时间长短依赖于系统的拓扑结构。

回页首

四、CpuMemSets

SGI的Origin 3000 ccNUMA系统在许多领域得到了广泛应用,是个非常成功的系统,为了优化Origin 3000的性能,SGI的IRIX操作系统在其上实现了CpuMemSets,通过将应用与CPU和内存的绑定,充分发挥NUMA系统本地访存的优势。Linux在NUMA项目中也实现了CpuMemSets,并且在SGI的Altix 3000的服务器中得到实际应用。

CpuMemSets为Linux提供了系统服务和应用在指定CPU上调度和在指定结点上分配内存的机制。CpuMemSets是在已有的Linux调度和资源分配代码基础上增加了cpumemmap和cpumemset两层结构,底层的cpumemmap层提供一个简单的映射对,主要功能是:将系统的CPU号映射到应用的CPU号、将系统的内存块号映射到应用的内存块号;上层的cpumemset层主要功能是:指定一个进程在哪些应用CPU上调度任务、指定内核或虚拟存储区可分配哪些应用内存块。

4.1 cpumemmap

内核任务调度和内存分配代码使用系统号,系统中的CPU和内存块都有对应的系统号。应用程序使用的CPU号和内存块号是应用号,它用于指定在cpumemmap中CPU和内存的亲和关系。每个进程、每个虚拟内存区和Linux内核都有cpumemmap,这些映射是在fork()、exec()调用或创建虚拟内存区时继承下来的,具有root权限的进程可以扩展cpumemmap,包括增加系统CPU和内存块。映射的修改将导致内核调度代码开始运用新的系统CPU,存储分配代码使用新的内存块分配内存页,而已在旧块上分配的内存则不能迁移。Cpumemmap中不允许有空洞,例如,假设cpumemmap的大小为n,则映射的应用号必须从0到n-1。Cpumemmap中系统号和应用号并不是一对一的映射,多个应用号可以映射到同一个系统号。

4.2 cpumemset

系统启动时,Linux内核创建一个缺省的cpumemmap和cpumemset,在初始的cpumemmap映射和cpumemset中包含系统目前所有的CPU和内存块信息。

Linux内核只在该任务cpumemset的CPU上调度该任务,并只从该区域的内存列表中选择内存区分配给用户虚拟内存区,内核则只从附加到正在执行分配请求CPU的cpumemset内存列表中分配内存。

一个新创建的虚拟内存区是从任务创建的当前cpumemset获得的,如果附加到一个已存在的虚拟内存区时,情况会复杂些,如内存映射对象和Unix System V的共享内存区可附加到多个进程,也可以多次附加到同一个进程的不同地方。如果被附加到一个已存在的内存区,缺省情况下新的虚拟内存区继承当前附加进程的cpumemset,如果此时标志位为CMS_SHARE,则新的虚拟内存区链接到同一个cpumemset。

当分配页时,如果该任务运行的CPU在cpumemset中有对应的存储区,则内核从该CPU的内存列表中选择,否则从缺省的CPU对应的cpumemset选择内存列表。

4.3硬分区和CpuMemSets

在一个大的NUMA系统中,用户往往希望控制一部分CPU和内存给某些特殊的应用。目前主要有两种技术途径:硬分区和软分区技术,CpuMemSets是属于软分区技术。将一个大NUMA系统的硬分区技术与大NUMA系统具有的单系统映像优势是矛盾的,而CpuMemSets允许用户更加灵活的控制,它可以重叠、划分系统的CPU和内存,允许多个进程将系统看成一个单系统映像,并且不需要重启系统,保障某些CPU和内存资源在不同的时间分配给指定的应用。

SGI的CpuMemSets软分区技术有效解决硬分区中的不足,一个单系统的SGI ProPack Linux服务器可以分成多个不同的系统,每个系统可以有自己的控制台、根文件系统和IP网络地址。每个软件定义的CPU组可以看成一个分区,每个分区可以重启、安装软件、关机和更新软件。分区间通过SGI NUMAlink连接进行通讯,分区间的全局共享内存由XPC和XPMEM内核模块支持,它允许一个分区的进程访问另一个分区的物理内存。

回页首

五、测试

为了有效验证Linux NUMA系统的性能和效率,我们在SGI公司上海办事处测试了NUMA架构对SGI Altix 350性能。

该系统的配置如下:
CPU:8个1.5 GHz Itanium2
内存:8GB
互连结构:如图3所示

图3 SGI Altix350 4个计算模块的Ring拓扑

测试用例:

1、Presta MPI测试包(来自ASCI Purple的Benchmark)

从互连拓扑结构可以看出,计算模块内部的访存延迟不需要通过互连,延迟最逗,剩下的需要通过1步或2步互连到达计算模块,我们通过Presta MPI测试包,重点测试每步互连对系统的影响,具体结果如下:

最小延迟(us) 一步延迟(us) 两步延迟(us)
1.6 1.8 2.0

2、NASA的NPB测试

进程数

程序名

1 2 4 8
IS 墙钟(s) 10.25 5.38 3.00 1.66
加速比 1 1.9 3.4 6.17
EP 墙钟(s) 144.26 72.13 36.12 18.09
加速比 1 2 3.9 7.97
FT 墙钟(s) 138.29 90.39 47.46 22.21
加速比 1 1.52 2.91 6.25
CG 墙钟(s) 131.65 67.34 36.79 21.58
加速比 1 1.9 3.6 6.1
LU 墙钟(s) 584.14 368.92 144.73 66.38
加速比 1 1.6 4.0 8.7
SP 墙钟(s) 627.73   248.22  
加速比 1   2.5  
BT 墙钟(s) 1713.89   521.63  
加速比 1   3.2  

上述测试表明,SGI Altix 350系统具有较高的访存和计算性能,Linux NUMA技术已进入实用阶段。

本文的Linux NUMA测试工作得到国防科大计算机学院周恩强讲师、SGI公司上海办事处孙晓工程师的大力支持,在此表示衷心的感谢。

回页首

下载

名字 大小 下载方法
ws-statefulws3code.zip   HTTP

关于下载方法的信息

参考资料

  • [1] Matthew Dobson, Patricia Gaughen, Michael Hohnbaum, Erich Focht, “Linux Support for NUMA Hardware”, Linux Symposium 2003
  • [2] Kazuto MIYOSHI, Jun’ichi NOMURA, Hiroshi AONO, Erich Focht, Takayoshi KOCHI, “IPF Linux Feature Enhancements for TX7”, NEC Res. & Develop. Vol.44 No.1, 2003
  • [3] Mel Gorman, “Understanding The Linux Virtual Memory Manager”, 2003
  • [4] Eirch Focht, “Node affine NUMA scheduler”, 2002
  • [5] Paul Larson, “内核比较:2.6 内核中改进了内存管理”,developerWorks 中国网站,2004
  • [6] Steve Neuner, “Scaling Linux to New Heights: the SGI Altix 3000 System”, Linux Journal, Feb, 2003

NUMA (Non- Uniform Memory Access Architecture)相关推荐

  1. 《深入浅出DPDK》读书笔记(三):NUMA - Non Uniform Memory Architecture 非统一内存架构

    本文内容为读书笔记,摘自<深入浅出DPDK>. 47.NUMA系统 之前的章节已经简要介绍过NUMA系统,它是一种多处理器环境下设计的计算机内存结构.NUMA系统是从SMP(Symmetr ...

  2. NUMA全称 Non-Uniform Memory Access,译为“非一致性内存访问”,积极NUMA内存策略

    目录 NUMA的诞生背景 NUMA构架细节 上机演示 NUMA Memory Policy What is NUMA Memory Policy? Memory Policy Concepts Sco ...

  3. Non Uniform Memory Access

    NUMA:Non Uniform Memory Access 非均匀内存访问 不易扩展,CPU数量增多后引起内存访问冲突加剧,CPU的很多资源花在争抢内存地址上面,一般4颗左右比较合适 ZGC - N ...

  4. NUMA - Non Uniform Memory Architecture 非统一内存架构

    Table of Contents Non Uniform Memory Architecture Unlucky NUMA Placement Optimized NUMA placement No ...

  5. 【性能】什么是NUMA(Non-Uniform Memory Access)|什么是SMP

    目录 简略说明 什么是SMP (对称多处理器) 什么是 NUMA? NUMA 的设置 测试 NUMA Linux 的 NUMA 策略 附录1 NUMA(Non-Uniform Memory Acces ...

  6. Non-uniform memory access

    Non-uniform memory access(NUMA)是多处理器系统中的内存设计. 在NUMA中,每个处理器都有自己本地内存(local memory),处理器访问自己的本地内存比访问非本地内 ...

  7. Remote Direct Memory Access (RDMA)

    前言 本博文主要是简单介绍RDMA的概念和与它相关的技术.实现RDMA需要许多其他技术的支持,包括硬件和软件.目前RDMA有多种实现方式,比如RoCE1.INFINIBAND2,不同的实现方式所考虑的 ...

  8. caffe 报错 Check failed: error == cudaSuccess (77 vs. 0) an illegal memory access was encounteredcaffe

    caffe 报错 Check failed: error == cudaSuccess (77 vs. 0) an illegal memory access was encountered 训练时候 ...

  9. 直接内存访问 (Direct Memory Access, DMA)

    Table of Contents 直接内存访问 (Direct Memory Access, DMA) DMA 模型 设备 DMA 的类型 总线主控器 DMA 第三方 DMA 第一方 DMA 主机平 ...

最新文章

  1. 周志华:最新实验表明gcForest已经是最好的非深度神经网络方法
  2. linux yum源安装
  3. python创建一个包,如何从python包创建一个osx应用程序/ dmg?
  4. 【BZOJ1433】【codevs2347】假期的宿舍,最大流
  5. php eval 二进制,PHP eval函数使用介绍
  6. Android开发笔记(六十五)多样的菜单
  7. 23种设计模式(十一)对象性能之单件模式
  8. Python的web相关及Django简介
  9. MED-V服务器配置,MED-V系列之二
  10. RHCE盘点(5)—— 打印机
  11. 信息学奥赛一本通C++版
  12. 内嵌式串口转WiFi模块
  13. java号码归属地接口,免费API-手机号码归属地接口
  14. Mac用命令行在访达中打开指定目录
  15. 网络作战训练模拟仿真管理系统软件
  16. 使用命令提示符分区安装官方Windows10
  17. 从头开始学习JAVA
  18. 10个免费的HTML在线编辑工具
  19. 拼多多盈利模式分析研究
  20. 变量在内存中如何存放c语言,c语言程序中用来存储变量的三种内存

热门文章

  1. 2021年制冷与空调设备运行操作考试APP及制冷与空调设备运行操作找解析
  2. 在精读英文文献时有哪些好习惯?
  3. 谈谈Android的中的Drawable
  4. 【考纲】2013年信息系统项目管理师(高级)考试大纲-刘俊平
  5. 计算机输入法无法启动,电脑输入法不能切换解决方法
  6. awesome PHP之monolog
  7. 以客户为中心,CRM系统可以给企业带来哪些价值?值得一看
  8. 智能家居控制面板:让AI技术为您的家庭带来更多智能化服务
  9. Python按关键字提取txt文本并保存到Excel
  10. 360 QVM启发式引擎的研究