NUMA在Linux上的应用

1. NUMA介绍

NUMA(Non-Uniform Memory Access)是一种计算机内存访问方式,它通过在不同的处理器或处理器组件之间提供多个内存节点,以使每个处理器能够快速访问其本地内存。NUMA架构相比传统的对称多处理(SMP)架构,在处理器之间提供更高的带宽和更低的延迟。

NUMA在高性能计算和服务器领域得到广泛应用,特别是在那些需要大量内存和高处理能力的任务中,如科学计算、虚拟化、数据库和Web服务器等。

2. NUMA的工作原理

NUMA架构中,整个系统内存被划分为多个内存节点(Node),而每个内存节点都与一个或多个处理器核心关联。每个处理器核心都有一个本地内存节点和一个或多个远程内存节点。

当一个处理器核心访问其本地内存时,访问速度相对较快,因为本地内存与处理器核心之间的距离较近,带宽较高,延迟较低。而当一个处理器核心访问远程内存时,访问速度相对较慢,因为远程内存与处理器核心之间的距离较远,带宽较低,延迟较高。

NUMA架构通过使用一种称为“本地性”(Locality)的技术来优化内存访问性能。本地性意味着处理器核心优先访问其本地内存,而不是远程内存。这样可以减少内存访问的延迟,提高系统性能。

3. NUMA在Linux上的应用

3.1 NUMA感知调度

在NUMA架构中,由于不同处理器核心访问不同的内存节点速度不同,内核调度器需要考虑到这一点,以有效地分配任务和内存。

Linux内核提供了NUMA感知调度器,该调度器可以根据不同任务的NUMA特性选择最佳的处理器核心来执行任务,从而最大限度地利用本地内存,减少远程内存的访问。

/*

* Select best cpu in an affected grp for a task

*/

static struct sched_group *

select_idlest_cpu(struct task_struct *p, int target)

{

unsigned int cpumask_bits = cpumask_bits(&p->cpus_allowed);

struct sched_group *group = NULL, *sg;

unsigned long most_idle = ULONG_MAX;

for_each_online_node(node) {

struct sched_domain *sd;

int cpu;

sd = rcu_dereference(per_cpu(sd_node, node));

if (unlikely(!sd))

continue;

/* When there's unused capacity in the system, select from all */

if (cpumask_bits >= nr_cpu_ids)

goto all;

sd = rcu_dereference(per_cpu(sd_llc, target_node));

if (unlikely(sd))

cpumask_and(cpu_llc_shared_mask, p->cpus_allowed,

sched_domain_span(sd));

else

cpumask_copy(cpu_llc_shared_mask, p->cpus_allowed);

sched_domain_best_mask(sd, cpu_llc_shared_mask,

nohz_cpu_mask, NULL,

cpumask_bits, NODE_SELECTOR_OTHER,

NULL, &best_mask);

sg = sd->groups;

for_each_cpu_and(cpu, sched_group_span(sg), idle_cpu_mask) {

unsigned long util = idle_cpu(cpu)->util_avg;

if (util <= most_idle) {

most_idle = util;

group = sg;

}

}

}

3.2 NUMA内存管理

Linux内核还提供了NUMA内存管理功能,用于有效地管理系统中的内存分配和访问。NUMA内存管理器可以确保每个任务分配到与其本地内存节点对应的内存,以减少远程内存访问。

#

# Enable NUMA support

#

CONFIG_NUMA=y

CONFIG_AMD_NUMA=y

CONFIG_X86_64_ACPI_NUMA=y

CONFIG_ACPI_NUMA=y

CONFIG_AMD_NUMA_NUM_NODES=4

CONFIG_NR_CPUS=4096

#

# NUMA Information

#

CONFIG_NUMA_EMU=y

CONFIG_NUMA_BALANCING=y

CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y

CONFIG_NUMA_BALANCING_DEFAULT_ENABLED_DEMAND=y

CONFIG_NUMA_BALANCING_DEFAULT_ENABLED_NUMA=y

CONFIG_NUMA_BALANCING_DEFAULT_ENABLED_AUTONUMA=y

CONFIG_NUMA_BALANCING_DEFAULT_DISABLED=y

CONFIG_NUMA_BALANCING_DEFAULT_EFFICIENT=y

CONFIG_NUMA_BALANCING_DEFAULT_BALANCING=y

CONFIG_NUMA_BALANCING_DEFAULT_MIGRATION=y

CONFIG_NUMA_BALANCING_DEFAULT_RECLAIM=y

CONFIG_NUMA_BALANCING_DEFAULT_FULL=y

CONFIG_NUMA_BALANCING_DEFAULT_MOVE=y

CONFIG_NUMA_BALANCING_DEFAULT_SHIFT=y

CONFIG_NUMA_BALANCING_DEFAULT_FAIR=y

CONFIG_NUMA_BALANCING_DEFAULT_EFAULT=y

#

# NUMA Topology

#

CONFIG_AMDMCA=y

CONFIG_AMD_PCIE_AER=y

CONFIG_TRACER_MAX_TRACE=y

CONFIG_MMIOTRACE=y

#

# Memory Model options

#

CONFIG_X86_USE_NUMA=y

CONFIG_USE_PERCPU_NUMA_NODE_ID=y

CONFIG_NUMA_KBALANCER_INSTANT=y

CONFIG_NUMA_KBALANCER_STATS=y

CONFIG_NUMA_KBALANCER_RATIOS=y

CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y

CONFIG_NUMA_BALANCING_DEFAULT_ENABLED_DEMAND=y

CONFIG_NUMA_BALANCING_DEFAULT_ENABLED_NUMA=y

CONFIG_NUMA_BALANCING_DEFAULT_ENABLED_AUTONUMA=y

CONFIG_NUMA_BALANCING_DEFAULT_ENABLED_MOVE=y

CONFIG_NUMA_BALANCING_DEFAULT_ENABLED_SHIFT=y

CONFIG_NUMA_BALANCING_DEFAULT_ENABLED_FULL=y

CONFIG_NUMA_BALANCING_DEFAULT_ENABLED_FAIR=y

CONFIG_NUMA_BALANCING_DEFAULT_ENABLED_AUTOMIGRATE=y

CONFIG_NUMA_BALANCING_DEFAULT_ENABLED_RECLAIM=y

CONFIG_NUMA_BALANCING_DEFAULT_ENABLED_SYNC=y

CONFIG_NUMA_BALANCING_DEFAULT_SQF=y

CONFIG_NUMA_BALANCING_DEFAULT_BUS_SEQ=y

CONFIG_NUMA_BALANCING_DEFAULT_CACHE_PASS=y

CONFIG_NUMA_BALANCING_DEFAULT_VIA=y

CONFIG_NUMA_BALANCING_DEFAULT_CACHE_FRONT=y

CONFIG_NUMA_BALANCING_DEFAULT_CACHE_SNAPSHOT=y

CONFIG_MEMORY_BALLOON=y

CONFIG_BALLOON_COMPACTION=y

4. 结论

NUMA在Linux上的应用为高性能计算和服务器领域提供了优化的内存访问方式。通过NUMA感知调度和NUMA内存管理功能,Linux内核能够最大限度地利用本地内存,减少远程内存的访问,从而提高系统性能。

操作系统标签