Linux下的NUMA API
版本为2.5之后的linux内核在进程调度,内存管理等方面对NUMA系统做了大量优化。同时,基于2.6内核版本的各主要linux发行版,如Redhat,SUSE等均包括了面向用户空间的numautils工具包,提供对NUMA系统内存策略的监控功能,并开放面向用户空间程序的API接口。该接口习惯上称为NUMA API。
NUMA API主要任务是管理NUMA的内存策略。NUMA策略通过几个子系统的协同工作来实现。内核管理进程的内存分配机制以及特殊的内存映射。NUMA API通过新引入的3个内核系统调用来实现这一点。在用户空间中,NUMA API通过libnuma库提供了统一的接口供用户空间程序使用。相对于系统调用,libnuma接口更加清晰易用。同时NUMA API还提供了命令行工具numactl和numastat来帮助系统管理员实现进程级别的策略管理。
在Linux上NUMA API支持四种内存分配策略:
缺省(default) - 总是在本地节点分配(分配在当前线程运行的节点上)
绑定(bind) - 分配到指定节点上
交织(interleave) - 在所有节点或者指定的节点上交织分配
优先(preferred) - 在指定节点上分配,失败则在其他节点上分配
绑定和优先的区别是,在指定节点上分配失败时(如无足够内存),绑定策略会报告分配失败,而优先策略会尝试在其他节点上进行分配。强制使用绑定有可能会导致前期的内存短缺,并引起大量换页。在libnuma库中,优先和绑定是组合在一起的。通过对线程调用uma_set_strict函数,可以在两种策略间切换。缺省的策略是更加普适的优先策略。
策略可以基于进程或内存区域设定。进程策略对整个进程内的内存分配都有效,而内存区域策略作用于指定的内存区域,其优先级比进程策略要高。
进程策略 作用于所有由内核分配的内存页,包括malloc, 系统调用中使用的内核级的分配以及文件缓冲区等。唯一的例外是,中断中分配的内存总是在当前节点中。当子进程Fork时,会继承父进程的进程策略。
内存区域策略 又称为VMA策略,它允许一个进程为自己地址空间里的一块内存设置策略。内存区域策略比进程策略具有更高的优先级。它的主要优点在于能够在分配发生前进行设置。目前,内存区策略只支持一部分内存机制,如:SYSV共享内存,shmem和tmpfs文件映射,以及hugetlbfs文件系统。在共享内存段或文件映射被删除前,共享内存的区域策略会一直有效。
Linux系统提供命令行及编程API两级用户空间工具来对策略进行控制。
UMACTL 是设定进程NUMA策略的命令行工具。对于那些无法修改和重新编译的程序,它可以进行非常有效的策略设定。Numactl使管理员可以通过简单的命令行调用来设定进程的策略, 并可以集成到管理脚本中。
Numactl的主要功能包括:
1. 设定进程的内存分配基本策略
2. 限定内存分配范围,如某一特定节点或部分节点集合
3. 对进程进行节点或节点集合的绑定
4. 修改命名共享内存,tmpfs或hugetblfs等的内存策略
5. 获取当前策略信息及状态
6. 获取NUMA硬件拓扑
下面是使用numactl设定进程策略的实例:
numactl --cpubind=0 --membind=0,1 program
其意义为:在节点0上的CPU运行名为program的程序,并且只在节点0,1上分配内存。Cpubind的参数是节点编号,而不是cpu编号。在每个节点上有多个CPU的系统上,编号的定义顺序可能会不同。
下面是使用numactl更改共享内存段的分配策略的实例:
numactl --length=1G --file=/dev/shm/interleaved --interleave=all
其意义为: 对命名共享内存interleaved进行设置,其策略为全节点交织分配,大小为1G。
NUMASTAT 是获取NUMA内存访问统计信息的命令行工具。对于系统中的每个节点,内核维护了一些有关NUMA分配状态的统计数据。numastat命令会基于节点对内存的申请,分配,转移,失败等等做出统计,也会报告NUMA策略的执行状况。这些信息对于测试NUMA策略的有效性是非常有用的。
http://software.intel.com/zh-cn/blogs/2009/01/22/numaxeon9/
总的来讲,实践出真知,不知道具体场景有什么区别,学习策略白扯的事情。