c - Linux操作系统如何在有多个套接字时调度线程

标签 c linux gcc numa

例如,在具有 2 个四核处理器的双路系统中,线程调度程序是否试图将来自相同进程的线程保持在同一处理器中?因为在进程中的线程有大量共享内存访问的情况下,不同处理器中不同进程的交错线程会降低性能。

最佳答案

视情况而定。

在当前的 Intel 平台上,BIOS 默认设置似乎是内存在系统的插槽之间逐页交错。分配 1Mbyte,一半在一个套接字上,另一半在另一个套接字上。这意味着无论您的线程在哪里,它们都可以平等地访问数据。

这对于操作系统来说非常简单——任何地方都可以。

这可能对您不利。呈现给操作系统的 SMP 硬件环境由通过 QPI 协作的 CPU 合成。如果有很多线程都在访问相同的数据,那么这些链接就会变得非常繁忙。如果他们太忙,那么就会限制性能,并且您会受到 I/O 限制。那就是我所在的地方;采用 Intel 内存子系统设计的 Z80 内核与我实际拥有的 nahelem 内核一样快(好吧,我可能有点夸张了...)。

归根结底,真正的问题是内存不够快。 Intel 和 AMD 最近都在内存方面做了一些令人印象深刻的事情,但我们仍然被它的缓慢所困扰。理想情况下,内存应该足够快,以便所有内核都能以时钟速率访问它。 Cell 处理器有点像这样做 - 每个 SPE 都有一点 SRAM 而不是高速缓存,一旦你了解它们,你就可以让它们真正唱歌。

===编辑===

还有更多。正如 Basile Starynkevitch 暗示的那样,另一种方法是采用 NUMA。

NUMA 是现代 CPU 的实际体现,内存访问是非统一的,因为其他 CPU 插槽上的内存无法通过寻址总线直接访问。相反,CPU 通过 QPI 链接(或 AMD 的 Hypertransport)请求数据,要求另一个 CPU 从其内存中获取数据并将其发回。因为 CPU 在硬件中为您完成所有这些工作,所以它最终看起来像一个传统的 SMP 环境。 QPI/Hypertransport 非常快,所以大多数时候它已经足够快了。

如果您编写代码以反射(reflect)硬件架构,理论上您可以进行改进。因此,这可能涉及(例如)在系统中拥有两份数据副本,每个套接字各一份。 Linux 中有内存关联例程,专门以这种方式分配内存,而不是在所有套接字之间交错分配。还有 CPU 亲和例程,允许您控制线程在哪个 CPU 核心上运行,这个想法是您在靠近它将处理的数据缓冲区的核心上运行它。

好吧,这可能意味着要对源代码进行大量投资才能使它为您工作(特别是如果该数据重复不适合程序的流程),但如果 QPI 已成为一个有问题的瓶颈这是您唯一能做的。

我在某种程度上摆弄过这个。在某种程度上,这是一个正确的 faff。 Intel 和 AMD(以及操作系统和库)的整体思路是为您提供一个 SMP 环境,在大多数情况下,它非常好。但是,它们让您可以通过加载大量库函数来使用 NUMA,您必须调用这些库函数才能部署所需的线程和内存。

然而,对于您想要一点点额外速度的边缘情况,如果架构和操作系统严格采用 NUMA 而不是 SMP 会更容易。实际上就像 Cell 处理器一样。更容易,不是因为它写起来简单(事实上它会更难),而是如果你让它运行起来,你就会确定它是硬件所能达到的最快速度。使用我们现在拥有的伪造 SMP,您可以尝试使用 NUMA,但您大多想知道它是否尽可能快。这不像是库告诉您您正在访问实际上驻留在另一个套接字上的内存,它们只是让您这样做而没有暗示有改进的余地。

关于c - Linux操作系统如何在有多个套接字时调度线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16198057/

相关文章:

c - 内联汇编未知

c - C 编程中的段错误(核心转储)

c - 修改代码以通过引用传递

c# - 尝试在 Linux 上使用 Mono 编译 x64 应用程序会出现 PE32Plus 错误?

linux - 将 bash 脚本作为守护进程运行

c++ - 带有 std::function 的通用 lambda 不捕获变量

c++ - supc++ 的链接顺序真的很重要吗?

c - 从内核读取 seq_file

c - 重新分配的安全方法

python - 在没有 setcap cap_net_raw 的 Linux 中打开原始套接字