第5章 线程级并行 摘录

5.1 引言

在微处理器发展的推动下,单处理器性能的增长速度在1986年到2003年期间达到高峰。

由于利用ILP的收益越来越少,单处理器的性能增长开始放缓,再加上对功耗的日益关注,计算机体系结构进入了一个新时代。多处理器在从低端到高端的各个领域都扮演了重要角色。

多重处理的重要性在不断提升,原因如下:
        1.  2000~2005年,设计人员尝试进一步利用ILP,而事实表明这种方法的效率很低,因为功耗和硅成本的增长速度快于性能的增长速度。提到快于基本技术的可扩展、通用性能提升的方法,除了ILP之外,我们知道的唯一方法就是多重处理。
        2. 云计算和软件即服务变得越来重要,人们对高端服务器的关注度也在提升。
        3. 互联网上的海量数据推动了数据密集型应用程序的发展。
        4. 认识到提高桌面计算机的性能(至少GPU之外的性能)不再那么重要,要么是当前性能可接受,要么计算密集和数据高度密集的应用程序是在云上运行的。
        5. 深入了解到如何有效地利用多处理器,特别是在服务器环境中。由于大型数据集、自然并行或大量独立请求的并行而产生了显著的内在并行性。
        6. 通过可复用设计而不是独特设计来充分发挥设计投入的效用。所有多处理器设计都具备这一特点。

多核可能只提供有限的扩展性能的可能性。Amdahl定律的效应加上登纳德缩放定律的终结意味着多核的未来可能受限,至少作为一种提高单个应用程序性能的方法是受限的。

TLP意味着多个PC,因此主要通过MIMD加以利用。将TLP引入嵌入式应用程序和高端服务器领域也只是最近的事情。

多处理器定义为由紧耦合处理器组成的计算机,这些处理器的协调与使用通常由单个操作系统控制,它们通过共享地址空间来共享存储器。此类系统通过2种不同的软件模型来利用TLP。
        (1)运行一组紧密耦合的线程,它们协同完成一项任务,这种情况通常称为并行处理。
        (2)由一位或多位用户发起的多个相对独立的进程,这是请求级并行的一种形式。

在大规模多核处理器中,互联网络是设计的一个关键部分。

5.1.1 多处理器体系结构:问题与方法

分配给一个线程的计算量称为粒度大小,在考虑高效利用线程级并行时很重要,但线程级并行与指令级并行的重要定性区别在于:TLP是由软件系统或程序员在较高层级确定的,这些线程由数百条乃至数百万条可以并行执行的指令组成。

线程还能发挥数据级并行的优势,但是开销通常高于使用SIMD处理器或者GPU的情况。这意味着数据的粒度必须足够大才能高效地利用并行。

根据所包含的处理器数量,可以将现有共享存储器的多处理器分为2类,而处理器的数量又决定了存储器的组织方式和互联策略。


        (1)对称多处理器,特点是核数量较少,通常不超过32个,所以处理器可以共享一个集中式存储器并且平等地访问它,这就是对称一词由来。一些多核对最外层的缓存有不一致的访问,即NUCA,不是真正的SMP。再由多个多核芯片组成的多处理器中,每个多核芯片通常都有独立的存储器。因此,存储器是分布式的,而不是集中式的。因为处理器快速访问局部存储器,而对远端存储器的访问要慢得多。随着处理器数量的增加,SMP方法的吸引力越来越小,所以大多数的众核处理器使用某种形式的分布式存储器。SMP体系结构有时也被称为UMA多处理,因为所有处理器访问存储器的延迟都是一致的,即使当存储器被分为多个组时也是如此。


        (2)分布式共享存储器DSM,多处理采用物理分布式存储器。为了支持更多的处理器,存储器必须分散在处理器之间,而不应当是集中式的;否则,存储器系统就无法再不大幅延长访问延迟的情况下为大量处理器提供高带宽支持。将存储器分散在节点上,即增加了带宽,也降低了到局部存储器的延长。DSM多处理也称为NUMA,因为访问时间取决于数据在存储器中的位置。DSM的主要缺点是让在处理器之间传输数据的过程变复杂了,而且需要在软件开发中付出更多努力才能利用分布式存储器提升的存储带宽。

在SMP和DSM这两种体系结构中,线程之间的通信是通过共享地址空间来完成的,也就是说,任何拥有正确访问权限的处理器都可以对任意存储地址进行访问。与SMP和DSM相关的共享存储器一词指的是地址空间是共享的。

5.1.2 并行处理的挑战

两个障碍:
        1. 程序中有限的并行性,很难在任意并行处理器中实现良好的加速比;
        2. 较高的通信成本。

这两个障碍都可以用Amdahl定律来解释。要克服这些障碍,通常需要一种全面的方法来选择算法及其实现、底层的编程语言和系统、操作系统及其支持功能,以及体系结构的硬件实现。尽管在许多情况下,其中之一是瓶颈,但当处理器数量接近100或更多时,通常需要注意软件和硬件的所有方面。

并行处理的第二个重要挑战涉及并行处理器进行远程访问所带来的高延迟。在现有的共享存储器多处理器中,不同核之间的数据通信可能耗费35~50个时钟周期,不同芯片上的核之间的数据通信可能耗费100~500甚至更多时钟周期,具体取决于通信机制、互联网络的类型以及多处理器的规模。

并行度不足和远程通信太高是使用多处理时最大的两个性能难题。应用程序并行度不足的问题必须通过在软件中采用并行性能更高的新算法来解决,还要在软件系统中尽可能多地使用完整的处理器。远程延迟过高的影响可以由体系结构和程序员来降低。例如,我们可以利用硬件机制(缓存共享数据)或软件机制(挑战数据的结构,使应用程序尽量访问局部存储器)来降低远程访问的效率。

5.2 集中式共享存储器体系结构

使用大型多级缓存可以大大降低处理器对存储带宽的需求,这个发现促进了集中式存储器多处理器的发展。最初,这些单核的处理器占据整个主板,而存储器位于共享总线上。随着额近期更高性能处理器的出现,存储器需求超过一般总线的能力,最近的微处理器直接将存储器连接到单个芯片中,这个芯片有时称为后端总线或内存总线,以区别于连接至IO的总线。在访问一个芯片的局部存储器时,无论是为了IO操作,还是为了从一个芯片进行访问,都需要通过“拥有”该存储器的芯片。因此,对存储器的访问是非对称的:对局部访问快,远端访问慢。在多核结构中,存储器由一个芯片上的所有核共享,但是从一个多核的存储器到另一个多核的存储器的访问仍然是非对称的。

采用对称共享存储器的计算机通常支持对共享数据与私有数据的缓存。私有数据供单个处理器使用,而共享数据则由多个处理器使用,基本上是通过读写共享数据来实现处理器之间的通信。在私有数据项被缓存时,它的位置被移往缓存,缩短了平均访问时间并降低了所需要的存储带宽。由于没有其他处理器使用数据,所以程序行为与单处理器中的行为相同。在缓存共享数据时,可能会在多个缓存中复制共享值。除了降低访问延迟和所需要的存储带宽之外,这一复制过程还可以减少争用。不过,共享数据的缓存也引入了一个新问题:缓存一致性。

