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内核能够最大限度地利用本地内存,减少远程内存的访问,从而提高系统性能。