并行处理器:从客户端到云(一)

1.写在前面

前面的博客我们介绍完了计算机系统的存储系统,今天我们来介绍下并行处理器。

2.引言

长久以来,计算机架构师一直在寻找计算机设计的"黄金之城":只需要简单地连接许多现有的小计算机,就可以制造出一台功能强大的计算机。这个"黄金愿景"就是多处理器产生的根源。在理想情况下,客户根据自己的支付能力订购尽可能多的处理器,并希望以获得相应多的性能。因此,必须将运行在多处理器上的软件设计为可以运行在数量可变的处理器之上。能耗已经成为微处理器和数据中心要面对的首要问题。如果软件可以有效地使用处理器,那么使用大量小型、高效的处理器替换大型、低效的处理器,每单位焦耳就可以在不同类型的处理器中都提供更好的性能。因此,在多处理器情况下,除了可伸缩的性能外,还需要关注提升能源效率。

由于多处理器软件支持数量可变的处理器系统,所以有一些设计支持在部分硬件损坏的情况下继续进行操作。也就是说,如果在具有n个处理器的多处理器中有1个处理器出现故障,这些系统将继续使用剩下的n-1个处理器提供服务。因此,多处理器也可以提高可用性。

对多个相互独立的任务来说,高性能意味着更高的吞吐量,我们称之为任务并行或进程级并行。这种多任务、单线程、相互独立的应用程序组织方式在多处理器中非常重要并且普遍使用。与之相对的是在多个处理器上运行单个任务,我们使用术语并行处理程序来指代同时运行多个处理器上的单个程序。

在过去的几十年中,存在很多的科学问题需要速度更快的计算机,同时这些问题也被用于评价许多新型并行计算机的性能。通过使用集群这种由许多位于独立服务器中的微处理器组成的结构,这其中的一些问题在今天已经十分容易解决。除此以外,集群还可以为除科学之外的其他同等需求的应用程序提供服务,例如搜索引擎、Web服务器、电子邮件服务器和数据库等。

由于能耗问题意味着未来处理器性能的提升主要来自于显示的硬件并行,而不是更高的时钟频率或更大的CPI提升,因此多处理器已经成为受人瞩目的焦点。它们被命名为多核微处理器,而不是多处理器微处理器,这可能是为了避免名称上的冗余。因此,处理器在多核芯片中通常被称为核心,核心数量预计按照摩尔定律的速度增长。这些多核基本都是共享内存处理器(SMP),因为它们通常共享同一个物理地址空间。

3.创建并行处理程序的难点

并行性的困难并不在于硬件,而是在于只有很少的重要应用程序在被重写后能够在多处理器上更快地完成任务。事实上,编写软件以利用多处理器使得单个任务的运行更加快速是十分困难的,并且在处理器的数量增加时问题会变得更加严重。

是什么造成了这些问题?

  1. 你必须通过在多处理器上运行的并行处理程序获得更好的性能或更高的能效,否则,为什么不在单处理器上运行顺序程序呢?顺序程序的编程更加简单。事实上,单处理器设计技术(超标量和乱序执行)都充分利用了指令级并行,而且通常不需要程序员的参与。这些创新减少了重写多处理器程序的需求,因为程序员对这种重写无能为力,而且即使什么都不做,顺序程序也能在新计算机上运行得更快。

    为什么编写快速的并行处理程序很困难?举个例子:我们使用了八个记者试图同时编写一个故事以期能够快八倍地完成这样工作的类比。要想成功地完成工作,任务必须被分成相同大小的八个部分,否则一些记者都会因为等待分配到较大工作量的人员完成任务而产生闲置时间。另一个影响加速的障碍是记者可能会将太多的时间花费在沟通上,而不是用于写下自己负责的那部分故事上。无论是这个类比还是并行编程本身,都要面临如下挑战:调度、将工作划分为可并行的部分、在工作者之间均衡负载、同步时间以及处理各部分之间通信的开销。而随着在报纸上报道故事的记者数量的增加,以及参与并行编程的处理器数据的增多,这种挑战会变得更加严峻。

    我们的讨论还揭示了另外一个障碍,它被称为Amdahl定律。该定律提醒我们,如果一个程序想要充分地利用许多核心,那么即使是改成的很小的一部分也必须进行优化。

    拓展:强比例缩放意味着在保持问题规模不变的同时所测量的加速比。弱比例缩放意味着问题规模与处理器的数量成比例增长时所测量的加速比。我们假设问题规模M是主存中的工作集,处理器数量为P,那么每个处理器所占用的内存对于强比例缩放大约为M/P,对于弱比例缩放大约为M

    需要注意的是,存储器层次结构可能会干扰认为弱比例缩放比强比例缩放更简单的传统观念。举例来说,如果弱比例缩放的数据集不再适用于多核处理器的最后一级cache,那么可能会导致系统性能比使用强比例缩放更加糟糕。