5.2.1 什么是多处理器缓存一致性

因为两个不同的处理器是通过各自的缓存来保留存储器视图的,所以针对同一存储地址,它们可能会看到不同的值,即缓存一致性问题。

通俗的说,如果每次读取某一数据项都会返回该数据项的最新写入值,就说这个存储器系统是一致的。该定义看似正确,实则含混且过于简单。这个简单定义包含了存储器系统行为的两个方面,对于编写正确的共享存储器程序都至关重要:
        1. 一致性:定义了读操作能返回什么值。
        2. 连贯性:决定了一个写入值什么时候被读操作返回。

如果存储器系统满足以下条件,则说它是一致的:
        1. 处理器P对未知X的读操作跟在P对X的写操作之后,并且在P的写操作和读操作之间没有其他处理器对X执行写操作,此读操作总是返回P写入的值。
        2. 如果一个处理器对位置X的读操作紧跟在另一个处理器对X的写操作之后,读写操作的间隔时间足够长,而且在两次访问之间没有其他处理器对X执行写操作,俺么该读操作将返回写入值。
        3. 对同一位置执行的写操作是被串行化的,也就是说,在所有处理器看来,任意两个处理器对相同位置执行的两次写操作顺序是相同的。

第一个特性只保持了程序顺序。第二个特性定义了一致性存储器视图的含义:如果处理器持续督导一个旧数据值,我们就可以明确地说该存储器是不一致的。第三个特性对写操作串行化的需求更加微妙。假定我们没有实现写操作串行化,而且P1先写入位置X,然后P2写入位置X。某些处理器可能会先看到P2写入的结果,后看到P1写入的结果,并将P1写入的值无限期保存下去。避免此类难题的最简单方法是确保对同一位置执行的所有写操作在所有处理器看来都是同一顺序,这一特性称为写操作串行化。另外,写入值到底必须在多久之后能被读操作读到?这一问题由存储器一致性模型决定。

一致性和连贯性是互补的:一致性确定了向同一存储地址的读写行为,而连贯性则确定了对于其他存储地址的访问的读写行为。现在,做出2条假设,使处理器能够调整读操作的顺序,但强制处理器必须按照程序顺序来完成写操作:
        1. 在所有处理器都看到写入结果之后,写操作才算完成(并运行下一次写入)。
        2. 对于任何其他存储器访问,处理器不会改变任何写入顺序。

5.2.2 一致性的基本实现方案

在一致性多处理器中,缓存提供了对共享数据项的迁移和复制功能。迁移即降低了访问远程共享数据的延迟,也降低了对共享存储器的带宽要求。复制即降低了访问延迟,又减少了对被共享数据项的争用。因此,多处理器没有尝试通过软件来解决一致性问题,而是采用硬件解决方案,通过引入协议来保持缓存一致性。

为多个处理器保持缓存一致性的协议称为缓存一致性协议cache coherence protocol。实现缓存一致性协议的关键在于跟踪数据块的所有共享状态。目前协议采用不同的技术来跟踪共享状态:
        1. 目录协议:特定物理内存块的共享状态保存在一个位置中,称为目录。共有两种目录式缓存一致性,它们的差异很大。在SMP中,可以使用一个集中目录,与存储器或其他某个串行化相关联,比如多核的LLC。在DSM中,使用单个目录没有意义,因为这种方法会生成单个争用点,而且考虑到8核以上的存储器需求,很难扩展到多个多核芯片中。分布式目录比单个目录复杂。
        2. 监听协议:如果一个缓存拥有某一物理内存块中的数据副本,它就可以跟踪该块的共享状态,而不必将共享状态保存在同一个目录中。在SMP中,缓存通常可以通过某种广播介质访问(比如将各个核的缓存连接至共享缓存或存储器的总线),所有缓存控制器都监听这一介质,以确定自己是否拥有总线或交换访问上所请求的副本。监听协议也可用作多芯片多核处理器的一致性协议,有些设计在目录协议的基础上,在芯片间同步使用监听实现。

监听协议在使用微处理器(单核)的多处理器和通过总线连接到单个共享存储器的缓存中变得流行起来。总线提供了一种非常方便的广播介质来实现监听协议。在多核体系结构中,所有多核都共享芯片上的某一级缓存。因此,一些设计转而使用目录协议,因为其开销低。

5.2.3 监听一致性协议

有两种方法可以满足上一节讨论的一致性需求。一种方法是确保处理器在写入某一数据项之前,获取对该数据项的独占访问,即写无效协议。因为它在执行写操作时会使其他副本无效。这是目前最常用的协议。

考虑在处理器执行写操作之后由另一个处理器进行读取:由于写操作独占访问,所以进行读取的处理器所保留的所有副本必须无效(这就是协议名称的来历)。缓存无效的处理器在进行读操作时会发生缺失,必须提取此数据的新副本。对于写操作,我们要求执行写操作的处理器拥有独占访问,禁止任何其他处理器同时写入。如果两个处理器尝试同时写入同一数据,其中一个将会胜利,从而导致另一个处理器的副本无效。另一个处理器要想完成自己的写操作,必须获得此数据的新副本,其中必须包含更新后的取值。因此,这一协议实施了写入串行化。

无效协议的一种替代方法是在写入一个数据项时更新该数据项的所有缓存副本,即写更新或写广播协议。由于写更新协议必须将所有写操作都广播到共享缓存行上,所以它要占用相当多的带宽。为此,最近的多处理器几乎都选择了实现写无效协议。

5.2.4 基本实现技术

在多核中实现无效协议的关键在于使用总线或其他广播介质来执行无效操作。在单芯片多核处理器中,总线可能是私有缓存和共享外部缓存之间的连接。为了执行一项无效操作,处理器只获得总线访问,并在总线上广播要使其无效的地址。所有处理器持续监听该协议,观测这些地址。处理器检查总线上的地址是否在自己的缓存中,如果在,则使缓存中的相应数据无效。

在写入一个共享块时,执行写操作的处理器必须获取总线访问权限来广播其无效。如果两个处理器尝试同时写入共享块,当它们争用总线时,其广播无效操作的尝试将被串行化。第一个获得总线访问权限的处理器会使它正在写入的块的所有副本无效。如果这些处理器尝试写入同一个块,则由总线强制实现的串行化也将串行化它们的写入。这种机制隐含的意思:在获得总线访问权限之前,无法实际完成共享数据项的写操作。所有一致性机制都需要某种方式来串行化对同一缓存块的访问,具体方式可以是串行化对通信介质的访问,也可以是对另一共享结构访问的串行化。

对于写回缓存,查找最新数据值要困难一些,因为数据项的最新值可能放在私有缓存中,而不是共享缓存或存储器中。所幸,写回缓存可以为缓存缺失和写操作使用相同的监听机制:每个处理器都监听放在共享总线上的所有地址。如果处理器发现自己拥有被请求缓存块的脏副本,它会提供该缓存块以回应读取请求,并终止存储器或L3访问。由于必须从另一个处理器的私有缓存提取缓存块,所以增加了复杂性,花费时间通常多于从L3进行提取的时间。由于写回缓存对存储带宽的需求较低,所以它们可以支持更多,更快速的处理器。因此,所有多核处理器都在缓存的最外层级别使用写回缓存。

