【书摘】计算机组成与设计 - 硬件/软件接口

计算机性能水平的提高是永无止境的,计算机设计者和程序员必须理解更广泛的问题。


小结

计算机性能水平的提高是永无止境的,计算机设计者和程序员必须理解更广泛的问题。硬件和软件设计者都是用分层的方法构建计算机系统,每个下层都对其上层隐藏本层的细节。这个抽象原理是理解当今计算机系统的基础,但这并不意味着设计者只要懂得抽象原理就足够了。也许最重要的抽象层次是硬件和底层软件之间的接口,称为指令集体系结构。将指令集体系结构作为一个常量可以使其不同的实现方法(价格和性能可能不同)能够运行同一软件。产生的一个副效应:这些预先排除可能需要接口发生变化的那些革新结构。

现代处理器硬件的关键技术是硅。与理解集成电路技术同样重要的是理解我们所期望的技术进步速率。在硅技术加快硬件进步的同时,计算机组织的新思想也改进了产品的性价比。其中有连个重要的新思想:第一,在程序中开发并行性,目前的典型方法是借助多处理器;第二,开发存储层次结构的访问局部性,目前的典型方法是通过 cache。

功耗已经取代芯片面积,成为微处理器设计中最重要的资源。保存功耗并且改进性能的需求已经迫使硬件工业向多核微处理器跃进,从而迫使软件工业向并行硬件编程跃进。计算机设计总是以价格和性能来度量的,也包括其他一些重要因素,如功耗、可靠性、成本和可扩展性等。尽管本章的重点放在价格、性能和功耗上,但是最佳的设计应该在特定的应用领域中取得所有因素之间适当的平衡。


存储程序计算机的两个准则是指令的使用与数字没有区别,以及使用可修改的存储器。选择机器可以理解的指令集需要精妙地平衡程序执行需要的指令数目、指令指令所需的时钟周期数和时钟的速度。在做精妙平衡时有四条准则可以指导设计者:

  1. 简单源于规整。
  2. 越小越快
  3. 加速常用操作
  4. 优秀的设计需要好的折中

机器语言上面是人类可读的汇编语言。汇编器将翻译为机器可以理解的二进制数,它甚至通过创造硬件中没有的符号指令来『扩展』指令集。


存储程序计算机有一个副作用,就是位模式没有内在的含义。相同的位模式可能代表有符号整数、无符号整数、浮点数和指令等。对这个字操作的指令决定了其意义。

计算机算数和用纸和笔手算的算术不同的地方是受到有限精度的约束。这个限制可能会因为计算中数大于或者小于预先的设定而导致无效操作。这种异常,称为『上溢』或『下溢』,可能导致异常、中断或类似于意外的子程序调用。

浮点算术因为是对实际的数字的近似而增加了挑战性,而且要小心确保所选的计算机数能最接近地表示实际数字。不精确和有限的表达带来的挑战是数值分析领域灵感的部分来源。最近转向并行性的趋势使得数值分析再次被关注起来,在顺序计算机上是完全安全的东西,在并行计算机里需要重新考虑,在寻找快速的算法的同时也要有正确的结果。

过去的多年里,计算机算术变得非常标准化,极大地增加了程序的可移植性。当今销售的大量计算机都采用了二进制整数补码算术和 IEEE 754 二进制浮点算术。

处理器的数据通路和控制通路的设计,可以从指令集系统和对工艺基本特性的理解开始。当然,背后的工艺也影响许多设计决策,如数据通路中哪些部件可用,以及单周期实现是否有意义等。流水线提高了吞吐率,单不能提高指令的内在执行时间;对某些指令而言,指令延迟与单周期实现的延迟类似。多发射增加了额外的允许每个时钟周期发射多条指令的数据通路硬件,但是却增加了有效延迟。为了减少简单的单周期实现数据通路的时钟周期,提出了流水线技术。相比之下,多发射关注于减少每条指令的平均时钟周期数 CPI。流水线和多发射都试着开发指令级并行。开发更高指令级并行的主要限制因素是存在数据相关和控制相关。在软硬件上都使用调试和推测执行,是降低相关带来影响的主要手段。为了维持通过并行处理器带来的计算性能提高,Amdahl 定律预言了系统中的其他部件会成为瓶颈。这个瓶颈就是内存系统。

无论最快的计算机还是最慢的计算机中,构成主存的原材料——DRAM 本质是相同的,并且是最便宜的,这使得构建一个和快速处理器保持同步的存储系统变得更加困难。局部性原理可以用来克服存储器访问的长延迟——这个策略的正确性已经在存储器层次结构的各级都得到了证明。尽管层次结构中的各级从量的角度来看非常不同,但是在它们的执行过程中都遵循相似的策略,并且利用相同的局部性原理。

多级 cache 可以更方便地使用更多的优化,这有两个原因。第一,较低级 cache 的设计参数与一级 cache 不同。例如,由于较低级 cache 的容量一般很大,因此可能使用更大容量的块。第二,较低级 cache 并不像一级 cache 那样经常被处理器用到。这让我们考虑当较低级 cache 空闲时让它做一些事情以预防将来的缺失。

另一个趋势是寻求软件的帮助。使用大量的程序转换和硬件设备有效地管理存储器层次结构是增强编译器作用的主要焦点。现在有两种不同的观点。一种是重新组织程序结构以增强它的空间和时间局部性。这种方法主要针对以大数组为主要数据结构的面向循环的程序;大规模的线性代数问题就是一个典型的例子。通过重新组织访问数组的循环增强了局部性,也因此改进了 cache 的性能。

还有一种方法是预取。在预取机制中,一个数据块在真正被访问之前就被取入 cache 肿了。许多微处理器使用硬件预取尝试预测访问,这对软件可能比较困难。

第三种方法是使用优化存储器传输的特殊 cache 感知指令。微处理器使用了一个优化设计:当发生写缺失时,由于程序要写整个块,因而并不从主存中取回一个块。对于一个内核来说,这种优化明显减少了存储器的传输。对并行处理器来说,存储系统也是一个重要的设计问题。存储器层次结构决定系统性能的重要性在不断增长,这也意味着在未来,这一领域对设计者和研究者来说将成为焦点。

采用几个不同的特性评估 IO 系统性能:可靠度;所支持 IO 设备的多样性;IO 设备的最大数目;成本;性能延迟和吞吐量。这些目标导致提供 IO 设备接口的方案多样化。在低端和中端系统中,采用缓冲区的 DMA 是主流的传输机制。而在高端系统中,时延和带宽同样重要,成本是其次。具有有限的缓冲多通道 IO 设备通常被刻画为高端 IO 系统。典型地,随着系统的增大,能在任何时间访问 IO 设备上的数据(高可用性)变得越来越重要。结果是当我们扩大系统时,冗余和纠错机制变得越来越普遍。

自从计算开始之日,人们就梦想着通过简单的集成若干处理器就可以构建计算机。然而,构建并充分有效利用并行处理器的进程是缓慢的。其原因一方面是受软件难点的限制,另一方面是为了提高可用性和效率,多处理器的体系结构在不断改进。不同并行体系结构之间往往存在巨大差异,所取得的性能提升也非常有限,而且过去许多并行体系结构的生命周期非常短暂,这些因素使得软件更加困难。

  • 软件即服务的重要性正在增长中,并且集群已经被证实为提供此类服务的一种非常成功的方法。通过提供高层次的冗余,包括地理分布的数据中心,此类服务可以为全世界的客户提供 24x7x365 的可用性。不难想象无论是数据中心的数量还是每个数据中心内服务器的数量都会持续增长。毋庸置疑,此类数据中心会采用多核设计,因为数据中心已经在应用中使用了数以千计的处理器。
  • 在科学计算和工程计算等领域中并行处理的使用是非常普遍的。此类应用领域对计算机能力几乎充满无限的渴望。而且有很多应用具有天然的并行性。集群再一次地占据了此类应用领域。虽然如此,为这些应用编程也并非易事,如何进行并行处理器编程仍是一项挑战。此类应用也必然采用多核新品啊,因为它们已经采用成百上千个处理器。
  • 为了获得更高性能,所有的桌面和服务器微处理器制造上正在构建多处理器,顺序应用程序不会像过去一样再有获取更高性能的捷径。因此,需要更高性能的程序员必须将自己的代码并行化,或者编写全新的并行处理程序
  • 相对于多芯片设计,同一芯片上的多处理器可提供完全不同的通信速率,具有更低的延迟和更高的带宽。这些改进可以使得高性能更易获得
  • 在过去,微处理器和多处理器在成功上的定义是不同的。当缩放单处理器性能时,如果单线程性能随着增加硅面积开方增长,微处理器设计者会感觉很满意。也就是说,他们满足于性能随资源数量的亚线性增长。多处理器的成功在过去通常定义为与处理器数量相关的线性加速比函数,并假定 n 个处理器的购买成本或管理成本是单一处理器的 n 倍。目前并行正在片上以多核的形式实现,我们可以使用已经获得成功的传统微处理器来获得亚线性的性能提升
  • 运行时编译技术的成功使得软件更容易适应处理器核数量的增长,提供受静态编译器限制所不能提供的灵活性。
  • 与过去不同的是,开放源代码运动已经成为软件业的一个关键部分。这项运动可以改善工程解决方案,促进开发者之间的知识共享。它也鼓励创新,在改变旧有软件时欢迎新的语言和软件产品。这种开放式的文化必将有益于目前日新月异的时期。