4.SISD、MIMD、SIMD、SPMD和向量机

传统的单处理器具有单个指令流和单个数据流,传统的多处理器具有多个指令流和多个数据流。这两个类别分别缩写为SISD和MIMD

在这里插入图片描述

尽管可以在MIMD计算机上编写运载在不同处理器上的独立程序,但是,为了实现更宏大、更协调的目标,程序员通常会编写一个运行在MIMD计算机中所有处理器上程序,不同的处理器通过条件语句执行不同的代码段。这种编程风格称为单程序多数据流,它是在MIMD计算机上编程的一种常用的方法。

最接近多指令流但数据流(MISD)的处理器应该是"流处理器"了,这种处理器在但数据流上以流水线方式执行一系列计算:解析来自网络的输入,分析数据,解压缩,查找匹配,等等。相比之下,与MISD相反的类型—SIMD更欢迎一些。SIMD计算机对数据向量进行操作。

SMID的优点是所有的并行执行单元都是同步的,它们都响应自同一程序计数器(PC)中发出的同一指令。从程序员的角度看,这与他们已经熟悉的SISD的概念非常接近。尽管每个单元将执行相同的指令,但是每个执行单元都有自己的地址寄存器,因为每个单元可以有不同的数据地址。一个顺序应用程序编译后,既可能在组织为SISD的串行硬件上运行,也可能在组织为SIMD的并行硬件上运行。

SIMD的初衷是在数个执行单元上分摊控制单元的成本。因此SIMD的另一个优点是减少指令带宽和空间----SIMD只需要同时执行代码的一个副本,而消息传递的MIMD可能需要在每个处理器中都存在一个副本,而共享存储器的MIMD可能需要多个指令缓存。

SIMD在处理for循环中的数组时效果最好。因此,为了在SIMD上并行运行,程序中必须存在大量相同结构的数据,这称为数据级并行。SIMD在处理case和switch语句效果最差,在这些语句中,每个执行单元必须根据单元内存放的不同数据对这些数据执行不同的操作。存放有错误数据的执行单元必须被禁止执行,以便存放有正确数据的执行单元可以继续工作。在有n个case的语句的情况下,SIMD处理器基本上只能以峰值性能的1/n工作。

虽然促使SIMD类型产生的阵列处理器已经逐渐淡出历史,但是目前对SIMD的两种解释依然活跃。

4.1x86中的SIMD:多媒体扩展

1996年x86多媒体扩展(MMX)指令的灵感来源是窄整数数据的子字并行。随着摩尔定律的持续,更快的的指令被添加进来,首先引入的流式SIMD扩展和高级向量扩展(AVX)AVX支持同时执行四个64位浮点数。操作和寄存器的宽度被编码在这些多媒体指令的操作码中。随着操作和寄存器的数据宽度的增加,多媒体指令的操作码数量也在增加。

4.2向量机

