您的位置:

深入浅出Linux NUMA

一、什么是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感知分配和调度等手段来进行性能优化。