在NUMA硬件上进行内存分配和访问

8
我正在使用Python开发一款科学计算工具,它应该能够在NUMA共享内存环境中分配工作到多个核心上。我正在寻找最有效的方法。
线程不幸地退出游戏了,因为Python的全局解释器锁定,这让fork成为我唯一的选择。对于进程间通信,我认为我的选择是管道、套接字或mmap。如果列表中有遗漏的,请指出。
我的应用程序将需要相当多的进程间通信,并访问一些共同数据。我的主要关注点是延迟。
我的问题:当我fork一个进程时,它的内存是否会位于它被分配到的核心附近?由于*nix上的fork是写时复制,所以最初我认为这不可能是这种情况。我想强制进行内存复制以获得更快的内存访问,如果是这样,最好的方法是什么?如果我使用mmap进行通信,那么该内存还会分布在多个核心上,还是只会位于一个核心上?是否存在透明重新定位数据以优化访问的进程?是否有一种直接控制物理分配的方法,或者一种请求有关分配信息以帮助优化的方法?
在更高的层面上,这些事情中哪些是由硬件决定的,哪些是由操作系统决定的?我正在购买一台高端多插槽机器,对于AMD Opteron和Intel Xeon之间的选择存在疑问。具体硬件对以上任何问题的影响是什么?

1
如果代码是用Python编写的,那么在这个级别上担心性能是愚蠢的 - 解释器开销很可能会淹没NUMA所产生的任何差异。 - Joseph Garvin
Python可以调用用C语言编写的程序,例如numpy。此外,Pypy使得Python脚本变得相当高效。多个具有共享内存的进程与NUMA的交互方式也是一个有趣的问题。 - Paul Harrison
2
事实上,我认为Python是一种方便的语言,可以以灵活的方式将C代码片段粘合在一起。如果以正确的方式完成,我相信解释器开销可以保持较低水平。 - gertjan
1个回答

6
由于Python的GIL是其致命弱点之一,因此有更好的多进程支持。例如,有队列、管道、锁、共享值和共享数组。还有一种称为Manager的东西,它允许您以IPC友好的方式包装许多Python数据结构并共享它们。我想大多数这些都是通过管道或套接字工作的,但我还没有深入研究过内部机制。

http://docs.python.org/2/library/multiprocessing.html

Linux如何建模NUMA系统?

内核检测到正在运行于多核机器上,然后检测硬件数量和拓扑结构。然后使用节点的概念创建此拓扑结构的模型。节点是一个物理插座,其中包含一个CPU(可能有多个核)和连接其上的内存。为什么基于节点而不是基于核心?因为内存总线是将RAM连接到CPU插座的物理电线,单个插座中的所有CPU核心都对该内存总线上驻留的所有RAM具有相同的访问时间。

如何让一个内存总线上的内存被另一个内存总线上的核心访问?

在x86系统上,这是通过缓存来实现的。现代操作系统使用一个叫做转换后备缓存(TLB)的硬件来将虚拟地址映射到物理地址。如果缓存需要获取的内存是本地的,则在本地读取。如果不是本地的,则会通过AMD系统上的Hyper Transport总线或Intel上的QuickPath总线到达远程内存以满足需求。由于它是在缓存级别上完成的,理论上您不需要了解它。当然,对于高性能应用程序,了解它非常有用,以最小化远程访问的数量。

操作系统实际上在哪里定位虚拟内存的物理页面?

当一个进程被复制时,它会继承所有父进程的页面(由于COW)。内核知道哪个节点对该进程最适合,这就是它的“首选”节点。这可以修改,但默认情况下与父节点相同。除非明确更改,否则内存分配将默认为与父节点相同的节点。

是否有一个透明的过程来移动内存?

没有。一旦内存被分配,它就被固定在分配它的节点上。您可以在另一个节点上进行新的分配,移动数据,并在第一个节点上取消分配,但这有点麻烦。

是否有一种控制分配的方法?

默认情况下,分配到本地节点。如果使用libnuma,可以更改分配方式(例如轮询或交错),而不是默认为本地。

我从这篇博客文章中获取了很多信息:

http://blog.jcole.us/2010/09/28/mysql-swap-insanity-and-the-numa-architecture/

我强烈建议您阅读全文以获取更多信息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接