GPU 是大规模并行处理器,且被广泛应用,不仅在 3D 图形方面,而且在众多其他应用方面。图形设备到可编程处理器的演变使得这个广泛的应用成为可能。GPU 的图形应用编程模型通常是一个 API,像 DirectX 活着 OpenGL。为了更多通用目的计算,CUDA 编程模型使用 SPMD 风格,执行一个具有众多并行线程的程序。

GPU 的并行性将继续以摩尔定律扩展,主要通过增加处理器的数量。只有可以容易地扩展到数百个处理器核和数千个线程上的并行编程模型,在支持众核 GPU 和 CPU 方面,才会获得成功。同样,只有那些具有众多大量独立并行的任务才能被大规模并行众核架构所加速。

GPU 的并行编程模型正在变得更为灵活,可用于图形和并行计算。例如,CUDA 正朝着完全 C/C++ 功能方向快速发展。图形 API 和编程模型将可能根据 CUDA 的并行计算能力和模型改编。它的 SPMD 风格的线程模型对于表达大量并行来说,是可扩展的,并且方便、简洁、易学。

被编程模型中的这些改变所驱动,GPU 架构变得更为灵活和更具编程性。GPU 固定功能单元正变得可被通用程序访问,沿着 CUDA 程序,使用 GPU 纹理指令和纹理单元,已经使用纹理内在函数执行纹理查找的路线。

GPU 架构将不断地适应图形和其他应用程序员的使用模型。GPU 将继续扩展以包含更多的处理能力,通过增加处理器核、增加线程和程序可用的存储器带宽。另外编程模型必须改进以包含可编程异构众核系统(同时包含 GPU 和 CPU)

用汇编语言进行程序设计需要程序员放弃高级语言中的一些有益的特点——如数据结构、类型检查以及控制结构——以获得对机器执行指令的完全控制。一些应用的外部约束,如响应时间、程序大小等,需要程序员密切关注每条指令。然而,和高级语言程序相比,这种级别的关注带来的是更长、编写更费时、更难维护的汇编语言程序。

此外,三个趋势导致不必再用汇编语言来编写程序。第一个趋势是编译器的改进。现在,编译器生成的代码可以与最好的收工书写的代码相媲美——有时候甚至会更好。第二个趋势是新处理器的速度不仅更快,而且对于哪些可以同时执行多条指令的处理器,手工编程也变得更加困难。此外,现代计算机的快速发展也支持高级语言程序不再依赖单一的体系结构。最后,我们见证了日渐复杂的应用趋势,不仅有复杂的图形界面,而且还有许多先前不曾遇见的特征。由程序员组成的团队合作开发的大规模应用程序需要有由高级语言提供的模块化设计思想和语义检查的特点。

重点

组成计算机的五个典型部件是输入、输出、存储器、运算器和控制器,其中最后两个部件通常合称为处理器,该组成与硬件技术无关。

无论硬件还是软件都可以分成多个层次,每个较低的层次把细节对上层隐藏起来。硬件设计者和软件设计者都用这种抽象原则来应对计算机体系的复杂性。计算机体系结构是抽象层次中的一个关键接口——硬件和底层软件之间的接口。这一抽象使得同一软件可以由成本不同、性能也不同的实现方法来完成。

执行时间 = 秒/程序 = 指令数/程序 乘以 时钟周期数/指令 乘以 秒/时钟周期。

执行时间是唯一有效且不可推翻的性能度量方法。人们曾经提出许多其他度量方法,但均已失败告终。有些从一开始就没有反应执行时间,因而是无效的;还有一些只能在有限条件下有效,超出了限制条件则失效,或是没有清晰的说明有效性的限制条件

现代计算机基于两个重要的准则构建:1)指令用数的形式表示,2)和数一样,程序存储在存储器中,并且可以读写。这些原则引出存储程序(stored-program)的概念,这一发明释放了计算机的巨大潜力。指令表示成数的好处就是程序可以被当成二进制数的文件发行。商业上的意义就是计算机可以沿用那些指令集兼容的现成软件。这种『二进制兼容』使得工业界围绕着几种指令集体系结构形成联盟。

位模式并没有内在的含义,它们可能表示有符号整数、无符号整数、浮点数和指令等。具体代表什么意思要看指令对该字的哪些位进行操作。计算机数和真实世界里的数的主要不同是计算机数的大小是有限制的,因此限制了其精度;计算的数字有可能太大或太小而无法在一个字中表示。程序员必须记住这些限制并相应地编程。

流水线增加了同时执行的指令数目以及指令开始和结束的速率。流水线并不能够减少单一指令的执行时间,也称为延迟。对流水线的设计者来说,指令集既可能将事物简单化,也可能将事物复杂化。流水线设计者必须解决结构冒险、控制冒险和数据冒险。而分支预测、转发和阻塞机制能够在保证得到正确结果的前提下提高计算机的性能。

流水线和多发射都提高了指令的吞吐率并致力于开发指令级并行。然而,由于处理器有时必须等待依赖关系明确后才能继续工作,所以程序中的数据相关和控制相关往往限制了可达性能的上限。基于软件的指令级并行开发主要依赖于编译器来寻找依赖关系并尽量减少这些依赖关系可能造成的不良后果。基于硬件的指令级并行开发主要依赖于流水线和多发射机制。推测执行可以由硬件或编译器完成,它可以增加指令行并行。但是使用时必须小心,因为错误的推测可能会降低性能。

程序不仅表现出时间局部性,即重复使用最近被访问的数据项的趋势,同时也表现出了空间局部性,即访问与最近被访问过的数据项地址空间相近的数据项的趋势。存储器层次结构利用了时间局部性,将最近被访问的数据放在靠近处理器的地方;同时也利用了空间局部性,将一些包含连续字的块移至存储器层次结构的较高层次。

存储器层级结构设计所面临的挑战在于:任何一个改进缺失率的设计同时也可能对整体性能产生负面的影响。

设计变化对缺失率的影响可能对性能产生的负面影响
增加 cache 容量减少了容量缺失可能增加访问时间
提高关联度由于减少了冲突缺失,因此降低了缺失率可能增加访问时间
增加块的容量由于空间局部性,因此对很宽范围内变化的块大小,都能降低缺失率增加缺失代价,块太大还会增加缺失率

理解程序性能

不同的应用关注计算机系统的不同方面。许多应用,特别是那些运行在服务器上的应用,主要关注 IO 性能,所以此类应用既依赖硬件又依赖软件,对时间最感兴趣。而在其他一些应用中,用户可能对吞吐率、响应时间或两者的复杂组合更为关注(例如最差响应时间情况下的最大吞吐率)。要改进一个程序的性能,必须明确性能的定义,然后通过测量程序执行时间来寻找性能瓶颈。

程序的性能与算法、编程语言、编译程序、体系结构以及实际的硬件有关。

硬件或软件指标影响什么如何影响
算法指令数,CPI算法决定源程序执行指令的数目,从而也决定了 CPU 执行指令的数目。算法也可能通过使用较快或较慢的指令影响 CPI
编程语言指令数,CPI编程语言中的语句必须被翻译为指令,从而决定了指令数。编程语言也可以影响 CPI
编译程序指令数,CPI编译程序的效率,既影响指令数,又影响 CPI。因为编译程序决定了最后生成的计算机指令,所以会以复杂的方式影响 CPI
指令集体系结构指令数,时钟频率,CPI影响 CPU 性能的所有方面

除了存储系统以外,流水线的有效运作是决定处理器 CPI 乃至性能最终要的因素。结构冒险、数据冒险和控制冒险在简单流水线处理器和更复杂的流水线处理器中都是非常重要的,对现代流水线而言,结构冒险常出现在浮点单元附近,浮点单元是一个几乎不可能完全流水的地方。与之相比,控制冒险一般出现在整数程序中,因为其中分支出现的概率更高,也更难预测。数据冒险在整数和浮点程序中都可能成为性能平静。一般来说浮点程序中的数据冒险更容易处理,因为低的分支出现频率和规则的存储器存取使得编译器有更大的空间调度指令以避免冒险。与之相比,在整数程序中涉及大量的指针,存储器的存取更不规则,做这样的优化就要困难一些。有很多编译器和基于硬件的技术通过调度来减少数据间的依赖。

既然编译器可以根据数据依赖关系调度代码,为什么还需要超标量处理器来进行动态调度呢?有三个原因。1)不是所有的阻塞都可以事先知道的。尤其是 cache 缺失会导致不可预测的阻塞。动态调度使得处理器可以调度并执行其他无关的指令以掩盖阻塞。2)如果处理器采用动态分支预测推测分支结果,那么由于这些信息依赖于预测和分支指令的真实情况,编译器无法得知指令的精确顺序。采用动态推测而不是动态调度,会极大地限制可开发的指令级并行度(ILP)。3)由于流水线延时和发射宽度根据处理器的具体实现的不同有很大而差别,所以最佳的编译代码顺序也并不固定。例如,调度一个相互依赖的指令序列的具体方式与发射宽度和延时存在着密切关系。流水线的结果同样会影响循环展开的尝试,才能避免可能的阻塞。它还回影响编译器进行寄存器重命名的过程。动态调度使得硬件将这些细节隐藏起来。因此,用户和软件发行商就不用针对同一指令集的不同处理器发行相应的软件了。同样的,以前的代码也能从更新的处理器上获得好处而不用重新编译。

尽管虚拟存储器能使一个小容量的存储器看起来像大容量的存储器,但磁盘和主存之间的性能差异意味着,如果一个程序经常访问比它拥有的物理存储器多的虚拟存储器,程序运行速度就会很慢。这样的程序会不断地在主存和磁盘之间交换页面,称为抖动 thrashing。抖动的发生将会是灾难,但很少见。如果你的程序产生抖动,那么最简单的解决方式就是在一个有着更大主存的计算机上运行,或者为你的计算机增加主存。一个复杂的办法是重新检查所使用的算法和数据结构,看看能否改变它的局部性,从而减少程序程序同时使用的页数。这一组页通常被称为工作集 working set

I/O 系统的性能,无论是通过带宽开始时延来度量,都取决于设备和内存之间路径上的所有要素,包括产生 I/O 命令的操作系统。总线的带宽、内存和设备决定了进出设备的最大传输速度。同样,延迟时间由设备的延迟时间、内存系统或者总线带来的延迟决定。有效带宽和响应时延依赖于路径中其他可能引起的资源冲突的 I/O 请求。最后,操作系统变成一个平静。在某些情况下,OS 需要很多时间才能把 I/O 请求从用户程序转交给 I/O 设备,从而导致很大的延时。在其他情况下,操作系统在很大程度上限制了 I/O 带宽,因此操作系统能够支持并发 I/O 操作的数量是有限的。

硬件 软件接口

并行性对计算性能一直十分重要,但它往往是隐蔽的。流水线是一种漂亮的技术,通过指令重叠执行使程序运行得更快。这是指令集并行性的一个例子。在抽取的硬件的并行本质之后,程序员或编译程序可以认为在硬件中指令是串行执行的。

除了将变量与寄存器对应起来,编译器还在存储器中为诸如数组和结构这样的数据结构分配相应的位置。然而,编译器可以将它们在存储器中的起始地址放到数据传送指令中。

很多程序都用到字节类型,且大多数体系结构按字节编地址。因此,一个字的地址必和它所包括的四个字节中某个的地址相匹配,且连续字的地址相差 4。在 MIPS 中,字的起始地址必须是 4 的倍数,这叫对齐限制,许多体系结构都有这样的限制。

有两种类型的字节寻址的计算机:一种使用最左边或『大端』big end 字节的地址作为字地址;另一种使用最右边或『小端』little end 字节的地址作为字地址。

许多程序的变量个数要远多于计算机的寄存器个数。因此,编译器会尽量将最常用的变量保持在寄存器中,而将其他的变量放在存储器中,方法是使用取数/存数指令在寄存器和存储器之间传送变量。将不常使用的变量(或稍后才使用的变量)存回到存储器中的过程叫做寄存器溢出(spilling register)

寄存器与存储器相比,访问时间短、吞吐率高,寄存器中的数据访问速度快并易于利用,访问寄存器相对于访问存储器功耗更小。因此,为了获取高性能和节约功耗,编译器必须高效率地利用寄存器

存储器地址很自然地从 0 开始且一直连续增加到最大的地址,因此负地址是没有意义的。

编译器经常创建一些在编程语言中没出现过的分支和标签。避免显式编写这些标签和分支是使用高级编程语言的好处之一,也是其编码速度块的一个原因。

以分支指令结束的这类指令序列对编译非常重要,因此它们有对应的专用术语:基本块。基本块是没有分支(可能出现在末尾者除外)并且没有分支目标/分支标签(可能出现在开始者除外)的指令序列。编译最初阶段的任务之一就是将程序分解为若干基本块。

虽然在 C 或 Java 这样的编程语言中有许多分支判断和循环语句,但是在指令集这一层次实现其功能的基本语句是条件分支。

和算术运算一样,对取数指令来说有符号位和无符号位是有区别的。取回有符号数后需要使用符号位填充寄存器的所有剩余位,称为符号扩展,但其目的是在寄存器中放入数字正确的表示方式。

编译器或汇编程序必须把大的常数分解为若干小的常数然后再合并到一个寄存器中。

大多数条件分支都转移到一个附近的位置,但有时也会转移很远,距离超过位数可能表示的范围。汇编器的解决方法就像处理对大地址或大常数的方法一样:插入一个跳转到分支目标的无条件跳转,并将条件取反以便由分支决定是否跳过该无条件跳转指令。

计算机设计者必须考虑如何处理算术溢出。但是一些编程语言如 C 和 Java 会忽略整数溢出,而 Ada 和 Fortran 语言则需要通知程序溢出。因此程序员或者是编程环境必须决定在溢出发生时如何处理。

当乘数为常数时,乘法也可以用位移来替代。一些编译器将有短常数的乘法替换为一系列的移位和加法。几乎每个编译器都将以 2 为底的指数乘法替换为移位来进行优化。

在支持浮点算数方面,体系结构设计者面临着一个问题:是否和整数指令使用相同的寄存器,或者为浮点增加一组专用的寄存器。因为程序通常对不同的数据执行整数和浮点操作,单独的寄存器会稍微增加程序中要执行的指令数目。主要的影响是需要建立一组单独的用于浮点寄存器和内存之间传送数据的指令。

单独的浮点寄存器的好处是倍增了寄存器数目而不需要在指令格式中增加更多的位数,因为使用了相互独立的整数和浮点寄存器堆而倍增了寄存器带宽,另外,还可以量身定做针对浮点的寄存器;例如,一些计算机将寄存器中各种大小的源操作数转化为一种单一的内部格式。

硬件与操作系统必须协同工作才能按照我们期望的方式处理异常。硬件一般暂停指令流中导致异常的指令,同时执行完该指令前的所有指令,清除该指令后的所有指令,并且设置一个寄存器描述异常发生的原因,保存导致异常发生的指令的地址,然后跳转到预先确定的地址开始执行。操作系统则查看异常发生的原因并才去相应的操作。对于一个未定义指令异常、硬件错误异常或算数溢出异常,操作系统通常终止执行的程序并返回原因描述。对于 I/O 设备请求活操作系统服务调用,操作系统保存程序的当前状态,执行期望的任务,然后重新载入程序继续运行。在 I/O 设备请求的情况下,我们可能需要在继续执行发出 I/O 设备请求的任务前先运行另一个任务,因为该任务一般在 I/O 完成之后才能继续执行。这就是保存和恢复任务状态如此重要的原因。一个最重要且频繁出现的异常是页缺失与 TLB 异常。

现代的高性能微处理器可以在一个时钟周期内发射多条指令。遗憾的是,持续这样的高发射速率是相当困难的。例如,尽管我们又一个单时钟周期可以发射4-6条指令的处理器,只有很少的应用程序能保持每周期发射两条以上指令。这里面主要有两个原因。1)由于使用了流水线,主要的性能平静在于那些不能立即解决的相关性,这就限制了指令间的并行度,因此也就限制了发射速率。虽然对于真正的数据相关而言么有什么的好的解决办法,但是一般情况下硬件或编译器对于相关是否确实存在都不知道,因而也就只能保守地假设相关存在了。一般来说,指令级并行总是有开发空间的,但是因为并行度较为分散,编译器和硬件往往会显得力不从心。2)存储系统中的 miss 同样会使流水线难以满负荷运转。尽管一个访存引起的阻塞可以被掩盖掉,但是有限的指令级并行度同样会使阻塞被掩盖的程度有所下降。

要完全准确地执行 LRU 算法的代价太高了,因为每次存储器访问时都需要更新数据结构。作为替代,大多数操作系统通过追踪哪些页最近被使用,哪些页最近没有用到来近似地实现 LRU 算法。为了帮助操作系统估算最近最少使用的页,一些计算机提供了一个引用位或者称为使用位,当一页被访问时该位被置位。操作系统定期将引用位清零,然后再重新记录,这样就可以判定在这段时间内哪些页被访问过。有了这些使用信息,操作系统就可以从那些最近最少访问的页中选择一页(通过检查其引用位是否关闭)。如果硬件没有提供这一位,操作系统就要通过其他的方法来估计哪些页被访问过。

在虚拟存储系统中,写回机制有另一个主要的优点。因为相对磁盘访问时间,其传输时间要少得多,因此,把整页复制会磁盘比把单个字写回要高效得多。尽管写回操作比传输单个字更高效,但是开销很大。因此,当某一页被替换时,我们希望知道该页是否需要被复制写回。为了追踪读入主存中的页是否被写过,可以在页表中增加一个重写位 dirty bit。当页中任何字被写时就将这一位置位。如果操作系统选择替换某一页,重写位指明了在把该页所占用的主存让给另一页之前,是否需要将该页写回磁盘。因此,一个修改过的页也通常被称为脏页 dirty page

为了使操作系统能保护虚拟存储系统,硬件至少提供下面三种基本能力:1)支持至少两种模式,并指出当前运行的进程是用户进程还是操作系统进程,操作系统进程也称为超级用户管理进程、核心进程或主管进程。2)提供一部分处理器的状态,这部分内容是用户进程可读而不可写的。这包括指示处理器是处于用户态还是管理态的用户/管理模式位、页表指针以及 TLB。操作系统用只能在管理态下可用的特殊指令对它们操作。3)提供能让处理器在用户态和管理态下相互切换的机制。从用户态到管理态的转换通常是由系统调用异常处理完成的,它用特殊指令将控制权传到管理代码空间的指定位置。和其他异常处理一样,系统调用处的程序计数器中的值被保存在异常程序计数器中(EPC),处理器被置于管理态。从异常中返回至用户模式,使用异常返回 return from exception 指令,将重置用户模式,并且跳转到 EPC 中的地址处。

在操作系统开始进行异常处理和保存处理器所有状态位的时候,操作系统特别脆弱。例如,如果在操作系统中正在处理第一个异常时,另一个异常又发生了,控制单元将重写异常程序计数器,就不能反悔引起缺页的那条指令。我们可以通过提供禁止异常 disable exception 和使能异常 exception enable 来避免这种错误的发生。当异常第一次发生时,处理器设置一个位,禁止其他异常的发生;这可以与处理器设置管理态位同时进行。随后操作系统保存足够的状态,如果有另一个异常发生——异常程序计数器 EPC 和异常引发寄存器也能正确恢复。异常程序计数器和异常引发寄存器是协助处理异常、TLB 缺失以及缺页的两个特殊控制寄存器。而后操作系统可以重新允许异常发生。这些步骤保证了异常不会使处理器丢失任何状态,因此也就不会出现无法重新执行中断指令的情况。

采用虚拟内存的系统中,DMA 是应该采用虚拟地址还是物理地址?采用虚拟地址最明显的问题是 DMA 部件需要将虚拟地址转换成物理地址。使用物理地址在 DMA 传输中的主要问题是传输不容易跨越一个存储页的边界。一个 I/O 请求如果跨越了存储页的边界,它传输的内存位置在虚拟内存中就不一定连续。因此,如果使用物理地址,DMA 传输必须被限制在一个页面之内。使 DMA 工作在虚拟地址上的一种方法是允许系统能启动跨越边界的 DMA 传输。在这样一个系统中,DMA 部件有少量的映射项用于保存传输中的虚拟地址到物理地址的映射。当 I/O 启动时,由操作系统来提供这些映射。使用这种映射,DMA 部件不需要关注被传输的虚拟页面的位置。另外一种方法是将 DMA 传输切断为由操作系统执行的一系列的传输,它们中的每一个操作都限制在单一的物理页面中,最后将这些传输链接起来,交给 I/O 处理器活着只能 DMA 部件处理,由它们执行整个序列的传输;或者由操作系统逐一请求这些传输。无论采用以上提及的哪一种方法,当包含某个页面的 DMA 传输正在进行时,操作系统都不能对该页进行重映射。

避免 I/O 数据不一致问题,可以使用下面三种方法之一。第一种方法是将高速缓存与 I/O 操作关联,这种方法确保了读操作能看到最新值而写操作会更新高速缓存中的数据。将高速缓存和所有的 I/O 相关联的成本很高,对处理器也存在潜在的负面影响,因为 I/O 数据很少立刻被用到,而且这可能会将运行程序所需的有用数据从 cache 中挤出去。第二种方法是让 OS 选择性地将高速缓存中与 I/O 读操作相关的数据项设置为无效;对于 I/O 写操作,强迫高速缓存写回内存(通常称为高速缓存刷新)。这种办法需要一些少量的硬件来支持,如果软件能够方便而有效地执行这个功能,采用软件可能会更加有效。因为这种大块高速缓存刷新的操作只在 DMA 进行块的访问时发生,所以它的相对出现次数不多。第三种方法是提供一种硬件机制,选择性地刷新高速缓存中的一些块(或者使之无效)。用硬件失效机制来确保高速缓存一致性的技术在多处理器系统中很常见,,这种技术也被用在 I/O 中。

对硬件设计者来说,基于消息传递的计算机比需要维持缓存一致性的共享存储计算机更加容易设计。对程序员来说,消息传递的优点是显式通信,这意味着共享存储的隐式通信相比性能提升较少;缺点是难以将一个顺序程序移植到消息传递计算机中,因为每次通信必须提前标识出来,否则程序将无法工作。缓存一致的共享存储允许硬件判断哪些数据需要通信,这使得移至相对简单。现在对于如何最快地获得高性能有不同的观点,隐式通信有有大量的支持者和反对者。

功耗效率与高级流水线

通过动态多发射和推测执行开发指令级并行的负面问题是功耗效率。每项发明都成功将更多的晶体管转化为性能,但是这种转化往往极其缺乏效率。因为功耗墙的原因,最新的处理器是单片多核式的,而非前辈的深流水线或贪婪式推测。尽管简单的处理器没有复杂的处理器那么快,但是在同样的功耗下却能得到更高的性能。所以当设计的约束更多来自功耗而非晶体管数量时,简单的处理器能在单芯片上获得更高的性能。

谬误与陷阱

陷阱:在改进计算机的某个方面时期望总性能的提高与改进大小成正比

Amdalh 定律 -> 硬件设计的主题:加速常见事件

谬误:利用率低的计算机功耗低

SPECpower 的表格,即使服务器的利用率只有 10%,也会消耗掉大约三分之二的峰值功耗

陷阱:用性能公式的一个子集去度量性能

几乎所有取代用时间去度量性能的方法都会导致歪曲的结果或错误的解释

误解:更强大的指令意味着更高的性能

比方说使用更大的浮点寄存器代替 x86 的整数寄存器,复制操作比使用复杂指令快 2 倍

误解:使用汇编语言编程来获得最高的性能

高级语言而不是汇编语言编写的程序不仅可以使未来的编译器为未来的机器生成代码,还可以使软件易于维护并运行在其他类型的计算机上

误解:商用计算机二进制兼容的重要性意味着成功的指令集不需要改变

在向后的二进制兼容的前提下,x86 指令集在 30 年中,平均每个月至少增加一条新的指令

陷阱:忘记在字节寻址的机器中,连续的字地址相差不是 1

要增加一个字的字节数

陷阱:在自动变量的定义过程外,使用指针指向该变量

指向自动变量的指针会造成混乱

谬误:只有理论数学家才会关心浮点精度

Pentium 处理器的浮点 bug

算术中常见的谬误与陷阱通常是由计算机算术的有限精度和自然算术的无限精度之间的差异引起的

谬误:流水线是一种简单的结构

正确设计流水线必须非常谨慎

谬误:流水线概念的实现与工艺无关

在 20 世纪 90 年代初期,动态流水线调度需要耗费大量资源并且无法得到很好的性能

陷阱:没有考虑指令集的设计反过来会影响流水线

许多流水线中遇到的困难都是由指令集的复杂性造成的

陷阱:在模拟 cache 的时候,忘记说明字节编址或者 cache 块大小

这是一个非常容易犯的错误

陷阱:在写程序或者编译器生成代码时忽略了存储系统的行为

比方说矩阵相关计算,不同的循环顺序可以导致非常大的性能差异

陷阱:对于共享 cache,组相联度少于核的数量或者共享该 cache 的线程数

陷阱:用存储器平均访问时间来评估乱序处理器的存储器层次结构

唯一可以用来准确评估存储器层次结构的办法是模拟乱序处理器和存储器结构

陷阱:通过在未分配地址空间的顶部增加段来扩展地址空间

陷阱:在不为虚拟化设计的指令集上实现虚拟机监视器

谬误:磁盘的平均故障时间(MTTF)为 1200000 小时,即近 140 年,所以磁盘实际上不会有故障

市场策略误导用户

谬误:实际的磁盘故障率和规格书中声明的一致

通常要高 3-5 倍

GB/s 的互联网络可以每秒传输 1GB 的数据

你不可能 100% 利用任何计算机资源(传输地址的时间、应答信号的时间、等待繁忙总线而阻塞的时间)

陷阱:试图仅仅提供互联网络的特性,而忽视端到端的情形

陷阱:把 CPU 的功能向 I/O 处理器转移,没有经过仔细分析就期望提高性能

陷阱:操作系统是调度磁盘访问的最好地方

陷阱:采用 I/O 系统一部分的传输峰值来表示性能或进行性能比较

要全面去比较,不要一叶障目

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

显然适用于

谬误:峰值性能可代表实际性能

超级计算机业界在市场中使用该度量方法,并且该谬误在并行机中更加严重

陷阱:在利用和优化多处理器体系结构时不开发软件

操作系统的算法和数据结构在多处理器上需要重新考虑

