2009-04-10 34 views
13

Azul Systems拥有一个支持数千个缓存一致性CPU的设备。我很想知道为了安排数千个同时运行的线程而需要对操作系统进行哪些更改。1024个CPU的内核调度

回答

6

您要求对操作系统进行可能的更改,所以我认为这项工作背后有一个重要的工程团队。

也有clarififying信息,这将有助于确定问题的参数几块:

多少IPC(进程间通信),你需要什么?
他们是否真的必须是线程,还是他们可以是进程?
如果他们是进程,如果必须通过套接字彼此对话,而不是使用共享内存,那么是否可以?
什么是内存架构?你是直接使用1024核心的SMP,还是有其他一些NUMA(非统一内存架构)或MMP在这里?你的页面表是什么样的?

只知道有关Azul系统的最小信息,我猜你的IPC很少,而且一个简单的“每个内核运行一个内核”模型实际上可能工作得很好。如果进程需要彼此交谈,那么他们可以创建套接字并以这种方式传输数据。你的硬件是否支持这种模式? (你可能最终需要每个内核一个IP地址,并且在1024个IP地址上,这可能很麻烦,尽管它们都可能是NAT的,也可能不是那么重要)。如果当然,这种模式会导致一些效率低下的情况,比如额外的页表,以及相当一部分内存开销,甚至可能不会被硬件系统支持。

即使“每个核心1个内核”不起作用,您可能会运行1024/8个内核,并且会很好,让每个内核控制8个物理CPU。这就是说,如果你想在一个传统的SMP机器上运行1个线程,每个内核只有1024个内核(并且只有少数几个物理CPU),那么我认为旧式的O(1)调度器就是你想要的想。很有可能你的CPU [0]在内核中会以近100%的速度结束并进行中断处理,但对于这种用例来说,这很好,除非你需要超过1个内核来处理你的工作负载。

15

调度成千上万的线程并不是什么大不了的事情,但是在数百个CPU上调度它们是。首先您需要的是非常细致的锁定,或者更好的是,无锁数据结构和算法。当一个CPU执行关键部分时,您不能让200个CPU等待。

5

我没有受过教育的猜测是,当处理器空闲时,每个处理器有一个运行队列和一个工作窃取算法。我可以看到这在M:N模型中工作,每个cpu和轻量级进程都有一个进程作为工作项目。然后,这会和盗取工作的线程池类似,比如Java-7的fork-join库中的线程池。

如果你真的想知道,可以选择Solaris内核或深入Solaris内核代码。我仍然在读设计& FreeBSD的Impl,Solaris Internals是我名单上的下一个,所以我所能做的就是做一个疯狂的猜测atm。

1

我很确定我们在工作中使用的SGI Altix(ccNUMA)使用特殊的硬件来实现缓存一致性。

有一个巨大的开销连接到每个核心相干持有4MB缓存。这不太可能发生在软件上。

在一个256 cpu的数组中,您需要768mb RAM来保存缓存无效位。 12MB缓存/每个缓存行128字节* 256个核心。

+0

是的,Altix机器有所谓的“分布式目录”CC。 – janneb 2009-04-15 18:47:31

1

修改操作系统是一回事,但使用不变的应用程序代码会浪费硬件。当遇到一些限制(取决于硬件)时,为了执行通用代码而保持一致性和同步的努力实在太多了。你可以做到这一点,但它会非常昂贵。 从操作系统方面来说,您需要复杂的关联模型,即不要因为您的CPU繁忙而跳CPU。基于硬件拓扑调度线程 - 在“关闭”的CPU上协作线程以最小化处罚。简单的工作窃取并不是一个好的解决方案,你必须考虑拓扑结构。一种解决方案是分层偷窃 - 按距离窃取工作,将拓扑划分到扇区,并尝试从最近的第一个盗取。 触摸有点锁问题;你仍然会使用自旋锁,但使用完全不同的实现。这可能是CS目前最具专利的领域。 但是,您需要专门针对如此大规模的程序进行编程。或者你会简单地使用它。没有自动的“并行器”会为你做。

6

制定Linux规模一直是一个长期和正在进行的项目。第一个具有多处理器能力的Linux内核具有保护整个内核的单个锁(Big Kernel Lock,BKL),这很简单,但是可扩展性有限。随后,锁定变得更加细致,即有许多锁(数千个),每个锁只覆盖一小部分数据。但是,可以采取多大程度的限制,因为细粒度锁定会变得复杂,并且锁定开销会削弱性能优势,特别是考虑到大多数多CPU Linux系统的CPU数量相对较少。

另一件事是,内核尽可能使用per-cpu数据结构。这非常重要,因为它避免了共享数据的缓存一致性问题,当然也没有锁定开销。例如。每个CPU都运行自己的进程调度程序,只需要偶尔的全局同步。

此外,有些算法是考虑到可扩展性而选择的。例如。一些主要读取数据受Read-Copy-Update(RCU)保护,而不是传统的互斥锁;这允许读者在并发更新期间继续。

至于内存,Linux会尽力从运行进程的同一个NUMA节点分配内存。这为应用程序提供了更好的内存带宽和延迟。

+0

有成千上万的锁。 inode和dnode数据结构每个都包含一个单独的锁。没关系。解锁或锁定和未锁定的锁仅占用几个字节的RAM,并且不占用其他资源。 – Joshua 2009-04-15 19:13:31

1

最简单的方法是将每个进程/线程绑定到几个CPUS,然后只有那些CPU必须争夺该线程上的锁。很明显,需要一些方法来移动线程以平衡负载,但在NUMA体系结构中,您必须尽可能地减少这种情况。

0

即使在双核英特尔系统上,我也确信Linux已经可以使用本地posix线程处理“数千个”线程。 (Glibc和内核都需要配置来支持这个,但是,我相信现在大多数系统现在默认都是这样的)。