对于写操作,需要知道是否缓存了写入块的其他副本,如果不存在其他缓存副本,那么在写回缓存中就不需要将写操作放在总线上。如果不用发送写操作,就既可以缩短写入时间,还可以降低所需带宽。

每个总线事务都必须检查缓存地址标记,这些标记可能会干扰处理器缓存访问。减少这种干扰的一种办法就是复制这些标记,并将监听访问引导至这些复制的标记。另一种办法是在共享的L3缓存使用一个目录,这个目录指示给定块是否被共享,那些核心可能拥有它的副本。利用目录信息,可以将无效操作仅发送给拥有该缓存块副本的缓存。这就要求L3必须总是拥有L1或L2中所有数据项的副本,这一特性称为包含。

5.2.5 示例协议

监听一致性协议通常是通过在每个核中整合有限状态机控制器来实现的。这个控制器相应来自核内部的处理器和外部总线(或其他广播介质)的请求,改变所选缓存块的状态,并使用总线访问数据或使其失效。在实际实现中,单个控制器允许交错执行以不同块为目标的多个操作。(即使仅允许同时执行一个缓存访问或一个总线访问,也可以在一个操作完成之前启动另一个操作)另外请记住,尽管在之后介绍以总线为例,但在实现监听协议时可以使用任意互连网络,只要它能够向所有一致性控制器及其相关私有缓存进行广播即可。

若仅考虑三种状态:无效、共享和已修改。共享状态表明私有缓存中的块可能被共享,已修改表示在私有缓存中更新了这个块。注意,已修改状态意味着这个块是独占的。

下表针对写无效协议,写回策略:

每个缓存只有一个有限状态机,其激励信号要么来自所属的处理器,要么来自总线。注意区分上图左右激励信号来源。

为了理解这一协议为何能够工作,可以观察一个有效缓存块,它要么在一个或多个私有缓存中处于共享状态,要么就在一个缓存中处于独占状态。任何到独占状态的转换(处理器写入块时所需要的)都需要在总线上放置一个无效操作或写缺失,从而使所有本地缓存都是这个块无效。另外,如果其他某个本地缓存已经将这个块设为独占状态,该本地缓存将生成一个写回操作,提供包含所需地址的块。最后,对于处于独占状态的块,如果总线上出现对这个块的读缺失,拥有其独占副本的本地缓存会将其状态改为共享。

处理总线上的读缺失和写缺失,实际上就是协议的监听部分。在该协议及扩展协议中,还保留着另外一个特性:任何处于共享状态的存储器块在其外层共享缓存(L2或L3,如果没有共享缓存就是存储器)中总是最新的,该特性简化了实现过程。

尽管这个简单的缓存协议是正确的,但它省略了许多大大增加实现难度的复杂因素。最重要的一点是,这个协议假定操作是具有原子性---在完成一项操作的过程中,不会发生任何中间操作。例如假定采用单个原子形式来检测写缺失、获取总线和接收响应。事实上即使读缺失也可能不具备原子性;在多核处理器的L2中检测到缺失之后,这个核必须通过仲裁,以访问连接到共享L3的总线。非原子性操作可能会导致协议死锁,也就是进入一种无法继续执行的状态。

对于多核处理器,处理器多个核之间的一致性都在芯片上实现,要么使用监听协议,要么使用简单的集中式目录协议。多处理器可以通过连接已经集成在芯片中的高速接口来构建。这些下一级别的互连并不只是共享总线的扩展,而是使用一种不同的方法来实现多核互连。

用多个多核芯片构建而成的多处理器通常采用分布式存储器体系结构,而且需要一种机制来保持芯片间的一致性,这超出芯片内部的机制。在大多数情况下,会使用某种形式的目录机制。

5.2.6 基本一致性协议的扩展

前面介绍的一致性协议是一种简单的三状态协议,即MSI(modified,shared,invalid)协议。扩展协议是通过添加更多的状态和转换来创建的。下面介绍最常见的两种扩展:
        1. MESI协议,添加了独占E状态。用于表示缓存块仅驻存在一个缓存中,而且是干净的。如果一个块处于独占状态,就可以对其进行写入而不会产生任何无效操作。这优化了一个块先由单个缓存读取再由同一缓存写入的情况。当然,在处于独占状态的块产生读缺失时,必须将这个块改为共享状态,以保持一致性。因为后续所有访问都会被监听,所以有可能保持这一状态的准确性。添加独占E状态优点在于:在由同一个核对处于独占状态的块进行后续写入时,不需要访问总线,也不会生成无效操作,因为处理器知道这个块在本地缓存时独占的;处理器只是想状态改为已修改。添加这一状态非常简单,只需要使用将一致状态编码为独占状态的位,并使用脏位表示这个块已被修改。
        2. MOESI向MESI添加“拥有O”状态,表示相关块由该缓存拥有并且在存储器中已经过时。在MSI和MESI协议中,如果尝试共享处于“已修改”状态的块,会将其状态改为“共享”,并且必须将这个块写回存储器中。而在MOESI协议中,可以在原缓存中将这个块的状态由“已修改”改为“拥有”,不再将其写入存储器中。(新共享这个块)其他缓存使这个块保持共享状态:只有原缓存保持“拥有”状态,表示主存储器副本已经过期,指定缓存成为其拥有者。这个块的拥有者必须在发生缺失时提供该块,因为存储器中没有最新内容,如果替换了这个块,则必须将其写回存储器中。

5.2.7 对称多处理器多处理器与监听协议的局限性

随着多处理器中处理器数量的增加,或每个处理器的存储器需求的增加,系统中的任何集中式资源都可能变为瓶颈。因此,多核设计已经转向高带宽、独立内存的互连方案,以允许增加更多的核。例如:
        1. IBM Power8在一个多核中最多拥有12个处理器,它使用8个并行总线连接分布式L3缓存和最多8个独立的存储器通道;
        2. Xeon E7使用3个环来连接最多32个处理器,一个分布式L3缓存以及2个或4个存储器通道;
        3. Fujitsu SPARC64X+使用一个交叉开关将共享的L2缓存连接到最多16个核核多个存储器通道。

对于存储器争用,即使在一个芯片内,访问时间差也会变得非常大。在实践中,软件系统通常对存储器进行组织,使存储器通道与核的一个子集相关联。

监听缓存的带宽也会成为一个问题,因为每个缓存必须检查所有缺失,而增加额外的互连带宽只会将问题推给缓存。

增加监听带宽的方法有如下几种:
        1. 可以复制标记:使得有效的缓存级监听带宽翻了一倍。假设一般的一致性请求没有命中一个监听请求,并且监听请求的成本只有10个周期(而不是15个周期),那么可以将一个CMR的平均成本降低至12.5个周期。这使得一致性缺失率可以为0.08,或者支持一个额外的处理器(7而不是6)。参考文中本小节的计算case。
        2. 如果共享多核上的最外层缓存,则可以分配该缓存,使每个处理器都有一部分存储器,并处理对该部分地址空间的监听。如果在L3缓存中有一个监听命中,那么仍然必须广播到所有的L2缓存,而L2缓存反过来必须监听它们的内容。因为L3缓存充当监听请求的过滤器,所以L3缓存必须具有包含性。
        3. 我们可以将一个目录放在最外层共享缓存的级别上。LLC作为作为监听请求的过滤器,必须具有包含性。在LLC使用一个目录意味着不需要监听或广播到所有的L2缓存,而至需要监听或广播到目录表明可能有块的副本的那些缓存。

