我的意思是,在操作系统的实现中,什么机制可以完成这项工作?例如,在 Linux 内核中?或者,众所周知,有一些工具可以方便地实现这一点,比如 Windows 任务管理器,但内部机制是什么?
1 回答
快速回答
在 Linux 中,您需要查看 sched_setaffinity() 或 pthread_setaffinity_np()。
更长的答案
您需要对核心亲和性相当小心(即,将进程/线程指定给某个核心)。现代 CPU 和操作系统会做各种各样的事情,以使在一般情况下不必摆弄核心亲和力,如果您摆弄并弄错了,这些可能会开始对您不利。
例子
在双芯片 i7 平台上,它确实会变得相当复杂。在这样的平台上,超线程意味着 BIOS 报告 16 个内核,其中只有 8 个是真实的。将两个线程绑定到一个核心及其超线程的另一个自我很容易导致两个慢线程。
内存通常在两个芯片之间交错,一次 4kpage(另一种 BIOS 设置)。因此,将线程绑定到特定核心可以使其远离正在操作的数据;这会使两个芯片之间的 QPI 链接过载并减慢一切。顺便说一句,您也可以将内存分配给芯片,看看这个。这是一个复杂的话题,但你可能也必须接受它。
一般来说,跨机器内核、芯片和 SIMM 的线程及其内存的最佳部署是特定于每台 PC 的。例如,考虑一台机器中有两个 i7;最佳部署取决于插入了多少内存 SIMM。这些是操作系统非常清楚的事情,并且通常可以很好地移动线程以获得最佳性能。
您必须有一个非常特殊的环境,您会发现自己进行分发会更好。除非你有一个非常固定的硬件配置,否则你已经编写了你的应用程序,以便它在每次运行时为自己确定最佳部署。这是很多编程工作。
概括
简而言之,通常最好不要管它。
英特尔做了什么
让我们退后一步,看看英特尔当前设计背后的理念是什么,其中存在两个或更多芯片。
英特尔决定,一般来说,计算机在不同的数据集上同时执行许多不同的任务,线程和进程之间仅适度共享数据。这允许他们使用 QPI 合成一个 SMP 架构,将他们的 CPU 绑定到一个公共内存映射中(否则它将是严格的 NUMA,而不是 SMP)。在一般情况下,这会提供出色的性能。当然,AMD 早在几年前就得出了同样的结论,并使用 Hypertransport 来实现它。
重要的是,就应用程序和操作系统而言,它还提供了简单性,因为整台机器中的每个内核都可以看到整个内存,即使只是通过 QPI 间接地看到。
规则的例外
但是,如果应用程序的性质是由每个内核上的线程处理的海量数据集,那么 QPI 上的内存远程性可能是一个问题。该架构必须保持所有 CPU 之间的缓存一致性,因此 QPI 链接最终可能会因内存访问和缓存一致性流量而受到影响。例如,在我使用的平台上,QPI 只有 19GB/s,而每个 CPU 的三个内存库都有 25GB/s。这可能在英特尔最近的芯片上发生了变化。
在这种情况下,最好将这两个芯片视为 NUMA 架构。这可以通过分配数据集 NUMA 的两个副本来完成,这样每个 CPU 都有自己的副本。还可以让线程只处理本地内存。这减轻了 QPI 链路的负担。
围绕芯片的行为工作
如果一个人要优化到这种程度,那么一个人很快就会开始不喜欢现代 CPU 架构中内置的泛化。例如,缓存会假设要加载哪些数据、何时加载以及何时更新 RAM 和其他缓存。一般来说,这很好,但有时一个人知道得更好。
对我来说,最好的 CPU 是 Playstation 3 中使用的 Cell 处理器。在它的八个数学核心中,它没有缓存,所以没有缓存一致性,什么也没有。程序员全权负责让 DMA 引擎(我希望 Intel 包括)在正确的时间将数据移动到正确的位置,以便由正确的代码处理。或者可以将数据留在原处,然后将代码 DMA 到数据中。它非常复杂,需要大量的脑力,但如果做对了,你可以获得巨大的数学性能(2005 年为 200GFLOPs;领先英特尔数英里)。
至于哪种哲学是对的?好吧,英特尔正在抨击 Core this 和 Xeon that,而 Cell 则垂死挣扎。事实证明,没有多少程序员能够通过自己控制一切来获得最佳性能。