开发线程级并行性
前面描述的技术依赖于程序中可用的并行性来加速执行。除此之外,CPU还支持利用跨进程和/或线程的并行性的技术。接下来,我们将讨论三种利用线程级并行性(TLP)的技术:多核系统、同时多线程和混合架构。这些技术使得能够充分利用可用的硬件资源,并提高系统的吞吐量。
多核系统
随着处理器架构师开始达到半导体设计和制造的实际限制,GHz竞赛减缓,设计师不得不专注于其他创新来提高CPU性能。其中一个关键方向是多核设计,试图增加每代的核心数。其想法是在单个芯片上复制多个处理器核心,并让它们同时为不同的程序提供服务。例如,一个核心可以运行Web浏览器,另一个核心可以渲染视频,另一个可以播放音乐,所有这些都可以同时进行。对于服务器机器,来自不同客户端的请求可以在不同的核心上进行处理,这可以极大地增加系统的吞吐量。
第一个面向消费者的双核处理器是英特尔Core 2 Duo,于2005年发布,随后是同年稍后发布的AMD Athlon X2架构。多核系统导致许多软件组件被重新设计,并影响了我们编写代码的方式。如今,几乎所有面向消费者的设备中的处理器都是多核CPU。在撰写本书时,高端笔记本电脑包含超过十个物理核心,而服务器处理器包含的核心几乎达到100个。
这听起来可能非常令人印象深刻,但我们不能无限地增加核心。首先,每个核心在工作时会产生热量,并且安全地通过处理器封装从核心中散热仍然是一个挑战。这意味着当更多核心运行时,热量可能会迅速超过冷却能力。在这种情况下,多核处理器将降低时钟速度。这是您可以看到具有大量核心的服务器芯片频率明显低于进入笔记本电脑和台式机的处理器的原因之一。
多核系统中的核心彼此连接,也连接到共享资源,例如末级缓存和内存控制器。这样的通信通道称为互连,通常具有环形或网状拓扑结构。CPU设计者面临的另一个挑战是随着核心数量的增加,保持机器的平衡。当您复制核心时,一些资源保持共享,例如内存总线和末级缓存。这导致随着核心的增加,性能回报递减,除非您还解决了其他共享资源的吞吐量,例如互连带宽、末级缓存大小和带宽,以及内存带宽。共享资源经常成为多核系统中性能问题的来源。
同时多线程
改进多线程性能的一种更复杂的方法是同时多线程(SMT)。人们经常使用术语超线程来描述相同的事物。这种技术的目标是充分利用CPU管道的可用宽度。SMT允许多个软件线程在同一物理核心上使用共享资源同时运行。更准确地说,来自多个软件线程的指令在同一周期内同时执行。这些线程不必来自同一个进程;它们可以是完全不同的程序,恰好被调度在同一个物理核心上。
图@fig:SMT。在两种情况下,处理器管道的宽度为四,每个插槽表示发出新指令的机会。100%的机器利用率是指没有未使用的插槽,这在实际工作负载中从不会发生。很容易看出,在非SMT情况下,存在许多未使用的插槽,因此可用资源没有得到充分利用。这可能是由于多种原因引起的;一个常见的原因是缓存未命中。在周期3时,线程1由于等待数据到达而无法取得进展。SMT处理器利用这个机会从另一个线程调度有用的工作。这里的目标是通过另一个线程占用未使用的插槽来隐藏内存延迟,提高硬件利用率和多线程性能。
在SMT2实现中,每个物理核心用两个逻辑核心表示,这些逻辑核心对操作系统显示为两个独立的处理器,可用于接受工作。考虑这样一种情况,我们有16个准备运行的软件线程,但只有8个物理核心。在非SMT系统中,只有8个线程将同时运行,而在SMT2中,我们可以同时执行所有16个线程。在另一种假设情况下,如果两个程序运行在一个启用了SMT的核心上,并且每个程序一直只利用了四个可用插槽中的两个,那么它们以与在该物理核心上
独自运行时一样的速度运行的几率很高。
尽管两个程序运行在同一个处理器核心上,它们彼此完全分离。在启用了SMT的处理器中,即使指令混合在一起,它们也具有不同的上下文,有助于保持执行的正确性。为了支持SMT,CPU必须复制体系结构状态(程序计数器、寄存器)以保持线程上下文。其他CPU资源可以共享。在典型的实现中,缓存资源在硬件线程之间动态共享。用于跟踪乱序执行和推测执行的资源可以复制或分区。
在SMT2核心中,两个逻辑核心确实同时运行。在CPU前端,它们以交替的顺序(每个周期或几个周期)获取指令。在后端,处理器每个周期从所有线程中选择要执行的指令。指令执行混合,因为处理器动态地将执行单元在两个线程之间调度。
因此,SMT是一种非常灵活的设置,可以恢复未使用的CPU发射插槽。SMT提供了相等的单线程性能,除了对多线程的好处外。现代多线程CPU支持两路(SMT2)或四路(SMT4)。
SMT也有自己的缺点。由于某些资源在逻辑核心之间共享,它们最终可能会竞争使用这些资源。最有可能的SMT惩罚是由于对L1和L2缓存的竞争。由于它们在两个逻辑核心之间共享,它们可能在缓存中缺少空间,并迫使将将来将由另一个线程使用的数据逐出。
SMT也给软件开发人员带来了很大的负担,因为它使得更难以预测和衡量在SMT核心上运行的应用程序的性能。想象一下,您在SMT核心上运行性能关键代码,突然操作系统在同一处理器的兄弟逻辑核心上放置了另一个要求严格的作业。您的代码几乎耗尽了机器的资源,现在您需要与其他人共享。在云环境中,这个问题特别突出,因为您无法预测您的应用程序是否会有嘈杂的邻居。
某些同时多线程实现存在安全问题。研究人员表明,一些早期实现存在漏洞,通过这些漏洞可以使一个应用程序从同一处理器的兄弟逻辑核心中监视其缓存使用来窃取关键信息(如加密密钥)另一个应用程序。我们不会深入探讨这个话题,因为硬件安全不在本书的范围内。
混合架构
计算机架构师还开发了混合CPU设计,其中两种(或更多)类型的核心放置在同一处理器中。通常,更强大的核心与相对较慢的核心配对,以解决不同的目标。在这样的系统中,大核心用于延迟敏感的任务,而小核心则提供了较低的功耗。但是,两种类型的核心也可以同时使用,以提高多线程性能。所有核心都可以访问相同的内存,因此工作负载可以在大核心和小核心之间动态迁移。其目的是创建一个能够更好地适应动态计算需求并使用更少功耗的多核处理器。例如,视频游戏既有单核心突发性能的部分,也有可以扩展到多个核心的部分。
第一个主流的混合架构是ARM的big.LITTLE,于2011年10月推出。其他供应商也采用了这种方法。苹果于2020年推出了其M1芯片,具有四个高性能的“Firestorm”核心和四个节能的“Icestorm”核心。英特尔于2021年推出了其Alderlake混合架构,顶级配置中配备了八个P核心和八个E核心。
混合架构结合了两种核心类型的优势,但它也带来了一系列挑战。首先,它要求核心完全兼容ISA,即它们应该能够执行相同的指令集。否则,调度就会受到限制。例如,如果大核心具有一些小核心上不可用的高级指令,那么您只能将大核心分配给使用这些指令的工作负载。这就是为什么通常供应商在选择混合处理器的ISA时使用“最大公约数”的方法。
即使具有ISA兼容的核心,调度也变得具有挑战性。不同类型的工作负载需要特定的调度方案,例如,突发执行与稳定执行,低IPC与高IPC,低重要性与高重要性等。这很快就变得不那么简单了。以下是一些优化调度的考虑因素:
- 利用小核心以节省功耗。不要为后台工作唤醒大核心。
- 识别适合转移到较小核心的候选项(低重要性,低IPC)。类似地,将高重要性,高IPC任务提升到大核心。
- 在分配新任务时,首先使用空闲的大核心。在SMT的情况下,使用两个逻辑线程都空闲的大核心。之后,使用空闲的小核心。之后,使用大核心的兄弟逻辑线程。
从程序员的角度来看,不需要对代码进行任何更改就可以利用混合系统。这种方法在面向客户的设备中变得非常流行,特别是在智能手机中。