分布式缓存系统(方案2或3使用的系统)的多核的组织形式。如果想增加更多的多核芯片以形成更大的多处理器,就需要一个片外网络,以及一种扩展一致性机制的方法。

AMD Opteron展示了监听协议和目录协议之间的另一个折中。存储器被直链到每个多核芯片,最多可以连接4个多核芯片,即NUMA。因为局部存储器更快一些。Opteron使用点对点连接实现一致性协议,最多向其他3个芯片进行广播。因为处理器之间的链接未被共享,所以一个处理器要想知道无效操作何时完成,唯一的方法就是显式确认。因此,一致性协议使用广播来查找可能共享的副本,这一点与监听协议类似,但它使用确认来确定操作,这一点与目录协议类似。

5.4节研究目录协议,它在发生缺失时不需要向所有缓存进行广播。一些多核设计在多核内目录,而另一些设计在扩展到多核之外时添加目录。分布式目录消除了对单点串行化所有访问的需要(通常是监听模式中的单点共享总线),任何删除单点串行化的模式都必须处理与分布式目录模式相同的许多挑战。

5.2.8 实现监听缓存一致性

2017年,所有支持8个及以上的多核多处理器都是用互连网络,而不是单条总线。设计人员不得不面对一项挑战:在不简化总线来串行化事件的情况下实现监听(或目录模式)。

实现监听一致性协议时,最复杂的部分在于:在最近的所有多处理器中,写缺失和更新都不是原子操作。检测写缺失或更新缺失、与其他处理器或存储器通信,为写缺失获取最新值、确保所有无效操作可以正常进行、更新缓存,这些步骤不能再耽搁时钟周期内完成。

在只有一条总线的多核中,如果(在改变缓存状态之前)首先协调连向共享缓存或存储器的总线,并在完成所有操作之前保持总线不被释放,那就可以有效地使上述步骤变成原子操作。处理器怎么才能知道所有无效操作何时完成呢?在早期设计中,当收到所有必要无效操作并在处理时,会使用单根信号线发出信号。收到这一信号后,生成缺失的处理器就可以释放总线,因为它知道在执行与下一次缺失相关的操作之前,可以完成所有读写行为。只要在执行这些步骤期间独占总线,处理器就能有效地将各个步骤变成原子操作。

在没有单一中央总线的系统中,必须寻找其他方法,将缺失过程中的步骤变为原子操作。具体来说,必须确保两个处理器尝试同时写入同一数据块的操作(竞争)保持严格排序:首先处理一个写操作,然后再开始执行下一个。先后顺序并不重要,因为只会有一个获胜者,而它的一致性操作将被首先完成。在使用多条总线的多核中,如果每个存储器块只与一条总线关联,则可以消除竞争,从而确保访问同一个块的两次尝试必须由该公共总线序列化。这个特性,以及重启竞争失败者缺失处理的能力,是在无总线情况实现监听缓存一致性的关键。

还可以将监听与目录结合在一起,有些设计在多核处理器内部使用监听、在多个芯片之间使用目录,或者在一个换成级别使用目录、在另一个缓存级别使用监听。

5.3 对称共享存储器多处理器的性能

在使用监听一致性的多核处理器中,总体缓存性能由两个共同决定:一个是由单处理器缓存缺失造成的流量;另一个是通信导致的流量,它会导致无效及后续的缓存缺失。改变处理器数量、缓存大小和块大小能够以不同方式影响缺失率的两方面。

附录B对单处理器缺失进行3C分类:容量、强制、冲突,并深入讨论了应用特性和对缓存设计的可能改进。以及,有2种来源会引起处理器之间的通信而导致的缺失(通常称为一致性缺失)。
        1. 真共享缺失,源自通过缓存一致性机制进行的数据通信。在基于无效的协议中,处理器向共享缓存的第一次写操作会导致该块的所有权无效。此外,当另一个处理器尝试读取这个缓存块中的已修改字时,并传送结果块。由于这两种缺失都是由处理器之间的数据共享直接导致的,所以都被归类为真共享缺失。
        2. 伪共享缺失,源于使用了基于无效的一致性算法,每个缓存块只有一个有效位。如果因为写入块中的某个字(不是正被读取的字)而导致一个块无效(而且后续访问会导致缺失),就会发生假共享。如果收到无效操作的处理器真的正在使用要写入的字,那这个访问就是真正的共享访问,无论块大小如何都会导致缺失。但是,如果正被写入的字和读取的字不同,那就不会因为这一无效而传送新值,而只是导致一次额外的缓存缺失,所以它是假共享缺失。在假共享缺失中,块被共享,但缓存中的字没有被实际共享,如果块大小是单个字,那就不会发生缺失。

5.3.1 商业工作负载

使用两组组相连缓存来增加缓存大小的效果,这减少了大量的冲突缺失。随着L3缓存的增大,由于L3缺失的减少,执行时间也会缩短。令人惊讶的是,几乎所有改进都是在1~2MB(对4个处理器,使4~8MB)范围内发生,超过这一范围之后,几乎没有明显改进,这是为什么呢?

为了找到这个问题的答案,需要确定造成L3缺失的因素,已经当L3缓存增长时,这些因素是如何变化的。当L3缓存为1MB时,L3存储器访问周期的两个最大来源是指令和容量/冲突缺失;当L3缓存增大时,这两个来源变为次要因素。遗憾的是,强制,假共享和真共享不受增大L3缓存的影响。因此,在4~8MB时,真共享占主导地位。

增大缓存可以消除大多数单处理器缺失,但多处理器缺失不受影响。增加处理器数量如何影响不同类型的缺失呢?假定采用的基本配置是2MB,两路组相连L3。可以预期,真共享缺失率的增加(降低单处理器缺失不会对其有所补偿)会导致每条指令的存储器访问周期增加。

增大块大小影响会是?增大块大小应当能够降低指令和冷启动缺失率,还会在一定范围内降低容量/冲突缺失率,并可能降低真共享缺失率。图中所示:
        1. 真共享缺失率降低因素大于2,表示真共享模式存在某种局部性;
        2. 强制缺失率显著降低,与我们的预期一致;
        3. 冲突/容量缺失有小幅降低(降低因素1.26,而块大小增大到8倍),表示L3缓存大于2MB后所发生的单处理器缺失没有太高的空间局部性。
        4. 假共享缺失率接近翻倍,尽管其绝对值较小。

对指令缓存缺失率没有显著影响,这是令人惊讶。如果有一个仅包含指令的缓存具备这一特性,我们会得出结果:其空间局部性特别差。在采用L2/L3混合缓存时,诸如指令数据冒险之类的其他影响也可能会导致较大块中产生较高的指令缓存缺失率。

在块大小大于64字节后,还必须考虑存储器通信量的增加以及与其他核争用存储器的影响。后者可能会抵消通过提高单个处理器性能的收益。

5.4 分布式共享存储器和目录式一致性

