1024 CPU的内核调度

13

Azul Systems推出了一种支持数千个高速缓存一致性处理器的设备。我希望能够了解,为了安排数千个同时运行的线程,操作系统需要进行哪些更改。

8个回答

15

调度数千个线程并不是什么大问题,但在数百个CPU上进行调度就比较棘手。首要需要的是非常细粒度的锁定,或者更好的是无锁数据结构和算法。您不能承受让200个CPU等待一个CPU执行关键部分。


6
扩展Linux的规模一直是一个长期而持续的项目。第一个支持多处理器的Linux内核只有一个锁来保护整个内核(称为大内核锁,BKL),这很简单,但限制了可扩展性。
随后,锁定更加细粒度化,即有许多锁(成千上万?),每个锁仅覆盖少量数据。然而,这种做法有其局限性,因为细粒度锁定往往很复杂,并且锁定开销开始消耗性能优势,特别是考虑到大多数多CPU Linux系统相对较少的CPU。
另一个重要的事情是,内核尽可能使用针对每个CPU的数据结构。这非常重要,因为它避免了共享数据的高速缓存一致性性能问题,当然也没有锁定开销。例如,每个CPU都运行自己的进程调度器,仅需要偶尔进行全局同步。
此外,某些算法是基于可扩展性选择的。例如,一些只读数据采用读-拷贝-更新(RCU)而不是传统的互斥锁;这允许读者在并发更新期间继续进行。
至于内存,Linux会尽力从与进程运行的NUMA节点相同的节点分配内存。这为应用程序提供更好的内存带宽和延迟。

有数十万个锁。inode和dnode数据结构各自包含一个单独的锁。这没问题。未锁定或已锁定但未等待的锁只消耗少量RAM字节,不占用其他资源。 - Joshua

6

您正在寻求对操作系统进行可能的更改,因此我假设有一个庞大的工程团队在这个努力背后。

还有一些澄清信息可以帮助定义问题参数:

您需要多少IPC(进程间通信)?
它们真的必须是线程吗,还是可以是进程?
如果它们是进程,那么它们是否可以通过套接字而不是使用共享内存来互相通信?
内存架构是什么样的?您是直接SMP,有1024个核心,还是有其他NUMA(非统一内存架构)或MMP?您的页表是什么样子的?

仅了解Azul系统的最基本信息,我猜测您几乎没有IPC,简单的“每个核心运行一个内核”的模型实际上可能会很好地工作。如果进程需要互相通信,那么它们可以创建套接字并以这种方式传输数据。您的硬件支持这种模型吗?(您可能最终需要每个核心一个IP地址,而且在1024个IP地址时可能会有问题,尽管它们都可以进行NAT,也许这不是一个大问题)。当然,这种模型会导致一些效率低下,例如额外的页表和相当多的RAM开销,甚至可能不受硬件系统支持。

即使“每个核心1个内核”不起作用,您也可以运行1024/8个内核,并且非常好,让每个内核控制8个物理CPU。

话虽如此,如果您想在具有1024个核心(仅有少数物理CPU)的传统SMP机器上每个核心运行1个线程,那么我希望您使用老式的O(1)调度程序。很可能您的CPU [0]最终将近乎100%地处于内核状态并处理中断,但对于这种用例来说,除非您需要超过1个核心来处理工作负载,否则这没问题。


5

我猜测每个处理器都有一个运行队列,并且在处理器空闲时会使用工作窃取算法。我可以看到这种模式在M:N模型中起作用,其中每个CPU都有一个单一的进程和轻量级进程作为工作项。然后,这将感觉类似于Java-7的fork-join库中的工作窃取线程池。

如果你真的想知道,可以阅读Solaris Internals或深入研究Solaris内核代码。我仍在阅读FreeBSD的Design & Impl,而Solaris Internals是我接下来要阅读的书籍,所以现在我只能做出猜测。


1

我非常确定我们工作中使用的SGI Altix(它支持ccNUMA)使用了用于高速缓存一致性的特殊硬件。

每个核心保持4mb高速缓存一致性会有巨大的开销。仅靠软件实现是不可能的。

在一个256个CPU的阵列中,您需要768mb内存来保存高速缓存失效位。 12mb高速缓存/每128字节高速缓存行 * 256²个核心。


是的,Altix机器具有所谓的“分布式目录”CC。 - janneb

1
修改操作系统是一回事,但使用未更改的应用程序代码会浪费硬件资源。当超过某个限制(取决于硬件)时,为了执行通用代码而保持一致性和同步所需的工作量太大了。你可以做到,但代价非常昂贵。 从操作系统方面来看,你需要复杂的亲和模型,即不要跳转 CPU,因为你的 CPU 正忙。基于硬件拓扑的线程调度 - 在“接近”的 CPU 上协作线程以最小化惩罚。简单的工作窃取并不是一个好的解决方案,你必须考虑拓扑结构。一种解决方案是分层工作窃取 - 按距离窃取工作,将拓扑结构划分为区域,并尝试首先从最近的区域窃取。 稍微涉及一下锁问题;你仍然会使用自旋锁等,但使用完全不同的实现方式。这可能是计算机科学中专利最多的领域。 但是,你仍需要为如此大规模的应用程序编写特定的程序。否则,你将简单地未充分利用它。没有自动的“并行化”工具可以为你完成这项工作。

1

最简单的方法是将每个进程/线程绑定到几个CPU,然后只有这些CPU需要竞争该线程的锁。显然,需要有一些方法来移动线程以平衡负载,但在NUMA架构上,必须尽可能地将其最小化。


0
即使在双核英特尔系统上,我相信Linux已经可以使用本地posix线程处理“数千”个线程了。
(但是,Glibc和内核都需要配置才能支持此功能,不过我相信现在大多数系统默认都有这个功能)。

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