例如,在具有 2 个四核处理器的双插槽系统中,线程调度程序是否尝试将线程保持在同一处理器中的同一进程中?因为在一个进程中的线程有很多共享内存访问的情况下,在不同的处理器中交错不同进程的线程会降低性能。
1 回答
这取决于。
在当前的 Intel 平台上,BIOS 默认值似乎是内存在系统中的插槽之间逐页交错。分配 1Mbyte,一半在一个套接字上,一半在另一个套接字上。这意味着无论您的线程在哪里,它们都可以平等地访问数据。
这使得操作系统非常简单——任何地方都可以。
这可能对你不利。呈现给操作系统的 SMP 硬件环境是由 CPU 在 QPI 上协作合成的。如果有很多线程都在访问相同的数据,那么这些链接会变得非常繁忙。如果他们太忙,那么这会限制性能,并且您会受到 I/O 限制。这就是我所在的地方;采用英特尔内存子系统设计的 Z80 内核与我实际拥有的 nahelem 内核一样快(好吧,我可能夸大了......)。
归根结底,真正的问题是内存不够快。英特尔和 AMD 最近都在内存方面做了一些令人印象深刻的事情,但我们仍然受到其缓慢的阻碍。理想情况下,内存应该足够快,以便所有内核都有时钟频率访问时间。Cell 处理器就是这样做的——每个 SPE 都有一些 SRAM 而不是缓存,一旦你对它们有所了解,你就可以让它们真正唱歌。
===编辑===
还有更多。正如 Basile Starynkevitch 暗示的那样,另一种方法是采用 NUMA。
NUMA 是现代 CPU 的实际体现,内存访问是不统一的,因为其他 CPU 插槽上的内存不能通过寻址总线直接访问。相反,CPU 通过 QPI 链接(或 AMD 的 Hypertransport)请求数据,以要求其他 CPU 从其内存中获取数据并将其发送回。因为 CPU 在硬件中为您完成所有这些工作,所以最终看起来就像一个传统的 SMP 环境。QPI / Hypertransport 非常快,所以大多数时候它足够快。
如果您编写代码以反映硬件架构,那么理论上您可以进行改进。因此,这可能涉及(例如)在系统中拥有两个数据副本,每个套接字上一个。Linux 中有内存关联例程专门以这种方式分配内存,而不是在所有套接字之间交错。还有 CPU 关联例程允许您控制线程在哪个 CPU 内核上运行,这个想法是您在靠近将要处理的数据缓冲区的内核上运行它。
好的,所以这可能意味着对源代码进行大量投资以使其适合您(特别是如果该数据重复与程序的流程不匹配),但如果 QPI 已成为一个有问题的瓶颈,它是唯一的你可以做的事情。
我在某种程度上摆弄了这个。在某种程度上,这是一个正确的 faff。英特尔和 AMD(以及操作系统和库)的整体思路是为您提供一个 SMP 环境,在大多数情况下,这个环境非常好。但是,它们让您通过加载大量库函数来使用 NUMA,您必须调用这些函数来部署所需的线程和内存。
但是,对于需要一点额外速度的边缘情况,如果架构和操作系统是严格的 NUMA,根本没有 SMP,那会更容易。实际上就像 Cell 处理器一样。更容易,不是因为它写起来很简单(实际上它会更难),而是如果你让它运行起来,你就会确定它是硬件所能达到的一样快。使用我们现在拥有的伪造 SMP,您可以尝试使用 NUMA,但您大多想知道它是否尽可能快。这不像库告诉您您正在访问实际驻留在另一个套接字上的内存,它们只是让您这样做,而没有暗示还有改进的空间。