监听式机制没有任何用于跟踪缓存状态的集中式数据结构,这既是它的一个基本优点(因为可以降低成本),也是可扩展性方面的致命弱点。

过去几年,多核处理器的发展迫使所有设计人员转向某种分布式存储器,以支持各个处理器的带宽要求。

可以通过分布式存储器来提高存储带宽和互联带宽。这样会立刻将局部存储器通信与远程存储器通信分离开来,降低对存储器系统和互联网络的带宽要求。除非不再需要一致性协议在每次缓存缺失时进行广播,否则分布式存储器不会带来太大收益。

如前所述,监听一致性协议的代替方法是目录协议。目录中保存了每个可缓存块的状态。目录信息包括哪些缓存(或缓存集合)拥有这个块的副本,它是否需要更新等。在一个拥有最外层缓存LLC的多核中,实现目录机制比较容易:只需为每个L3块保存一个位向量,其大小等于核的数量。这个位向量表示哪些私有L2缓存可能具有L3中某个块的副本,无效操作仅会发送给这些缓存。如果L3是包含性的,那么这一方法对于单个多核非常有效。

在多核中使用单个目录的解决方案是不可扩展的,尽管它避免了广播。这个目录必须是分布式的,并且其分布式必须让一致性协议知道区那里寻找存储器所有缓存块的目录信息。显而易见的解决方案是将这个目录与存储器一起分配,使不同的一致性请求可以访问不同的目录,就像不同的存储器请求访问不同的存储器一样。如果信息是在外部缓存中维护的,那么目录信息可以分布在不同的缓存存储体中,从而有效地增加带宽。

分布式目录保留了如下特性:块的共享状态总是放在单个已知位置。利用这一性质,再指出其他哪些节点可能缓存这个块,就可以让一致性协议避免进行广播操作。

最简单的目录实现方式是将每个存储器块与目录中的一项相关联。在这种实现方式中,信息量与存储器块数和节点数的乘积成正比,其中一个节点就是内部实现一致性的单个多核处理器或一小组处理器。对于处理器少于数百个的多处理器而言(每个处理器可能是多核的),这一开销不会导致问题,因为当块的大小比较合理时,目录开销是可以忍受的。

5.4.1 目录缓存一致性协议:基础知识

目录协议必须实现两种主要操作:处理读缺失和处理共享、干净缓存块的写操作。(对于当前正被共享的块,其写缺失的处理就是上述两种操作的组合)。在简答协议中,目录状态信息如下:
        1. 共享:一个或多个节点缓存了这个块,存储器的值是最新的(所有缓存也是如此);
        2. 未缓存:所有节点都没有这个块的副本;
        3. 已修改:只有一个节点有这个缓存块的副本,它已经对这个块进行了写操作,所以存储器副本已经过期。这个处理器称为这个块的拥有者。

除了跟踪每个潜在共享存储器块的状态之外,还必须跟踪哪些节点拥有这个块的副本,因为在进行写操作时需要使这些副本无效。最简单的方法是为每个存储器块保存一个位向量,当这个块被共享时,这个向量的每一位指明相应的处理器芯片(它可能是一个多核)是否拥有这个块的副本。

每个缓存中状态机的状态与监听缓存时使用的状态机相同,只不过转换时的操作稍有不同。用于定位一个数据项独占副本并使其无效的过程有所不同,因为它们需要在发出请求的节点与目录之间,以及目录与一个或多个远程节点之间进行通信。在监听式协议中,这两个步骤通过向所有节点进行广播而结合在一起。

本地节点是发出请求的节点。主节点是一个地址的存储地址及目录项所在的节点。物理地址空间是静态分布的,所以可以事先知道哪些节点中包含给定物理地址的存储器与目录。例如,地址的高地址可以提供节点编号,而低阶位提供该节点上存储器内的偏移。当主节点是本地节点时,必须访问该目录,因为副本可能存在远程节点中。

远程节点时拥有缓存块副本的节点,该副本可能是独占的(只有一个副本),也可能是共享的。

5.4.2 示例目录协议

在目录协议中,写缺失操作由数据提取和无效操作替代,无效操作由目录控制器选择性地发送。在写入缓存时,它必须处于独占状态,所有共享块都必须在存储器中进行更新。在许多多核处理器中,处理器的LLC在核之间共享,这一级别的硬件使用内部目录或监听来保持同一芯片上每个核的私有缓存之间的一致性。因此,只需要与最外层共享缓存进行交互,就可以使用片上多核一致性机制在大量处理器之间扩展一致性。因为这一交互是在LLC进行的,所以处理器与一致性请求之间的争用就不会导致问题,也可以避免标记的复制。

在目录协议中,目录实现了一致性协议的另一半。发送给目录的一条消息会导致两种不同的操作:更新目录状态;发送额外消息以满足请求。目标中的状态表示一个块的三种标准状态,但与监听机制不同的是,目录状态表示一个存储器块所有缓存副本的状态,而不是表示单个缓存块的相应信息。

除了每个块的状态之外,目录还会跟踪拥有某一缓存块副本的节点集合,使用名为共享者的集合来执行这一功能。在节点数少于64(每节点含有4~8核)中,这一集合通常表示位向量。目录请求需要更新这个共享者集合,还会读取这个集合以执行无效操作。

目录接收3种请求:读缺失、写缺失和数据写回。目录发送的回应消息用黑体表示,而共享者集合的更新用斜体表示。因为所有激励信息都来自外部,所以所有操作都以灰色表示。为简化协议,假定一些操作是原子性,比如请求某个值并将其发送给另一个节点。

当块处于未缓存状态时,存储器中的副本就是当前值,所以对这个块的请求只能是以下两种:
        1, 读缺失:从存储器向发出请求的节点发送其请求的数据,请求者成为唯一的共享节点。块的状态变为共享。
        2. 写缺失:向发送请求的节点传送待写入的值,该节点变为共享节点。这个块变为独占状态,表明缓存了唯一有效的副本。共享者指明拥有者身份。

当块处于共享状态时,存储器值是最新的,所以可能出现两种请求:
        1. 读缺失:从存储器向发出请求的节点发送其请求的数据,请求者被添加到共享者集合中。
        2. 写缺失:向请求者回复值。向共享者集合的所有节点发送无效消息,共享者集合将包含发出请求的节点的身份。这个块的状态变为独占。

当块处于独占状态时,块的当前值保存在一个节点的缓存中,而这个节点有共享者(拥有者)集合识别,所以共有3种目录请求:
        1. 读缺失:向拥有者发送数据提取消息,这会导致拥有者缓存中的这个块的状态转变为共享,拥有者将数据发送给目录,再在这里将其写到存储器中,并发给提出请求的处理器。将发出请求的节点的身份添加到共享者集合中,这个集合中仍然包含拥有者处理器的身份。
        2. 数据写回:拥有者正在替换这个块,因此必须将其写回。这个写回操作会更新存储器副本(主目录实际上变为拥有者),这个块现在未被缓存,共享者集合为空。
        3. 写缺失:这个块有一个新的拥有者。向旧拥有者发送一条消息,使其缓存中的这个块无效,并将值发送给目录,再从目录中发送给提出请求的节点,这个节点现在变成新的拥有者。共享者被设定为新拥有者的身份,这个块仍然保持独占状态。

