为了理解改进性能的方法,我们需要理解现代处理器的微体系结构。由于大量的晶体管可以被集成到一块芯片上,现代微处理器采用了复杂的硬件,试图使程序性能最大化。带来的一个后果就是处理器的实际操作与通过观察机器级程序所察觉到的大相径庭。在代码级上,看上去似乎是一次执行一条指令,每条指令都包括从寄存器或内存取值,执行一个操作,并把结果存回到一个寄存器或内存位置。在实际的处理器中,是同时对多条指令求值的,这个现象称为指令级并行。在某些设计中,可以有100或更多条指令在处理中。采用一些精细的机制来确保这种并行执行的行为,正好能获得机器级程序要求的顺序语义模型的效果。现代微处理器取得的了不起的功绩之一是:它们采用复杂而奇异的微处理器结构,其中,多条指令可以并行地执行,同时又呈现出一种简单的顺序执行指令的表象。
整体操作
下图是一个简化的现代微处理器,它可以在每个时钟周期乱序执行多个操作。整个设计主要分为两个部分:
指令控制单元ICU:负责从内存中读出指令序列,并根据这些指令序列生成一组针对程序数据的基本操作。
执行单元EU:执行这些操作。
ICU从指令高速缓存(instruction cache)中读取指令,指令高速缓存是一个特殊的高速存储器,它包含最近访问的指令。通常,ICU会在当前正在执行的指令很早之前取指,这样它才有足够的时间对指令译码,并把操作发送到EU。不过,一个问题是当程序遇到分支 时,程序有两个可能的前进方向。一种可能会选择分支,控制被传递到分支目标。另一种可能是,不选择分支,控制被传递到指令序列的下一条指令。现代处理器采用了一种称为分支预测(branch prediction)的技术,处理器会猜测是否会选择分支,同时还预测分支的目标地址。使用投机执行(speculative execution)的技术,处理器会开始取出位于它预测的分支会跳到的地方的指令,并对指令译码,甚至在它确定分支预测是否正确之前就开始执行这些操作。如果过后确定分支预测错误,会将状态重新设置到分支点的状态,并开始取出和执行另一个方向上的指令。标记为取指控制的块包括分支预测,以完成确定取哪些指令的任务。
EU接收来自取指单元的操作。通常,每个时钟周期会接收多个操作。这些操作会被分派到一组功能单元中,它们会执行实际的操作。这些功能单元专门用来处理不同类型的操作。
读写内存是由加载和存储单元实现的。加载单元处理从内存读数据到处理器的操作。这个单元有一个加法器来完成地址计算。类似,存储单元处理从处理器写数据到内存的操作。它也有一个加法器来完成地址计算。如图中所示,加载和存储单元通过数据高速缓存(data cache)来访问内存。数据高速缓存是一个高速存储器,存放着最近访问的数据值。
使用投机执行技术对操作求值,但是最终结果不会存放在程序寄存器或数据内存中,直到处理器能确定应该实际执行这些指令。分支操作被送到EU,不是确定分支该往哪里去,而是确定分支预测是否正确。如果预测错误,EU会丢弃分支点之后计算出来的结果。它还会发信号给分支单元,说预测是错误的,并指出正确的分支目的。在这种情况中,分支单元开始在新的位置取指。这样的预测错误会导致很大的性能开销。在可以取出新指令、译码和发送到执行单元之前,要花费一点时间。
在ICU中,退役单元(retirement unit)记录正在进行的处理,并确保它遵守机器级程序的顺序语义。我们的图中展示了一个寄存器文件,它包含整数、浮点数和最近的SSE和AVX寄存器,是退役单元的一部分,因为退役单元控制这些寄存器的更新。指令译码时,关于指令的信息被放置在一个先进先出的队列中。这个信息会一直保持在队列中,直到发生以下两个结果中的一个。首先,一旦一条指令的操作完成了,而且所有引起这条指令的分支点也都被确认为预测正确,那么这条指令就可以退役(retired)了,所有对程序寄存器的更新都可以被实际执行了。另一方面,如果引起该指令的某个分支点预测错误,这条指令会被清空(flushed),丢弃所有计算出来的结果。通过这种方法,预测错误就不会改变程序的状态了。
控制操作数在执行单元间传送的最常见的机制称为寄存器重命名(register renaming)。当一条更新寄存器r的指令译码时,产生标记t,得到一个指向该操作结果的唯一的标识符。条目(r,t)被加入到一张表中,该表维护着每个程序寄存器r与会更新该寄存器的操作的标记t之间的关联。当随后以寄存器r作为操作数的指令译码时,发送到执行单元的操作会包含t作为操作数源的值。当某个执行单元完成第一个操作时,会生成一个结果(v,t),指明标记为t的操作产生值v。所有等待t作为源的操作都能使用v作为源值,这就是一种形式的数据转发。通过这种机制,值可以从一个操作直接转发到另一个操作,而不是写到寄存器文件再读出来,使得第二个操作能够在第一个操作完成后尽快开始。重命名表只包含关于有未进行写操作的寄存器条目。当一条被译码的指令需要寄存器r,而又没有标记与这个寄存器相关联,那么可以直接从寄存器文件中获取这个操作数。有了寄存器重命名,即使只有在处理器确定了分支结果之后才能更新寄存器,也可以预测着执行操作的整个序列。
功能单元的性能
每个运算都是由以下这些数值来刻画的:
延迟:表示完成运算所需要的总时间。
发射时间:表示两个连续的同类型的运算之间需要的最小时钟周期数。
容量:表示执行该运算的功能单元的数量。
标签:4.2,理解,指令,处理器,寄存器,操作,单元,分支 From: https://www.cnblogs.com/LCAB/p/17458295.html