最近在做某国产化平台相关的适配, 不管NUMA的性能和实现方式都和Intel有较大不同, 作为比较对象, 理解Intel的NUMA实现是很有必要的. 虽然从软件角度, 打开NUMA会带来额外的复杂度, 但是从硬件角度, 关闭NUMA其实更复杂, 本文尝试分析关闭NUMA时Intel平台的内存编址.
Memory Interleaving
Interleaving是一种基本的编址方式, 可以将连续的物理内存地址映射到不同的内存模块, 比如[0, 256)映射到模块0, [256, 512)映射到模块1, 物理内存分配一般以4KB或者更大粒度的页为分配单位, 这样即使是单线程的程序也能充分发挥底层内存模块的并发性. Interleaving按照内存的层次一般分为Socket, Channel和Rank等, DIY过电脑的同学可能还记得双通道, 也就是Channel Interleaving, 本文主要关心Socket Interleaving, 也就是关闭NUMA时的内存编址. Interleaving的基本思想见下图:
Intel Socket Interleaving
这里以Intel(R) Xeon(R) CPU E5-2682 v4为例, 基于Broadwell EP架构, 其他Intel的CPU应该大致相同. 测试机器插了2个CPU, 内存Interleaving的信息可以从对应的PCI配置空间拿到, 具体到Broadwell EP, 其PCI设备地址是固定的.
#xxd /sys/bus/pci/devices/0000:ff:0f.4/config
0000000: 8680 fc6f 0000 0000 0100 8008 0000 8000 ...o............
0000010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000020: 0000 0000 0000 0000 0000 0000 8680 e06f ...............o
0000030: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000040: 1111 1111 1111 1100 0000 0000 0000 0000 ................
0000050: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000060: c107 0804 0044 1155 c007 0804 0000 0000 .....D.U........
0000070: c007 0804 0000 0000 c007 0804 0000 0000 ................
0000080: c007 0804 0000 0000 c007 0804 0000 0000 ................
0000090: c007 0804 0000 0000 c007 0804 0000 0000 ................
00000a0: