一、什么是NUMA
NUMA的全称是Non-Uniform Memory Access,中文翻译为非一致性内存访问,是一种在多处理器系统中使用的内存架构和访问优化技术。
在NUMA架构下,多个处理器可以共享一部分内存,但是访问不同的内存区域的时间不同,这就是“非一致性”的含义。为了优化访问性能,Linux系统对NUMA架构提供了一些支持和优化手段。
/*
* 查看当前系统是否支持NUMA
*/
# cat /proc/cpuinfo | grep -i numa
二、为什么要使用NUMA
在单处理器系统中,所有内存都是一致的,处理器可以随意访问任何内存位置,不需要花费额外的时间。但是在多处理器系统中,不同处理器访问距离较远的内存位置的时间会变得很长,这就导致了可观的性能下降。
NUMA架构通过将内存分成多个节点来优化内存访问性能。每个节点拥有自己的内存,同时还能够访问其他节点的内存。这样,处理器只需要访问与自己所在节点相邻的内存节点,可以有效减少访问时间。
三、如何使用NUMA
1. 绑定进程
在NUMA架构下,Linux系统提供了一个针对进程的优化手段:CPU和内存绑定。通过指定进程运行的CPU和内存节点,可以提高进程的性能。
/*
* 绑定当前进程到CPU 0 和 NUMA节点 0
*/
# numactl --cpubind=0 --membind=0 <command>
2. NUMA感知分配
NUMA感知分配是一种对内存分配进行优化的手段。在NUMA感知分配中,内存会被分配到最适合它的节点上,而不是默认的全局节点。
/*
* 为指定进程分配一块大小为2GB的内存,并将其分配到NUMA节点1上
*/
# numactl --membind=1 <command>
# ptr = numa_alloc_onnode(2<<30, 1); // 用于内存分配的C函数
3. NUMA感知调度
NUMA感知调度是一种优化调度用于NUMA架构的进程的手段。在NUMA感知调度中,系统会尽量将进程调度到与它绑定的CPU和内存节点相同的CPU上。
/*
* 设置NUMA感知调度
*/
# echo 1 > /proc/sys/kernel/numa_balancing
# echo 1 > /proc/sys/kernel/sched_numa_placement
四、NUMA带来的性能提升举例
下面是在NUMA架构下启用NUMA感知分配和调度的例子。在这个例子中,通过在多个NUMA节点上启用线程,从而使用了多个处理器和多个内存节点,大大提高了程序的性能。
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <numa.h>
#define THREAD_NUM 4
#define MEM_SIZE (1<<30)
void* thread_func(void* arg) {
int node_id = *(int*)arg;
char* mem;
mem = (char*)numa_alloc_onnode(MEM_SIZE, node_id);
for(long i = 0; i < MEM_SIZE; i++)
mem[i] = 1;
}
int main() {
int node_num = numa_max_node() + 1;
pthread_t tids[THREAD_NUM];
for(int i = 0; i < THREAD_NUM; i++) {
pthread_create(&tids[i], NULL, thread_func, (void*)&(i % node_num));
}
for(int i = 0; i < THREAD_NUM; i++)
pthread_join(tids[i], NULL);
return 0;
}
五、总结
NUMA是一种优化多处理器系统中内存访问性能的架构和技术。在Linux系统中,我们可以使用CPU和内存绑定、NUMA感知分配和调度等手段来进行性能优化。