1.硬件层面解决NUMA
在part2的figure2.3中,
我们了解到,在一些机器上,不同的区域访问特定的内存花销不一样。例如,CPU1对它专属的内存的访问速度快于对CPU2专属内存的访问速度。CPU1访问CPU2的内存需要‘多走路’,这个‘多走的路’叫做NUMA factor。
关于NUMA,这是大型计算机才有的问题。这个大型计算机有很多的CPU访问同一个内存。就像上面的例子。我们使用的个人PC一般不涉及NUMA问题,对内存的访问也都是通过一个北桥走的。对于需要解决NUMA问题的大型计算机,他们是如何设计CPU之间的路径的?
这是关于CPU连接的拓扑。图2.3的抽象就是图5.1中的C=2的情况。
关于解决NUMA问题,很多厂商设计了不同的CPU,在此不表。
更常用的的一种方法是:商用计算机进行组网,通过高速网络相连。但这就不涉及NUMA问题,因为他们并没有使用共享的地址空间,因而不在讨论范围内。
2.OS层面解决NUMA
我们还可以在软件层面解决非一致内存访问(NUMA)的问题。
在支持NUMA的机器中,OS必须考虑到内存分散这一特性(即不同的cpu有其本地的memory)。例如,在一个CPU中,创建一个进程,给这个进程分配的内存应该是当前CPU本地(local)的memory。否则,跨U访问花销就大了。当其他的CPU不得不访问这个进程的内存时,那就得多走路了,但OS可以帮忙把这块内存拷贝到其他cpu的内存中。但这实现起来也很麻烦。
为了避免情况更糟,一般OS不要把一个节点(CPU的内存)的进程或线程移动到另一个节点(另一个CPU的内存)。否则,处理很麻烦。但作死移了,有两种解决方案:一是把落脚的内存当作暂时的,时机成熟(我也不知道)再移回去。二是移动的时候,尽量移动到和之前物理页紧邻的页上。
由于NUMA,对于进程来说,并不是所有的内存都是同等的。有的内存都用完了,有的一点儿没用。解决这个问题,需要在内存分配的时候,不要跨U(内存)分配,并且把所有内存stripe the memory(?).所有内存同等看待。但一个副作用就是,很容易就存在进程跨U(内存)移动。对于NUMA不明显的机器,这种方法可以接受,但并非最优。
上面这种内存分配方法是最保守的,是为了不使OS出现致命错误。在linux中,os给了每个进程分配内存所用何种方法的自由。
3.后续
- 系统关于CPU cache的信息
- 跨U访问的花销
请参考原文 。