词语对照表

  • 系统软件 systems software: 提供常用服务的软件,包括操作系统、编译程序、加载程序和汇编程序
  • 操作系统 operating system: 为了使程序更好地在计算机运行而管理计算机资源的监控程序
  • 编译程序 compiler: 将高级语言翻译为计算机所能识别的机器语言的程序
  • 位 bit: 0 或 1,信息的基本组成元素
  • 指令 instruction: 计算机硬件所能理解并服从的命令
  • 汇编程序 assembler: 将指令由助记符翻译成二进制形式的程序
  • 汇编语言 assembly language: 以助记符形式表示的机器指令
  • 机器语言 machine language: 以二进制元形式表示的机器指令
  • 高级编程语言 high-level programming language: 诸如 C C++ Java 等可移植的语言,由一些单词和代数符号组成,可以由编译器转换为汇编语言
  • 输入设备 input device: 为计算机提供信息的装置,如键盘和鼠标
  • 输出设备 output device: 输出计算结果给用户或其他计算机的装置
  • 主板 motherboard: 包含一组继承电路芯片的塑料板,包括处理器、缓存、内存以及连接 IO 设备的接口
  • 集成电路 integrated circuit: 也叫芯片,一种将几十个至几百万个晶体管连接起来的设备
  • 内存 memory: 程序运行时的存储空间,同时还存储程序运行时所需的数据
  • DRAM dynamic random access memory: 动态随机访问内存,可随机访问任何地址的内存
  • 中央处理器单元 central processor unit: 也被称为处理器,处理器是主板上最活跃的部分。严格按照程序中的指令运行,将数字相加,测试结果,并按结果发出控制信号使 IO 设备动作等
  • 数据通路 datapath: 处理器中执行算术操作的部分
  • 控制器 control: 处理器中根据程序的指令,指挥数据通路、存储器和 IO 设备的部分
  • 缓存 cache memory: 缓存是一种小而快的存储器,一般作为大而慢的存储器的缓冲
  • 静态随机访问存储器 static random access memory: 一种存储器的集成电路,但是更快,比 DRAM 集成度低
  • 指令集体系结构 instruction set architecture: 也叫体系结构。是低层次软件和硬件之间的抽象接口,包含了需要写机器语言程序正确运行的所有信息,包括指令、寄存器、存储访问和 IO 等
  • 应用二进制接口 application binary interface: 用户部分的指令加上程序员调用的操作系统接口,定义了二进制层次可移植的计算机的标准
  • 实现 implementation: 遵循体系结构抽象的硬件
  • 易失性内存 volatile memory: 类似 DRAM 的内存,仅在加点时保存数据
  • 非易失性内存 nonvolatile memory: 在掉电时仍可以保持数据的内存用于存储运行间的程序,例如磁盘
  • 主存储器 main memory: 用来保持运行中的程序,在现代计算机中一般由 DRAM 组成
  • 二级存储器 secondary memory: 非易失性存储器,用来保存两次运行之间的程序和数据;在现代计算机中,一般由磁盘组成
  • 磁盘 magnetic disk: 也叫硬盘,是使用磁介质材料构成的以旋转盘片为基础的非易失性存储设备
  • 闪存 flash memory: 一种非易失性半导体内存,价格和速度均低于 DRAM,但比磁盘要快
  • 局域网 local area network: 一种在一定地理区域使用的传输数据的网络
  • 广域网 wide area network: TODO
  • 真空管 vacuum tube: 一种电子元件,是晶体管的前身,因工作的电极封装在 5-10 厘米长的真空玻璃管中而得名,使用电子束传输数据
  • 晶体管 transistor: 一种由电信号控制的简单开关
  • 大规模集成电路 very large-scale integrated circuit: 由数十万到数百万晶体管组成的电路
  • 响应时间 response time: 也叫执行时间(execution time),计算机完成某任务所需的总时间,包括硬盘访问、内存访问、IO 活动、操作系统开销和 CPU 执行时间
  • 吞吐率 throughput: 也叫带宽 bandwidth,性能的另一种度量参数,表示单位时间内完成的任务数量
  • CPI clock cycles per instruction: 每条指令的时钟周期数,表示执行某个程序或者程序片段时每条指令所需的时钟周期平均数
  • 指令数 instruction count: 执行某程序所需的总指令数量
  • 硅 silicon: 一种自然元素,半导体
  • 半导体 semiconductor: 导电能力介于导体和绝缘体之间
  • 硅锭 silicon crystal ingot: 一条由硅晶体组成的棒。直径大约 8-12 英寸,长度约 12-24 英寸
  • 晶圆 wafer: 厚度不超过 0.1 英寸的硅锭片,被用来制造芯片
  • 瑕疵 defect: 晶圆上一个微小的缺陷,或者在图样化的过程中因为包含这个缺陷而导致芯片失效
  • 芯片 die: 从晶圆中切割出来的一个单独的矩形区域,更正式的叫法是芯片(chip)
  • 成品率 yield: 合格芯片数占总芯片数的百分比
  • 工作负载 workload: 运作在计算机上的一组程序,可以直接使用用户的一组实际应用程序,也可以从实际程序中构建
  • 基准测试程序 benchmark: 用于比较计算机性能的程序
  • Amdahl 定律 Amdahl’s law: 阐述了『对于特定改进的性能可能由所使用的改进特征的数量所限制』的规则。它是『收益递减定律』的量化版本(结合经济学?)
  • MIPS million instructions per second: 基于百万条指令的程序执行速度的一种测量。指令条数除以执行时间与 $10^6$ 之积就得到了 MIPS
  • 指令集 instruction set: 一个核定的计算机体系结构所包含的指令集合
  • 存储程序概念 stored-program concept: 多种类型的指令和数据均已数字形式存储于存储器中的概念,存储程序型计算机即源于此
  • 字 word: 计算机中的基本访问单位,通常是 32 位为一组
  • 数据传送指令 data transfer instruction: 在存储器和寄存器之间移动数据的命令
  • 地址 address: 用于在存储器空间中指名特定数据元素位置的值
  • 对齐限制 alignment restriction: 数据地址与存储器的自然边界对齐的要求
  • 二进制数位 binary bit: 二进制状态之一,0 或 1,信息的基本组成单位
  • 最低有效位 least significant bit: 字中最右边的一位
  • 最高有效位 most significant bit: 字中最左边的一位
  • 反码 one’s complement: 使用 10…000(2 进制)表示最大负数,01…111(2 进制)表示最大正数,整数和负数的数量相同,但保留两个零(正零与负零)
  • 偏移表示法 biased notation: 最大的负数用 00…000(2 进制) 表示,最大的正数用 11…111(2 进制)表示,0 一般用 10…000(2 进制) 表示,即通过将数加一个偏移使其具有非负的表示形式
  • 指令格式 instruction format: 二进制数字段组成的指令表示形式
  • 机器语言 machine language: 在计算机系统中用于交流的二进制表示形式
  • 十六进制 hexadecimal: 基数为 16 的数
  • 操作码 opcode: 指令中用来表示操作和格式的字段
  • 按位与 AND: 按位进行与操作,当且仅当两个操作位均为 1 时结果才为 1
  • 按位或 OR: 按位进行或操作,当两个操作位任意一位为 1 时结果就为 1
  • 按位取反 NOT: 按位进行非操作,仅有一个操作数,将 1 变成 0,将 0 变成 1
  • 异或 XOR: 按位进行异或操作,当两个操作位相同时结果为 0,反之为 1
  • 条件分支指令 conditional branch: 该指令先比较两个值,然后根据比较的结果决定是否从程序中的一个新地址开始执行指令序列
  • 基本块 basic block: 没有分支(可能出现在末尾者除外)并且没有分支目标/分支标签(可能出现在开始者除外)的指令序列
  • 转移地址表 jump address table: 又称作转移表(jump table),指包含不同指令序列地址的表
  • 过程 procedure: 根据提供的参数执行一定任务的子程序
  • 跳转和链接指令 jump and link instruction: 跳转到某个地址的同时将下一条指令的地址保存到寄存器中的指令
  • 返回地址 return address: 指向调用点的链接,使过程可以返回到合适的地址
  • 调用者 caller: 调用一个过程并为过程提供必要参数值的程序
  • 被调用者 callee: 根据调用者提供的参数执行一系列存储的指令,然后将控制权返回调用者的过程
  • 程序计数器 program counter, PC: 包含在程序中正在被执行指令地址的寄存器
  • 栈 stack: 被组织成后进先出队列形式并用于寄存器换出的数据结构
  • 栈指针 stack pointer: 指示栈中最近分配的地址的值,它指示寄存器被换出的位置,或寄存器旧值的存放位置
  • 压栈 push: 向栈中增加元素
  • 出栈 pop: 从栈中移除元素
  • 全局指针 global pointer: 指向静态数据区的保留寄存器
  • 过程帧 procedure frame: 也称作活动记录 activation record,栈中包含过程所保存的寄存器以及局部变量的片段
  • 帧指针 frame pointer: 指向给定过程中保存的寄存器和局部变量的值
  • 正文段 text segment: UNIX 目标文件中的段,包含源文件中例程对应的机器语言代码
  • PC 相对寻址 PC-relative addressing: 一种寻址方式,它将 PC 和指令中的常数相加作为寻址结果
  • 寻址模式 addressing mode: 根据对操作数和/或地址的使用不同加以区分的多种寻址方式的一种
  • 数据竞争 data race: 假如来自不同线程的两个内存地址访问同一个地址,它们连续出现,并且至少其中一个是写操作,那么这两个存储访问形成数据竞争
  • 汇编语言 assembly language: 一种符号语言,能被翻译成二进制的机器语言
  • 伪指令 pseudoinstruction: 汇编语言指令的一个变种,常被看做一条汇编指令
  • 符号表 symbol table: 一个用来匹配标记名和指令所在内存字的地址的列表
  • 链接器 linker: 它是一个系统程序,它把各个独立汇编的机器语言组合起来并且解决所有未定义的标记,最后生成可执行文件。
  • 可执行文件 executable file: 一个具有目标文件格式的功能程序,不包含未解决的引用。它可以包含符号表和调试信息。『剥离的可执行程序』不包含这些信息,可能包含加载器所需的重定位信息
  • 加载器 loader: 把目标程序装载到内存中以准备运行的系统程序
  • 动态链接库 dynamically linked libraries, DLL: 在程序执行过程中才被链接的库例程
  • Java 字节码 Java bytecode: 为了解释 Java 程序而设计的指令集中的指令
  • Java 虚拟机 Java Virtual Machine: 解释 Java 字节码的程序
  • 即时编译器 Just In Time compiler: 一类通用编译器的名称,编译器能够在运行时将解释的代码段翻译成宿主计算机上的机器语言
  • 面向对象语言 objected oriented language: 一种针对对象而不是动作的编程语言,或者针对数据而不是逻辑
  • 算数逻辑单元 ALU: 用于执行加法、减法,通常也包括如逻辑与、逻辑或等逻辑操作的硬件
  • 异常 exception: 也叫中断 interrupt,一种打断正常程序执行过程的事件,用于溢出检测
  • 中断 interrupt: 来自处理器外部的异常(在某些体系结构中所有的异常都称为中断)
  • 组合单元 combinational element: 一个操作单元,如与门或 ALU
  • 状态单元 state element: 一个存储单元,如寄存器或存储器
  • 有效 asserted: 信号为逻辑高或真
  • 无效 deasserted: 信号为逻辑低或假
  • 时钟方法 clocking methodology: 用来确定数据相对于时钟何时稳定和有效的方法
  • 边沿出发的时钟 edge-triggered clocking: 一种所有的状态改变发生于时钟沿的时钟机制
  • 控制信号 control signal: 用来决定多选器选择或指示功能单元操作的信号;它与数据信号相对应,数据信号包含由功能单元操作的信息
  • 数据通路部件 datapath element: 一个用来操作或保存处理器中数据的单元
  • 寄存器堆 register file: 包含一系列寄存器的状态单元,可以通过提供寄存器号进行读写
  • 符号扩展 sign-extend: 为增加数据项的长度,将原数据项的最高位复制到新数据多出来的高位
  • 分支目标地址 branch target address: 该地址指定了一个分支,如果分支发生,那么它将称为新的程序计数器 PC
  • 分支发生 branch taken: 分支条件满足而 PC 变为分支目标地址的分支。所有的无条件跳转都是发生的分支
  • 分支未发生 branch not taken: 分支条件不满足而 PC 变为分支指令的下一条指令
  • 延迟的分支 delayed branch: 不管分支条件是否满足,分支指令之后的那条指令总被执行的一种分支
  • 真值表 truth table: 逻辑操作的一种表示方法,即列出输入的所有情况和每种情况下的输出
  • 无关项 don’t care term: 逻辑函数的一个元素,表示输出与该输入取值无关。无关项可以用不同的方式指定
  • 操作码 opcode: 指示指令操作和格式的字段
  • 单周期实现 single-cycle implementation: 也被称为单时钟周期实现 single clock cycle implementation,即一个时钟周期执行一条指令的实现机制
  • 流水线 pipelining: 一种实现多条指令重叠执行的技术,与生产流水线类似
  • 结构冒险 structural hazard: 因缺乏硬件支持而导致指令不能在预定的时钟周期内执行的情况
  • 数据冒险 data hazard: 也称为流水线数据冒险,即因无法提供指令执行所需数据而导致指令不能在预订的时钟周期内执行的情况
  • 转发 forwarding: 也称为旁路 bypassing。一种解决数据冒险的方法,具体做法是从内部寄存器而非程序员可见的寄存器或存储器中提前取出数据
  • 装载 - 使用型数据冒险 load-use data hazard: 一类特殊的数据冒险,指当装载指令要取的数还没取回来时其他指令就需要使用的情况
  • 流水线阻塞 pipeline stall: 也称为气泡 bubble。为了解决冒险而实施的一种阻塞
  • 控制冒险 control hazard: 也称为分支冒险 branch hazard。因为取到的指令并不是所需要的(或者说指令地址的变化并不是流水线所预期的)而导致指令不能在预订的时钟周期内执行
  • 分支预测 branch prediction: 一种解决分支冒险的方法。它预测分支结果并立即沿预测方向执行,而不是等真正的分支结果确定后才开始执行
  • 延迟 latency: 流水线的级数活着顺序执行过程中两条指令间的级数
  • 空指令 nop: 一种不进行任何操作或不改变任何状态的指令
  • 清除 flush: 因发生了意外而丢弃流水线中的指令
  • 动态分支预测 dynamic branch prediction: 根据运行信息在运行中进行分支预测
  • 分支预测缓存 branch prediction buffer: 也称为分支历史记录表 branch history table。一小块按照分支指令的低位地址索引的存储器区,其中包括一位或多位数据用以说明最近是否发生过分支
  • 分支延迟时间片 branch delay slot: 紧跟延迟分支指令的时间片
  • 分支目标缓存 branch target buffer: 一种用于缓存分支目标地址或分支目标指令的结构,其一般形式为带标志位的 cache,因而其硬件开销大于简单的分支预测缓存器
  • 相关预测器 correlating predictor: 综合考虑特定分支的局部行为和最近执行分支的全局行为的分支预测器
  • 竞赛预测器 tournament branch predictor: 具有多种预测机制的分支预测器。其带有一个选择器,对给定分支可选择其中一个作为预测结果
  • 向量中断 vectored interrupt: 由异常原因决定中断控制转移地址的中断
  • 非精确中断 imprecise interrupt: 也称为非精确异常 imprecise exception。流水线处理器中的中断或异常不与导致中断或异常的指令精确地关联
  • 精确中断 precise interrupt: 也称为精确异常 precise exception。流水线处理器中的中断或异常与导致中断或异常的指令精确地关联
  • 指令级并行 instruction-level parallelism: 指令间的并行性
  • 多发射 multiple issue: 一种单时钟周期内发射多条指令的机制
  • 静态多发射 static multiple issue: 实现多发射处理器的一种方式,其中决策实在执行前的编译阶段作出的
  • 动态多发射 dynamic multiple issue: 实现多发射处理器的一种方式,其中决策是由处理器在执行阶段作出的
  • 发射槽 issue slot: 在给定时钟周期内能够发射指令的位置,可以类比于短跑比赛中的起点位置
  • 推测 speculation: 一种编译器或处理器推测指令结果以消除执行其他指令对该结果依赖的技术
  • 发射包 issue packet: 在一个时钟周期内发射的多条指令的集合。这个包可以由编译器静态生成,也可以由处理器动态生成
  • 超长指令字 Very Long Instruction Word, VLIW: 一类可以同时启动多个操作的指令集,其中操作在单个指令中相互独立,并且一般都有独立的操作码域
  • 使用延迟 use latency: 在装载指令与可以无阻塞使用其结果的指令间相隔的时钟周期数
  • 循环展开 loop unrolling: 一种从存取数组的循环中获取更多性能的技术,其中循环体会被复制多份并且不同的循环体中的指令可能会调度到一起
  • 寄存器重命名 register renaming: 由编译器或硬件对寄存器进行重命名以消除反相关
  • 反相关 antidependence: 也被称为名字相关 name dependence,因为寄存器名的重用导致的相关,并非由两条指令中使用同一个值导致的真正相关
  • 超标量 superscalar: 一种高级流水线技术,可以使每个周期处理器能执行的指令数超过一条
  • 动态流水线调度 dynamic pipeline scheduling: 对指令进行重排序以避免阻塞的硬件支持
  • 提交单元 commit unit: 位于动态流水线和乱序流水线中的一个单元,用以决定何时可以安全地将操作结果送至程序员可见的寄存器和存储器
  • 保留站 reservation station: 功能单元的缓冲区,用来保存操作数和操作
  • 重排序缓冲区 reorder buffer: 动态调度处理器中用于暂时保存执行结果的缓冲区,等到安全时才将其中的结果写回寄存器或存储器
  • 乱序执行 out-of-order execution: 流水线执行的一种情况,即执行的指令被阻塞时不会导致后面的指令等待
  • 顺序提交 in-order commit: 流水线执行的结果以取指顺序写回程序员可见寄存器的一种提交方式
  • 微体系结构 microarchitecture: 处理器的组织,包括主要的功能单元及它们的互连关系与流水线控制
  • 体系结构寄存器 architectural register: 处理器中的可见寄存器
  • 指令延迟 instruction latency: 执行一条指令所真正花费的时间
  • 时间局部性 temporal locality: 某个数据在被访问之后可能很快被再次访问的特性
  • 空间局部性 spatial locality: 某个数据项在被访问之后,与其地址相近的数据项可能很快被访问的特性
  • 存储器层次结构 memory hierarchy: 一种由多存储层次组成的结构,存储器的容量和访问时间随着与处理器距离的增加而增加
  • 块 block 或行 line: 可存在于或不存在于 cache 中的信息的最小单元
  • 命中率 hit rate: 在高层存储器中找到目标数据的存储访问比例
  • 缺失率 miss rate: 在高层存粗气中没有找到目标数据的存储访问比例
  • 命中时间 hit time: 访问某存储器层次结构所需要的时间,包括了判断当前访问是命中还是缺失所需的时间
  • 缺失代价 miss penalty: 将相应的块从低层存储器替换到高层存储器所需的时间,包括访问块、将数据逐层传输、将数据插入发生缺失的层和将信息块传送给请求者的时间
  • 直接映射 direct mapped: 一种 cache 结构,其中每个主存地址仅仅对应到 cache 中的一个位置
  • 标记 tag: 表中的一个字段,包含了地址信息,这些地址信息可以用来判断 cache 中的字是否就是所请求的字
  • 有效位 valid bit: 表中的一个字段,用来标识一个块是否含有一个有效数据
  • cache 缺失: 由于数据不在 cache 中而导致被请求的数据不能满足
  • 写直达法 write-through: 也翻译为写通过。写操作总是同时更新主存和 cache,以保持二者一致性的一种方法
  • 写缓冲 write buffer: 一个保存等待写入主存数据的缓冲队列
  • 写回机制 write-back: 当发生写操作时,新值仅仅被写入 cache 块中,只有当修改过的块被替换时才写到较低层存储结构中
  • 分离 cache, split cache: 一级 cache 由两个独立的 cache 组成,两者可以并行工作,一个处理指令,另一个处理数据
  • 全相联缓存 fully associative cache: cache 的一种组织方式,块可以放置到 cache 中的任何位置
  • 组相联缓存 set-associative cache: cache 的另一种组织方式,块可以放置到 cache 中的部分位置(至少两个)
  • 最近最少使用法(LRU, least recently used): 一种替换策略,总是替换很长时间没有被使用的块
  • 多级缓存 multilevel cache: 存储系统由多级缓存组成,而不仅仅只有主存和一个缓存
  • 全局缺失率 global miss rate: 在多级 cache 中所有级中都缺失的那部分访问
  • 局部缺失率 local miss rate: 在多级 cache 中,某一级 cache 的缺失率
  • 虚拟存储器 virtual memory: 一种将主存用作辅助存储器告诉缓存的技术
  • 物理地址 physical address: 主存储器的地址
  • 保护 protection: 一组确保共享处理器、主存、I/O 设备的多个进程之间没有故意地、无意地读写掐进程的数据机制,这些保护机制可以将操作系统和用户的进程隔离开来
  • 缺页 page fault: 访问的页不在主存储器中
  • 虚拟地址 virtual address: 虚拟空间的地址,当需要访问主存时需要通过地址映射转换为物理地址
  • 地址转化 address translation: 也称为地址映射 address mapping。在访问内存时将虚拟地址映射为物理地址的过程。
  • 交换区 swap space: 为进程的全部虚拟地址空间所预留的磁盘空间
  • 引用位 reference bit: 也称为使用位 use bit。每当访问一个页面时该位被置位,通常用来实现 LRU 或其他替换策略
  • 快表 translation-lookaside buffer, TLB: 用于记录最近使用骶椎的映射信息的高速缓存,从而可以避免每次都要访问页表
  • 虚拟寻址缓存 virtually addressed cache: 一种使用虚拟地址而不是物理地址访问的 cache
  • 别名 aliasing: 使用两个地址访问同一个目标的情形,一般发生在虚拟存储器中两个虚拟地址对应到同一个物理地址时
  • 物理寻址缓存 physically addressed cache: 使用物理地址寻址的 cache
  • 超级用户管理模式 supervisor mode: 也称作管态、核心模式 kernel mode。运行操作系统进程的模式
  • 系统调用 system call: 将控制权从用户模式转换到管理员模式的特殊指令,触发进程中的一个异常机制
  • 上下文切换 context switch: 为允许另一个不同的进程使用处理器,改变处理器内部的状态,并保存当前进程返回时需要的状态
  • 使能异常 exception enable: 也称为中断使能 interrupt enable,用于控制处理器是否响应异常的信号或动作;在处理器安全地保存重启所需信息之前,必须阻止异常的发生
  • 可重启指令 restartable instruction: 一种在异常被处理之后能从异常中恢复而不会影响指令的执行结果的指令
  • 处理程序 handler: 用于『处理』异常或中断的软件程序的名字
  • 非映射的 unmapped: 地址空间中的一个部分,在这个区域不会导致缺页异常
  • 3C three Cs model: 将所有的 cache 缺失都归位三种类型的 cache 模型,三类分别为:强制缺失、容量缺失和冲突缺失。因其三类名称的英文单词首字母均为 c 而得名
  • 强制缺失 compulsory miss: 也称为冷启动缺失 cold-start miss。对没有在 cache 中出现过的块第一次访问时产生的缺失
  • 容量缺失 capacity miss: 由于 cache 在全相联时都不可能容纳所有请求的块而导致的缺失
  • 冲突缺失 conflict miss: 也称为碰撞缺失。在组相联活着直接映射 cache 中,很多块为了竞争同一个组导致的缺失。这种缺失在使用相同大小的全相联 cache 中是不存在的
  • 有限状态机 finite-state machine: 由一组输入和输出,以及下一状态函数和输出函数组成的时序逻辑函数。下一状态函数将当前状态和当前输入映射为一个新的状态,输出函数将当前状态和当前输入映射为一组确定的输出
  • 下一状态函数 next-state function: 根据当前状态及当前输入来确定有限状态机下一状态的组合函数
  • 假共享 false sharing: 当两个不相关的共享变量放在相同的 cache 块中时,尽管每个处理器访问的是不同的变量,但是在处理器之间还是将整个块进行交换
  • 非阻塞缓存 nonblocking cache: 在处理器处理前面的 cache 缺失时仍可正常访问的 cache
  • 预取 prefetching: 使用特殊指令将未来可能用到的指定地址的 cache 块提前搬到 cache 中的一种技术
  • 非易失性的 nonvolatile: 当断电时,数据仍保留的存储设备
  • 磁道 track: 磁盘面上的一个同心圆为一个磁道
  • 扇区 sector: 磁道上的一段弧称为扇区,一个扇区是磁盘中被读活着写的最小信息块
  • 寻道 seek: 在一个读或者写操作中,把磁头定位到合适的磁道的过程
  • 旋转时间 rotational latency: 也称为旋转延迟 rotational delay,是使得合适的扇区旋转到读/写头下的时间
  • ATA, Advanced Technology Attachment: 在 PC 中很流行的一种被用作 I/O 设备标准的指令集
  • SCSI, Small Computer Systems Interface: 一种 I/O 设备的标准指令集
  • 处理器-内存总线 processor-memory bus: 连接处理器和内存的总线。通常比较短,速度高,和内存系统匹配,这样可以使得处理器和内存间的带宽达到最大
  • 底板总线 backplane bus: 一个用来连接处理器、内存和 I/O 设备的单一总线
  • I/O 事务 I/O transaction: 在一个互联上的一系列操作,包含了一个请求及可能的回答,它们均可能包含数据。一个事务由一个请求发起,可能包含很多独立的总线操作
  • 同步总线 synchronous bus: 这样的总线的控制线包含了时钟信号,以及依赖这个时钟的固定通信协议
  • 异步互联 asynchronous interconnect: 使用一个握手协议来协调而不用时钟,可以适应速度相异的不同设备
  • 握手协议 hand shaking protocol: 是为了协调异步总线传输而使用的一系列步骤,在这些步骤中,发送者和接受者只有当彼此都对当前的步骤确认时,才可以进行下一个步骤
  • 内存映射 I/O memory-mapped I/O: 一种 I/O 策略,地址空间的一部分被分配给 I/O 设备,而且读和写这些地址被解释为 I/O 设备的指令
  • I/O 指令 I/O instruction: 一种专用指令,用来给 I/O 设备发送指令,而且指定了设备号,以及指令字(或者内存中的指令字的地址)
  • 轮询 polling: 周期性地检查 I/O 设备的状态寄存器的过程,目的是确定是不是需要为设备服务
  • 中断驱动 I/O interrupt-driven I/O: 一种 I/O 策略,利用中断来指示处理器某个设备需要被关注
  • 直接内存访问 direct memory access, DMA: 一种提供设备控制器的机制,具备能够从内存传输数据,而不需要处理器介入的能力
  • 总线控制器 master: 处于 I/O 互联中的一个单元,能够发起传输请求
  • 事务处理 transaction processing: 这是一种应用,包含了处理小的、短的操作(事务),这些事务通常需要 I/O 和计算。事务处理应用通常具有响应时间的需求和基于事务吞吐量的性能度量
  • I/O 速率 I/O rate: 单位时间的 I/O 性能尺度,例如,每秒钟读操作数目
  • 数据速率 date rate: 单位时间字节的性能尺度,例如,GB/s
  • 条带化 striping: 将逻辑上连续的数据块分布到不同的磁盘上,得到比单个磁盘更高的性能
  • 镜像 mirroring: 将相同的数据写到多个磁盘上,目的是增加数据的可用性
  • 保护组 protection group: 共享一个公共校验磁盘的数据磁盘组或者数据块
  • 热交换 hot-swapping: 系统运行的时候,替换一个硬件模块
  • 应急备用 standby spares: 使用预留的硬件资源立即替换发生故障的模块
  • 多处理器器 multiprocessor: 至少含有两个处理器的计算机系统。与之对应的概念是单处理器 uniprocessor
  • 作业级并行 job-level parallelism 活着进程级并行 process-level parallelism: 通过同时运行独立程序的方法来利用多处理器
  • 并行处理程序 parallel processing program: 同时运行在多个处理器上的单一程序
  • 集群 cluster: 通过局域网连接的一组计算机,其作用等同于一个大型的多处理器。一组通过 I/O 接口与标准网络交换机连接而形成的消息传递多处理机
  • 多核微处理器 multicore microprocessor: 在单一集成电路上包含多个处理器(核)的微处理器
  • 强比例缩放 strong scaling: 在多处理器上不需增加问题规模即可获得的加速比
  • 弱比例缩放 weak scaling: 在多处理器上增加处理器数量的同时按比例增加问题规模所能获得的加速比
  • 共享存储多处理器 shared memory multiprocessor, SMP: 具有单一地址空间的并行处理器,存取时采用隐式通信的方式
  • 统一存储访问 uniform memory access, UMA: 无论访存的是哪个处理器,也无论访存的是哪个字,访存时间都大致形同的多处理器
  • 非统一存储访问 nonuniform memory access, NUMA: 使用单一地址空间多处理器的一种类型,某些存储访存速度高于其他访存,访存速度与访问哪个处理器及访问哪个字相关
  • 同步 synchronization: 对可能运行于不同处理器上的两个或者更多进程的行为进行协调的过程
  • 锁 lock: 一个时刻仅允许一个处理器访问数据的同步装置
  • 约简 reduction: 处理一个数据结构并返回单一值的函数
  • 消息传递 message passing: 通过显式发送和接收信息的方式在多个处理器之间通信
  • 发送消息例程 send message routine: 具有私有存储器的机器中一个处理器将消息发送给另一个处理器的例程
  • 接收消息例程 receive message routine: 具有私有存储器的机器中一个处理接收来自其他处理器消息的例程
  • 硬件多线程 hardware multithreading: 在线程阻塞时处理器可切换到另一线程的实现
  • 细粒度多线程 fine-grained multithreading: 硬件多线程的一种形式,其坚毅每条指令执行之后都进行线程切换
  • 粗粒度多线程 coarse-grained multithreading: 硬件多线程的一种形式,其建议仅在一些重要事件(如缓存缺失)之后进行线程切换
  • 同时多线程 simultaneous multithreading, SMT: 多线程的一种形式,其利用多发射、动态调度微体系结构中的资源实现多线程,从而降低多线程的开销
  • SISD Single Instruction stream, Single Data stream: 单指令流单数据流的单处理器
  • MIMD Multiple Instruction streams, Multiple Data streams: 多指令流多数据流的多处理器
  • SPMD Single Program, Multiple Data streams: 单程序多数据流。传统的 MIMD 编程模型,其中一个程序运行在所有处理器之上
  • SIMD Single Instruction stream, Multiple Data streams: 单指令流多数据流。同样的指令在多个数据流上操作,和向量处理器或阵列处理器一样
  • 数据级并行 data-level parallelism: 操作独立的数据所获得的并行
  • 网络带宽 network bandwidth: 非正式用语,用于表示网络传输速度的峰值;既可以指单一链路的速度,也可以指网络中全部链路的共同传输速度
  • 切分带宽 bisection bandwidth: 多处理器中两个相等部分之间的带宽。这种测量可以表示对多处理器的最差拆分情况
  • 全连接网络 fully connected network: 通过专用通信链路连接所有处理器 - 存储器节点的网络
  • 多级网络 multistage network: 每个节点提供一个小开关的网络
  • 交叉开关网络 crossbar network: 任何一个需一次即可与其他任意一个节点通信的网络
  • Pthread: 创建和操作线程的一个 UNIX API。它使用一个库提供
  • OpenMP: 在 C、C++ 或 Fortran 中用于共享内存多处理编程的 API,可以运行于 UNIX 和 Microsoft 平台。它包括编译器指示、一个库和运行时指示
  • 算数密度 arithmetic intensity: 一个程序中浮点操作数量与访问主存字节数量的比值
  • 软件即服务 software as a service: 软件不再是安装运行在客户自己的计算机上,而是运行在远程计算机上,通过 Internet 来使用,典型情况是通过 Web 接口为客户服务。然后根据使用情况向客户收费
  • 图形处理单元 graphics processing unit, GPU: 一种面向 2D 和 3D 图形、视频、可视化计算和显示优化的处理器
  • 可视化计算 visual computing: 图形处理和计算的混合体,使得用户可以通过图形、图像和视频可视化与计算对象进行交互
  • 异构系统 heterogeneous system: 由不同类型处理器组成的系统,如 PC 是 CPU 和 GPU 组成的异构系统
  • 应用程序接口 Application Programming Interface, API: 函数和数据结构定义的集合,为函数库提供一个接口
  • GPU 计算 GPU computing: 通过并行编程语言和 API 使用 GPU 进行计算
  • GPU 上的通用计算 General Purpose computation on GPU, GPGPU: 通过传统的图形 API 和图形流水线进行通用目的的计算
  • 统一计算设备架构 Compute Unified Device Architecture, CUDA: 一个基于 C/C++ 语言的可扩展并行编程模型。它是面向 GPU 和多核 CPU 的一个并行编程平台
  • PCI-Express, PCIe: 一种使用点对点链路的系统标准 I/O 互连,其链路具有可配置的槽数和带宽
  • 统一存储架构 unified memory architecture, UMA: 一种 CPU 和 GPU 共享系统存储器的体系结构
  • AGP: 一个 PCI I/O 总线的扩展版本,为一个单一的卡槽提供高达 8 倍于原始 PCI 总线的带宽。它的主要目的是将图形子系统连接到 PC 系统
  • OpenGL: 一个开放标准图形 API
  • Direct3D: 由微软及其合作伙伴定义的一个图形 API
  • 纹理 texture: 支持使用插值坐标进行采样和过滤的一个 1D、2D 或 3D 的数组
  • 渲染程序 shader programme: 对图形数据,如定点或像素段,进行操作的一个程序
  • 渲染语言 shading language: 一种图形描述语言,通常具有一个数据流或流编程模型
  • 内核 kernel: 适合与一个线程的程序或函数,设计用来被众多线程执行
  • 线程块 thread block: 执行相同线程程序并相互协作以计算结果的一系列并发线程
  • 网格 grid: 执行相同内核程序的一系列线程块
  • 同步栅障 synchronization barrier: 线程在同步栅障处等待,直到线程块中的所有线程到达该栅障
  • 原子存储器操作 atomic memory operation: 一个存储器读、修改、写操作序列,它们直到执行完成不被任何访问打断
  • 局部存储器 local memory: 每个线程的局部存储器,被该线程私有
  • 共享存储器 shared memory: 每个线程块存储器,被块中的所有线程共享
  • 全局存储器 global memory: 每个应用存储器,被所有的线程共享
  • 单程序多数据 single-program multiple data, SPMD: 并行编程模型的一种网格,其所有的线程执行同样的程序。典型地,SPMD 线程通过栅障同步进行协调
  • 单指令多线程 single-instruction multiple-thread, SIMT: 应用一条指令到多个独立的并行线程上的一种处理器结构
  • warp: 在 SIMT 结构下,一起执行相同指令的并行线程集
  • 协作线程组 cooperative thread array, CTA: 一组执行相同的线程程序且可以协作计算出一个结果的并发线程。一个 GPU CTA 实现一个 CUDA 线程块
  • 半精度 half precision: 一个 16 位二进制浮点格式,有 1 位符号为、5 位指数、10 位小数和隐含的整数位
  • 乘加 multiply-add, MAD: 执行一个先乘后加组合操作的单精度浮点指令
  • 特殊功能单元 special function unit, SFU: 一个用于计算特殊功能和插值平面属性的硬件单元
  • 前向引用 forward reference: 一个标签在被定之前就被使用
  • 符号表 symbol table: 用来将标签的名字和指令占用的内存字的地址相匹配的一个表
  • 反向修补 backpatching: 一种将汇编语言翻译成机器指令的办法,其中汇编器在第一遍扫描程序时就构建一个(可能不完整的)每个指令的二进制表示,然后返回对前面没有定义的标签进行替换
  • 代码段 text segment: UNIX 目标文件的一个段,源文件中程序的机器语言代码
  • 数据段 data segment: UNIX 目标文件活着可执行文件的一个段,包含程序初始所使用的数据的二进制表示
  • 重定位信息 relocation information: UNIX 目标文件的一个段,根据绝对地址来区别数据字和指令
  • 绝对地址 absolute address: 内存中标量或者程序的实际地址
  • 形式参数 formal parameter: 过程或者宏的参数变量,一旦这个变量被参数替换,宏就被展开
  • 单独编译 separate compilation: 将程序划分成多个文件,每个文件被编译时,并不知道其他文件的信息
  • 静态数据 static data: 包含数据的那部分内存,其大小为编译器所知,生命周期为整个程序的运行时间
  • 堆栈段 stack segment: 程序用来保存过程调用帧的那段内存
  • 寄存器使用 register use convention: 或者称为 procedure call convention,管理过程(调用)使用寄存器的软件协议
  • 调用者保存的寄存器 caller-saved register: 调用程序保存的寄存器
  • 被调用者保存的寄存器 caller-saved register: 被调用者程序保存的寄存器
  • 过程调用帧 procedure call frame: 用来保存被调用过程的参数,保存可能会被过程修改的寄存器的值,但是这些寄存器的值不会被调用者所修改,并为被调用程序的局部变量提供空间
  • 递归过程 recursive procedure: 就是指某个过程能通过调用链直接或间接地调用自己
  • 中断处理 interrupt handler: 一段代码,座位异常或中断的执行结果
  • 虚拟机 virtual machine: 一种虚拟计算机,它分支和取数指令没有延迟,且指令集比实际硬件更丰富