在采用目录协议以及用网络而非总线来实现监听机制时,协议需要处理非原子化存储器转换。

在现实被优化后目录协议上,当独占块发送读写缺失时,会首先将这个块发送到主节点的目录中,再从这里将其存储到主存储器中,并发送给原来发出请求的节点。

多芯片一致性和多核一致性有4种组合:监听/监听、监听/目录、目录/监听和目录/目录。许多多处理器选择在单芯片内进行某种形式的监听(如果LLC是共享和包含性的),跨多芯片时使用目录协议。这种方法简化了实现,因为只需要跟踪芯片,而非单个核。

5.5 同步:基础知识

同步机制通常是以用户级软件例程实现的,这些例程依赖于硬件提供的同步指令。对于较小的多处理器或低争用场景,关键的硬件功能是不可中断的指令或指令序列,它们能以原子方式提取和改变一个值。

在高争用情景中,同步可能会成为性能瓶颈,因为争用回引入更多延迟,而且在此种多处理器中延迟可能更大。

5.5.1 基本硬件原语

在多处理器中实现同步时,所需要的关键功能是一组能够以原子方式读取和修改存储地址的硬件原语。没有这一功能,构建基本同步原语的成本就会过高,并且会随着处理器数量的增加而增加。一般情况下,架构师不希望用户利用基本硬件原语,而是系统系统程序员用原语来构建同步库。

构建同步操作的一个典型操作就是原子交换,它会将寄存器中一个值与存储器中的一个值交换。假定数值0表示这个锁可以占用,数值1表示这个锁不可用。处理器设置锁的具体做法就是将寄存器中的1与跟这个锁对应的存储器地址交换。如果另外某个处理器以及申请了访问权,则这一交换指令将返回1,否则返回0.

考虑两个试图同时执行交换的处理器:因为只有一个处理器会首先执行操作并返回数值0,第二个处理器进行交换时将返回1,所以不存在竞争问题。使用交换原语来实现同步的关键是这个操作具有原子性:交换不可分的,两个同时进行的交换将由写入串行化机制进行排序。如果两个处理器都尝试以这种方式对同步变量进行置位,它们不可能认为自己同时对这个变量进行了置位。

其他原子原语可用于实现同步。它们都有一个关键特性:读取和更新存储器值的方式可以让我们判断这两种操作是不是以原子形式执行的。在许多较旧的多处理器中存在一种名为测试并置位TAS操作,它会测试一个值,如果通过,就对这个值进行置位。另一个原子同步原语是提取并递增FAI:它返回存储地址的值,并以原子方式使其递增。通过用0值来表示同步变量未被声明,我们可以像使用交换一样使用提取并递增。

实现单个原子存储器操作会引入一些挑战,因为它需要再单个不可中断的指令中进行存储器读写操作。这一要求增加了一致性实现的复杂性,因为硬件不允许在读取与写入之间插入任何其他操作,而且不能死锁。

替代方法是使用一对指令,其中第二条指令返回一个值,从这个值判断出这对指令是否像原子指令一样执行。如果任一处理器执行的所有其他指令要么在这对指令之前执行,要么在这对指令之后执行,就可以认为这对指令具有原子性。

在RISC-V中,这对指令对包含一个名为load reserved的特殊载入指令和一个名为条件存储的特殊存储指令。保留载入将rs1指示的存储器内容加载到rd中,并在该存储器地址上创建一个保留。条件存储将rs2中的值存储到rs1提供的存储器地址中。如果对同一存储地址的写操作破坏了对该载入的保留,则条件存储失败时并将非零写入rd;如果成功,条件存储写入0。如果处理器在两条指令之间进行了上下文切换,那么条件存储总是失败。

链接载入/条件存储机制的优势之一就是它能用于构建其他同步原语;之二是读写操作时明确独立的。链接载入不一定导致任何总线通信。

只有寄存器-寄存器指令才是安全的;否则,就有可能造成死锁,即处理器永远无法完成sc指令。此外,链接载入/条件存储之间的指令数应当很少,以尽可能降低无关事件或竞争处理器导致条件存储频繁失败的概率。

5.5.2 使用一致性实现锁

在拥有原子操作之后,就可以使用多处理器的一致性机制来实现自旋锁---处理器不断尝试获取的锁,它在循环中自旋,直到成功为止。有两种情况会用到自旋锁:
        1. 程序员希望短时间拥有这个锁;
        2. 程序员希望当这个锁可用时,锁定过程的延迟较低。

因为自旋锁会占用处理器,在循环中等待锁被释放,所以在某些情况下不适用。

如果多处理器实现缓存一致性,就可以使用一致性机制将锁放在缓存中,以保持锁值的一致性。将锁放在缓存中有两个好处:
        1. 可以在本地缓存副本完成“自旋”过程(尝试在一个紧凑循环中测试和获取锁),不需要在每次尝试获取锁时都请求全局存储器访问。
        2. 锁访问具有良好的局部性。上次使用了一个锁的处理器,会不不远的将来再次使用它。

要实现第一个好处(在缓存副本完成自旋),还需要修改自旋过程。因为每当尝试进行交换时都需要一次写操作。如果多个处理器尝试获取这个锁,会分别生成这一些操作。这些些操作大多会导致写缺失,因为每个处理器都尝试获取处于独占状态的锁变量。

因此,应当修改自旋锁过程,使其在自旋过程读取这个锁的本地副本,直到看到该所可用为止。然后它尝试通过交换操作来获取这个锁。处理器首先读取锁变量,以检测器状态。

当多个进程尝试使用原子交换来锁定一个变量时的处理器和总线(或目录)操作如下:一旦拥有锁的处理器将0存储到锁中,所有其他缓存都将无效,必须提取新值以更新它们保存的锁副本。这种缓存首先获取锁值(0)的副本,并执行交换。在满足其他处理器的缓存缺失之后,它们发现这个变量已经被锁定,所以必须回过头来进行检测和自旋。

5.6 存储器一致性模型:简介

缓存一致性保证了多个处理器看到的存储器内容是一致的,但它没有说明这些存储器内容应当保持何种程度的一致性。当我们问“何种程度一致性”时,实际是问一个处理器必须在什么时候看到另一个处理器更新过的值。由于处理器通过共享变量(用于数据值和同步两种目的)进行通信,于是这个问题简化为:处理器必须以何种顺序观测另一个处理器的数据写操作?由于“观测另一处理器的写操作”的唯一办法就是通过读操作,所以问题现在变为:在不同处理器对不同位置执行读写操作时,必须保持那些特性?

存储器一致性的最直观的模型称为顺序一致性模型。顺序一致性要求任何程序每次执行的结果都是一样的,就像每个处理器是按照顺序执行存储器访问操作的,而且不同处理器之间的访问任意交错在一起。

实现顺序一致性模型的最简单的方法是要求处理器推迟完成任意存储器访问,直到该访问操作锁导致的全部无效均已完全为止。

尽管顺序一致性模型给出了一种简单的编程范式,但它可能会降低性能,特别是在多处理器的处理器数量很多或者互联延迟很长时。

为了提供更高的性能,架构师已经探索出了2条路径:
        1. 开发了强大的实现方式,能够保持顺序一致性,同时使用延迟隐藏技术来降低代价。
        2. 开发限制条件较低的存储器一致性模型,支持采用更快速的硬件。这些模型可能会影响程序员看待多处理器的方式。