正如我们将要看到的那样,对SIMD更加古老、更加优雅的解释被称为向量体系结构,这与Seymour Cray在20世纪70年代开始设计的计算机密切相关。这种体系结构与具有大量数据并行的问题非常匹配。与早期的阵列处理器一样,64个ALU并不是同时执行64次加法,而是采用向量体系结构流水化ALU,从而以更低的成本获得良好的性能。向量体系结构的基本原理是从内存中收集数据元,将它们按顺序放入一大组寄存器中,使用流水化的执行单元在寄存器中依次对它们进行操作,然后将结果写回内存。向量体系结构的一个关键特性是拥有一组向量寄存器。这样,一个向量体系结构中可能具有32个向量寄存器,每个寄存器包含64个64位宽的数据元。

4.3向量与标量

与传统指令系统体系结构相比,向量指令具有几个重要的属性:

  • 单个向量指令指定了大量工作----相当于执行了完整的循环。正因为这样,指令取指和译码带宽大大减少。
  • 通过使用向量指令,编译器或程序员确认了向量中的每个结果都是独立的,因此硬件无须在检查向量指令内的数据冒险。
  • 当程序中存在数据级并行时,相比使用MIMD多处理器,使用向量体系结构和编译器的组合更容易写出高效的应用程序。
  • 硬件只需要在两条指令之间检查向量操作数之间的数据冒险,而无须检查向量中的每个数据元。减少检查的次数可以节省能耗和时间。
  • 访问存储器的向量指令具有确定的访问模式。如果向量中的数据元位置都是连续的,则可以从一组存储器中交叉访问数据块,从而快速获取向量。因此,对整个向量而言,主存储器的延迟开销看上去只有一次,而不是对向量中的每个字都产生一次。
  • 因为整个循环被具有已知行为的向量指令所取代,所以通常由循环引发的控制冒险不再存在。
  • 与标量体系结构相比,节省的指令带宽和冒险检查一级对存储器带宽的有效利用,使得向量体系结构在功耗和能耗方面更具有优势。

综上所述,在同等数据量的前提下,向量操作可以比一组标量操作序列更快地完成。如果应用程序当中经常使用这些向量操作,设计者将更有动力在设计中加入向量单元。

4.4向量与多媒体扩展

与X86 AVX指令中多媒体扩展类似,向量指令也指定了多种操作。但是多媒体扩展通常只能表示几种操作,而向量指令可以指定几十种操作。与多媒体扩展不同,向量操作中数据元的数量不存放在操作码中,而是存放一个在单独的寄存器中。这种区别意味着仅通过改变该寄存器的内存就可以用不同数量的数据元实现不同版本的向量体系结构,从而保持二进制代码的兼容性。与之相反,在X86的MMX、SSE、SSE2、AVX、AVX2等多媒体扩展中,每当向量的长度变化时,就需要添加一组新的指令操作码。

还有一点,与多媒体扩展不同,向量的数据传输不需要是连续的。向量支持步长访问和索引访问,前者是在存储器中每隔n个数据元加载一次数据,后者是按照数据项的地址将数据加载到向量寄存器中。索引访问也称为聚集-分散,因为索引加载从主存将数据元收集为连续的向量元素,而索引存储将向量元素分散至内存中。

与多媒体扩展类似,向量体系结构可以灵活支持不同的数据宽度,因此可以使向量操作工作在32个64位数据元、64个32位数据元、128个16位数据元或者256个8位数据元上。向量指令的并行特性可以使其采用深度流水的功能单元、并行功能单元阵列或者并行功能单元与流水功能单元的组合来执行这些操作。

在这里插入图片描述

上图使用多个功能单元来提高单个向量加法指令C=A+B的性能。左侧的向量处理器只有单个加法流水线,每个周期可以完成一次加法。右侧的向量处理器有四个加法流水线,每个周期可以完成四次加法。单个向量加法指令中数据元被分散在四个通道中。