5.6.1 程序员的观点

假定有一种支持高效实现方式的编程模型,认为程序是同步的。如果对共享数据的所有访问都是由同步操作进行排序,那么这个程序就是同步的。如果满足以下条件,就认为数据访问是由同步操作排序的:在所有可能的执行情景下,一个处理器对某一变量的写操作与另一个处理器对该变量的读写由一对同步操作隔离开,其中一个同步操作在第一个处理器执行写操作之后执行,另一个同步操作在第二个处理器执行读写操作之前执行。如果变量可以在未由同步操作排序的情况下更新,则称此类场景未数据竞争。因为操作的执行结果取决于处理器的相对速度,输出是不可预测的。由此得出同步程序的另一个名字:无数据竞争。

程序员可以尝试通过构造自己的同步机制来确保顺序,但这种做法需要很强的技巧性,可能会导致充满漏洞的程序,而且在体系结构上可能不受支持,也就是说在以后换代的新多处理器中可能无法工作。因此,几乎所有的程序员都选择使用针对多处理器和同步类型进行优化的同步库。

5.6.2 宽松一致性模型:基础知识和释放一致性

宽松一致性模型的关键思想是允许乱序执行读写操作,但使用同步操作来确保顺序,因此,同步程序的表现就像处理器具备顺序一致性一样。根据它们放松了那种读取与写入进行分类。
        1. 仅放松W(写)-->R(写)顺序会得到完全存储排序或处理器一致性。由于这种模型保持了写操作之间的顺序,许多根据顺序一致性运行的程序也能在这一模型下运行,不用添加同步。
        2. 放松W-->R和W-->W会得到部分存储顺序的模型。
        4. 放松四种顺序会得到弱排序或释放一致性模型。

通过放松这些顺序,处理器有可能获得显著的性能提升。

释放一致性区分了用于获取对共享访问的同步操作Sa和那些释放对象以允许其他处理器获取访问的同步操作Sr。释放一致性基于这样的观察:在同步程序中,获取操作必须在使用共享数据之前执行,而释放操作必须在共享数据的任何更新之后、下一个获取操作之前执行。这个属性允许通过如下观察稍微放松顺序:在获取操作之前的读取或写操作不需要再获取操作之前完成,并且在释放操作之后的读或写操作不需要等待释放操作。

释放一致性提供了一种限制最少得模型,它易于检查,并且能确保同步程序将看到顺序连贯的执行。尽管大多数同步操作是获取或释放操作(获取操作通常读取同步变量并更新它,而释放操作通常只是写入),但一些操作即充当读取操作又充当释放操作,并导致排序相对弱排序。尽管同步操作总是确保之前的写操作已经完成,但我们可能需要确保在没有指定同步操作的情况完成写操作。一个显式指令FENCE被用来确保该线程中所有之前的指令已经完成,包括所有存储器写入和相关的无效操作。

5.7 交叉问题

多处理器重新定义了许多系统特性:性能评估、存储器延迟和可扩展的重要性等。

5.7.1 编译器优化与一致性模型

定义存储器一致性模型的另一个原因是为了明确编译器可在共享数据上执行那些合法优化。在显式并行程序中,除非明确定义了同步点,而且程序被同步了,否则编译器不能交换对两个不同共享数据项的读操作和写操作,因为这种交换可能会影响程序的语义。

编译器能否从更宽松的一直小魔仙获得好处依然是一个开放性问题:统一模型的缺失,可能会妨碍编译器的发展。

5.7.2 利用推测来隐藏严格一致性模型中的延迟

推测隐藏因为严格一致性模型导致的延迟,获得宽松存储器模型的大多数好处。关键思想:处理器使用动态调度来安排存储器访问的顺序,让它们有可能乱序执行。乱序执行存储器访问可能会违反顺序一致性,从而影响程序的执行。利用支持推测执行的处理器的延迟提交功能,可以消除这种可能性。

如果处理器对存储器请求进行重新排序后,新执行顺序的结果不同于遵循顺序一致性时看到的结果,处理器将会撤销此次执行。关键在于:处理器只需确保其结果与所有访问按顺序完成时一样即可,而通过检测结果可能在什么时候出现不同就可以做到这一点。由于很少会触发推测重启,所以这种方法很诱人。

一个尚未解决的问题是:对于共享变量的存储器访问,编译器技术能优化到什么程序?共享数据通常是通过指针和数组索引进行访问的,这一事实再加上优化技术的现状,已经限制了此种优化技术的使用。RISC-V的设计者在经过长时间争论后选择了释放一致性。

5.7.3 包含性及其实现

所有多处理器都使用多级缓存层级结构来降低对全局互连的要求和缓存缺失延迟。

为了采用多个块大小时仍然保持包含性,在较低级别完成替换时,必须上溯到层次结构的较高级别,以确保较低级别中替换的所有字在较高级别的缓存中都已无效。相联度的不同级别都会产生同类问题。大多数设计人员选择实现包含性,通常是为所有级别的缓存设置一个块大小。例如,Intel i7为L3应用了包含性,即L3总是包含L2和L1的内容。这样就可以在L3实现一个简单的目录机制,在最大程度上降低因为监听L1和L2而对这些场景造成的干扰。

5.8 融会贯通

Power8的每个核都连接一个L3的8MB存储体;其他存储体通过8条独立总线的互连网络访问。因此,Power8是一个真正的NUCA,这是因为对附属L3的存储体的访问速度要远快于对另一个L3的访问。每个Power8的芯片都有一组片间互联链路,可用于构建一个大型多处理器。存储器链接被链接到一个特殊的存储器控制器,其中包含一个L4,还有直接与DIMM相连的接口。

上图展示了拥有20或更多核,Xeon E7处理器芯片是如何组织的。3个环将核和L3缓存存储体链接咋一起,每个核和每个L3存储体都链接到两个环。因此,通过选择正确的环,就可以从任意核访问任一存储体和任一其他核。因此,在芯片内部,E7的访问时间是一致的。但在实践中,E7通常是作为NUMA体系结构运行的,它在逻辑上一半核与每个存储器通道关联在一起,这样就提高了所需存储器页面在一次给定访问中处于开发状态的概率。E7提供3个QuickPath Interconnect链接,用于连接多个E7。

Power8的设计支持16个芯片,共计192核。组内连接在由4个处理器芯片组成的全连接模块之间提供了更高带宽的互连。组间连接用于将每个芯片连接到3个其他模块。因此,每个处理器距离任意其他处理器最多2跳,存储器访问时间取决于一个地址是在局部存储器内还是在集群存储器内,疑惑在集群之间的存储器内。

Xeon E7将一个方块的4个处理器芯片连接在一起,构成一个模块,每个处理器与两个邻居相连接。每个芯片中的第三个QPI连接到交叉开关。采用这种方式可以构建非常大型的系统,在不同的时刻,可以在4个位置进行存储器访问:处理器本地、直接相邻的处理器、寄存中相剧2跳的相邻处理器、通过交叉开关。

5.8.1 基于多核的多处理在处理多程序工作负载时的性能

三者有二在扩展到64核时候回报率降低。Xeon境地可能主要是更多核共用了一个较小的L3。

Power7的加速比看起来超过线性增长,主要是由于是时钟频率的变化导致的。64核配置最高4GHz,而4核配置为3.0GHz。所以在扩展到上百之后,Power7性能回归到线性之下。

将多核和SMT结合:

多核处理器确实将性能提高的更多责任嫁接给程序员。

5.9 谬论与易犯错误

易犯错误: 通过随执行时间线性变化的加速比来测量多处理器的性能。

尽管加速比是并行程序的一个方面,但它并不是对性能的直接度量。第一个问题是所扩展处理器的自身的能力:一个能将性能线性提高到相当于100个Intel Atom处理器的程序,它的速度可能慢于8核 Xeon运行的版本。

谬论: Amdahl定律不适用并行计算机

弱扩展和强扩展区分。

谬论:需要线性加速比来提高多处理器的成本收益

这种观点认为,由于多处理器的成本是处理器数目的线性函数,所以只要低于线性加速比,就意味着性价比下降,使并行处理器的成本效率低于使用单处理器的情况。这种观点的问题在于:成本不仅仅是处理器数目的函数,也依赖于存储器、IO和系统开销。对于具有更高存储器需求的应用程序来说,会大大增强使用多处理器的吸引力。

易犯错误:不要开发利用多处理器体系结构或针对此种结构进行优化的软件。

软件发展长期滞后于多处理器的发展,可能是因为软件问题要难得多。在多处理器上运行软件时,可能会出现一些微小但影响巨大的性能缺陷。和所有其他关键软件组件一样,操作系统算法和数据结构在多处理器上下文中也都必须重新设计。

5.10 多核扩展的未来

在寻找和利用更多ILP的尝试中,效率成本变得令人望而却步(在硅面积和功耗方面都是如此)。当然,多核并没有解决功耗问题,因为它显然增加了晶体管的数量和晶体管的进行开关切换的活动数目,而它们是功耗的两大因素。能耗问题对多核扩展的限制可能比以前认为的更加严重。

由于可用的ILP的数量和ILP的利用效率均受限,所以ILP扩展失败了。同样Amdahl定律和登纳德缩放比例定律的失效导致仅通过增加核心来扩展性能不太可能获得广泛的成功。

5.11 结语

多核并没有解决功耗问题,因为它显然增加了晶体管数量和晶体管开关的活动数目,而这正是增加功耗的两大因素。

多核的确也改变了这场游戏。通过运行将空闲核置于节点模式,可以在一定程度上提高功耗。Intel的Turbo模式允许具有更少处理器的更高时钟频率和具有更低时钟频率的更多处理器之间进行权衡。

更重要的是,多核技术更多地依赖TLP(软件)而不是ILP(硬件),从而减轻了保持处理器繁忙的负担。规避了Amdahl定律小于的多重编程、高度并行的工作负载更容易获得性能优势。

多核技术将大部分重担交给了软件系统,但仍然存在一些挑战和尚未解决的问题。

某些形式的简单多核扩展不太可能提供一种经济有效的性能提升途径。必须克服的一个基本问题:以能源和硅高效的方式寻求程序的高度并行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/236112.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL官网推荐书籍

MySQL官网推荐书籍 图片有防盗链csdn转存失败。有图版传送门MySQL官网推荐书籍 高效的MySQL性能:Daniel Nichter的最佳实践和技术 Daniel Nichter 向您展示了如何应用直接影响 MySQL 性能的最佳实践和技术。您将学习如何通过分析查询执行、为常见 SQL 子句和表联接…

[论文阅读]VoxSet——Voxel Set Transformer

VoxSet Voxel Set Transformer: A Set-to-Set Approach to 3D Object Detection from Point Clouds 论文网址:VoxSet 论文代码:VoxSet 简读论文 这篇论文提出了一个称为Voxel Set Transformer(VoxSeT)的3D目标检测模型,主要有以下几个亮点: 提出了基于…

传统算法: Pygame 实现深度优先搜索(DFS)

使用 Pygame 模块实现了深度优先搜索(DFS)的动画演示。首先,它通过邻接矩阵表示了一个图的结构,其中每个节点表示一个字符,每个字符的邻居表示与之相邻的节点。然后,通过深度优先搜索算法递归地访问所有节点,过程中通过动画效果可视化每一步的变化。每次访问一个节点,该…

leetcode-206-反转链表(C语言实现)

题目: 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 示例 1: 输入:head [1,2,3,4,5] 输出:[5,4,3,2,1]示例 2: 输入:head [1,2] 输出:[2,1]示例 3&…

hash_hmac函数讲解

hash_hmac函数的概述 PHP中的hash_hmac函数是一种基于加密哈希算法的函数,用于计算消息的哈希值。它返回一个哈希值字符串,并且可以用于验证消息的完整性和认证。 哈希是一种将任意长度的消息映射到固定长度的值的算法。哈希函数可以将任意大小的数据转…

Windows系列:Windows的13个版本以及 Windows Server详解(配置)

Windows的13个版本以及 Windows Server详解(配置) 一. Windows的13个版本的区别,企业版、教育版、专业版、工作站版、SE版的主要区别家庭版专业版教育版企业版Servers版 二. Windows Server VS Windows,两者有啥区别?什…

计算机服务器中了_locked勒索病毒如何处理,_locked勒索病毒解密数据恢复

网络技术的不断发展,给企业的生产生活提供了极大便利,越来越多的企业走向数字化办公时代,但网络的发展也为网络安全埋下隐患,网络安全威胁不断增加。近期,云天数据恢复中心陆续接到很多企业的求助,企业的计…

基于Python Flask 的全流程全栈项目自己的实战心得

我基于Python Flask框架开发全流程全栈项目的实战经验和心得。我将介绍整个项目的架构设计、前后端交互、数据库管理以及部署等方面,并提供具体的代码示例。通过这个实例项目,你将学习到如何使用Flask构建一个完整的Web应用,并了解一些常见的…

如何让嵌入式开发板使用主机的网络

配置网络 1.开发板配置 将开发板和主机用网线连接 安装 net-tools,使用 ifconfig 命令 或者使用 ip 命令 su root ip a 发现一个 eth0的网口 ip link set xxx up 有多个网口时可以用该命令启用某一个网口 vim /etc/netplan/00-installer-config.yaml写入以下…

人工智能 - 目标检测:发展历史、技术全解与实战

目录 一、早期方法:滑动窗口和特征提取滑动窗口机制工作原理 特征提取方法HOG(Histogram of Oriented Gradients)SIFT(Scale-Invariant Feature Transform) 二、深度学习的兴起:CNN在目标检测中的应用CNN的…

C++ 学习之匿名名字空间的使用细节

匿名命名空间(anonymous namespace)是C中的一种特殊命名空间,它没有显式的名称。匿名命名空间可以用来定义仅在当前文件中可见的全局变量、函数和类。 由于没有名字,所以相当于直接引入,但是没有引入定义 如果发生冲…

堆栈_有效括号

题比较特殊,主要在于它的所有要输入,都是左括号开头,没有右括号开头的,比如"] [",这种是不算为括号的,由于必然是对称的,若能符合,因而直接在遇到右括号时,检查…