向量算术指令通常仅允许一个向量寄存器的元素N与其他向量寄存器的元素N进行交互。这极大地简化了高度平行的向量单元的构造----可构造为多个平行的向量通道。与高速公路一样,我们可以通过添加更多车道来增加向量单元的峰值吞吐量。

在这里插入图片描述

上图包含四个通道的向量单元的结构图。向量寄存器内存等量地分配给每个通道,每个向量寄存器中的数据元依次分配给每个通道。图中画出了三个向量功能单元:浮点加法单元、浮点乘法单元和存取单元。每个向量运算单元包含四个执行流水线,每个通道一个,它们协同工作以完成单个向量指令。请注意向量寄存器堆的每个部分是如何只为其对应通道的功能单元提供足够的读写端口的。

总的来说,向量体系结构是执行数据并行处理程序的一种非常有效的方法。与多媒体扩展相比,向量体系结构更适合编译器技术,而且随着时间的推移,向量体系结构比x86体系结构的多媒体扩展更容易进行改进。

5.硬件多线程

从程序员的角度来看,硬件多线程是与MIMD相关的一个概念。MIMD依赖于多个进程或线程使得多个处理器保持忙碌状态,而硬件多线程允许多个线程以重叠的方式共享单个处理器的功能单元,以有效地利用硬件资源。为了支持这种共享,处理器必须复制每个线程的独立状态。

例如,每个线程都有一个寄存器堆和程序计数器的独立副本。内存本身可以通过虚拟内存机制实现共享,在多道程序编程中已经支持了这种方法。此外,硬件必须具有在线程之间快速切换的能力。特别是,线程切换应该比进程切换更加有效,线程切换可以是瞬时切换,而进程切换通常需要数百到数千个处理器周期。

硬件多线程主要有两种实现方法。细粒度多线程在每条指令执行后进行线程切换,导致了多线程的交叉执行。这种交叉执行通常以一种轮转方式完成,并跳过在该时钟周期停顿的任何线程。为了实现细粒度多线程,处理器必须能够在每个时钟周期切换线程。细粒度多线程的一个优点是可以隐藏由短期和长期停顿引起的吞吐量损失,因为当一个线程停顿时可以执行来自其他线程的指令。细粒度多线程的主要缺点是会减慢单个线程的执行速度,因为已经就绪的线程会因为执行其他线程的指令而延迟。

粗粒度多线程是作为细粒度多线程的另一种可选项被发明的。粗粒度多线程仅在高开销的停顿上切换线程,例如末级cache失效时,这种改变降低了高速切换线程的要求,并且几乎不会减慢单个线程的执行速度,因为只有在线程遇到高开销的停顿时才会发射来自其他线程的指令。然后粗粒度多线程有一个严重缺点:降低吞吐量损失的能力有限,尤其是对于短停顿。这种限制源于粗粒度多线程的流水线启动开销。因为组粒度多线程处理器从单个线程发出指令,所以当发生停顿时,必须清空或冻结流水线。在停顿之后开始执行的新线程必须在导致停顿的指令能够完成之前填充流水线。由于这种启动开销,粗粒度多线程对于降低高成本停顿的损失更为有用,因为在这种情况下,流水线重新填充的时间与停顿时间相比可以忽略不计。

同时多线程(SMT)是硬件多线程的一种变体,它使用多发射、动态调度流水线的处理器资源来挖掘线程级并行和指令级并行。提出SMT的主要原因是,多发射处理器中通常具有大多数单线程难以充分利用的并行功能的单元。此外,通过寄存器重命名和动态调度,可以发现来自相互独立的多线程的多条指令,而不需要考虑它们之间的依赖关系;可以通过动态调度能力来解决相关性的问题。

因为SMT依赖于现有的动态机制,因此它不会在每个时钟周期切换资源。相反,SMT始终执行来自多个线程的指令,将资源分配交给硬件完成,这些资源是指令槽或重命名寄存器。

在这里插入图片描述

上图说明了在不同的处理器配置下对超标量资源利用能力的差别。上半部分展示了四个线程如何在不支持多线程的超标量处理器上独立执行。下半部分展示了三个不同的多线程选项下,四个线程如何组合以在单个处理器上更高效地执行。这三个选项是:

  • 支持粗粒度多线程的超标量
  • 支持细粒度多线程的超标量
  • 支持同时多线程的超标量

在不支持硬件多线程的超标量处理器中,发射槽的使用受到指令级并行的限制。此外,诸如指令cache失效之类的绝大数停顿,都可能使整个处理器处于空闲状态。

在粗粒度多线程超标量处理器中,通过切换到使用该处理器资源的另一个线程,可以部分隐藏长停顿。尽管这样做可以减少完全空闲的时钟周期的数量,但是流水线的启动开销依然会带来空闲的时钟周期,并且ILP的限制意味着并非所有的发射槽都能得到充分利用。在细粒度多线程的情况下,线程的交叉执行可以基本的消除空闲的时钟周期。但是,由于在给定的时钟周期内只有一个线程发出指令,因此指令级并行的限制仍会导致某些时钟周期内出现空闲的发射槽。

在SMT中,线程级并行和指令级并行都得到了充分利用,多个线程在单个时钟周期中使用发射槽。理想情况下,发射槽使用仅受到多个线程资源需求不平衡和资源可用性的限制。实际上,还有其他因素可能会限制使用发射槽的数量。大大的简化了这些处理器的实际操作,但是它确实说明了多线程在一般情况下的潜在性能优势,特别是SMT。

6.多核及其他共享多处理器

尽管硬件多线程已经用很小的代价提升了处理器效率,但是在过去的十几年中,一个巨大的挑战是:如何通过有效地编程来利用单个芯片上数量不断增加的处理器,以发挥出摩尔定律呈现出的性能潜力。

考虑到重写旧程序使其能在并行硬件上良好运行是困难的,一个自然的问题是:计算机设计者该如何简化该任务?一种方法是为所有处理器提供一个共享的统一物理地址空间,使得程序无须考虑数据的存放位置,只需要考虑如何并行执行。在这种方法中,程序的所有变量对其他任何处理器都是随时可见的。另一种方法是每个处理器采用独立的地址空间,这就必须进行显示共享,当共享物理地址空间时,硬件通常提供cache一致性,以保证共享内存的一致性。

在这里插入图片描述

共享内存多处理器(SMP)为所有处理器提供统一物理地址空间----对多核芯片几乎总是如此----尽管更准确的术语是共享地址多处理器。处理器通过存储器中的共享变量进行通信,所有处理器都能够通过加载和存储指令访问任意存储器位置。请注意,即使这些系统共享物理地址空间,它们仍可在自己的虚拟地址空间中运行独立程序。

单地址空间处理器有两种类型。在第一种类型中,访存延迟不依赖于是哪个处理器提出的请求。这种机器称为统一内存访问多处理器。在第二种类型中,一些存储器的访问会比其他存储器快很多,这取决于是哪个处理器访问哪个存储。这通常是因为主存储器被划分,并分配给不同的微处理器或同一芯片上的不同内存控制器。这种机器称为非统一内存访问多处理器(NUMA)。如你所料,NUMA多处理器的编程难度高于UMA多处理器,但NUMA机器可以扩展到更大规模,并且NUMA在访问附近的内存时具有较低的延迟。

处理器并行执行时通常需要共享数据,因此在操作共享数据时需要进行协调;否则,一个处理器可能会在另一个处理器还没有对共享数据完成之前就开始处理该数据。这种协调被称为同步。当统一地址空间支持共享时,必须提供一套独立的同步机制。一种方法是为了共享变量提供锁。同一时刻只能有一个处理器可以获得锁,其他想要操作共享数据的处理器必须等待,直到该处理器解锁共享变量为止。

6.写在最后

今天的博客主要介绍了并行的处理器,后面会继续介绍别的内容。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值