64-ia-32架构优化手册(4)

来源:互联网 发布:国外健身社交软件 编辑:程序博客网 时间:2024/05/29 04:45

2.3. INTEL®微架构Sandy Bridge

Intel®微架构Sandy Bridge构建在Intel®CoreTM微架构与Intel微架构Nehalem成功的基础上。它提供了创新性的特性:

·        Intel先进向量扩展(Intel Advanced Vector Extension,AVX)

-  对128比特Intel流SIMD扩展(IntelStreaming SIMD Extension)的256比特浮点指令集扩展,相比之下提供最多加倍的性能提升。

-  非破坏性目标编码提供更灵活的编码技术。

-  支持256比特AVX代码,128比特AVX代码及遗留的128比特SSE代码间灵活的迁移与共存。

·        增强前端与执行引擎

-  提升了前端带宽且降低分支误预测代价的,新的已解码ICache组件。

-  先进的分支预测。

-  额外的宏融合(marco-fusion)支持。

-  更大的动态执行窗口。

-  多精度整数算术增强(ADC/SBB,MUL/IMUL)。

-  LEA带宽提升。

-  降低一般执行的暂停(读端口,回写冲突,旁路时延,部分暂停)。

-  快速浮点异常处理。

-  XSAVE/XRSTORE性能提升与XSAVEOPT新指令。

·        用于更宽数据通路的缓存层次结构的改进

-  通过用于内存操作的两个对称端口加倍带宽。

-  通过增加缓冲同时处理更多的读写。

-  每周期两个读与一个写的内部带宽。

-  改进的预取。

-  高带宽、低时延的LLC架构。

-  用于片上互联的高带宽环架构。

·        片上系统支持

-  第二代Intel Core处理器的集成显卡与多媒体引擎。

-  集成的PCIE控制器。

-  集成的内存控制器。

·        下一代Intel Turbo Boost技术

-  撬动TDP余量以促进CPU核与集成显卡的性能。

2.3.1.Intel® Sandy Bridge流水线概览

图2-5显示了基于Intel微架构SandyBridge的处理器核的流水线与主要组件。流水线包括

·        一个顺序发布前端,它获取指令并将它们解码为微操作(micro-ops,micro-operations)。前端向下一级流水线提供来自程序未来最有可能执行路径的连续微操作流。

·        一个乱序超标量执行引擎,每周期它最多可以分发6个微操作。分配/重命名部分重排微操作为“数据流”序,在数据来源与执行资源就绪时,使它们可以尽快得到执行。

·        一个顺序回收(retirement)单元,确保微操作的执行结果根据原始的程序序可见,包括它们可能遭遇的任何异常。

指令在流水线中的流程可总结为以下步骤:

1.      分支预测单元从程序选择下一个要执行的代码块。处理器在下列资源中,以这个次序查找代码:

a.      已解码ICache。

b.      指令缓存,通过活动的遗留(legacy)解码流水线。

c.      必要时,L2缓存,最后一级缓存(LLC)及内存。


2-5. Intel微架构Sandy Bridge流水线功能

1.      对应这段代码的微操作被发送到重命名器/回收部分。它们以程序序进入调度器,但根据数据流序从调度器执行、释放。对于同时就绪的微操作,几乎总是维护FIFO序。

使用在三个栈上安排的执行资源执行微操作。每个栈中的执行单元关联了指令的数据类型。

分支误预测在分支执行时发出信号。它将从正确的路径重新导向发布微操作的前端。处理器可以将分支误预测之前的工作与来自后面正确路径的工作重叠起来。

2.      管理并重排内存操作以实现并发与最大性能。L1数据缓存的不命中转到L2缓存。数据缓存是非阻塞的,可以同时处理多个不命中。

3.      异常(Fault,Trap)在失败指令回收(或尝试回收)时用发出信号。

如果启用Intel超线程技术,每个基于Intel微架构SandyBridge的处理器可以支持两个逻辑处理器。

2.3.2.前端

本节描述前端的关键属性。表2-12列出了前端的组件,它们的功能,以及它们处理的问题。

表2-12. Intel微架构SandyBridge前端组件

组件

功能

性能挑战

指令缓存

指令字节的32K字节后备储存

热点代码指令字节的快速访问

遗留解码流水线

将指令解码为微操作,将它们交付给微操作队列与已解码ICache

提供与之前Intel处理器相同的解码时延与带宽。

已解码ICache的预热

已解码ICache

向微操作队列提供微操作流

以更低的时延与功耗,提供比遗留解码流水线更高的微操作带宽

MSROM

复杂指令微操作流储存,可从遗留解码流水线与已解码ICache访问

 

分支预测单元(BPU)

确定要执行的下一块代码并驱动已解码ICache与遗留解码流水线的查找

通过降低分支误预测提升性能与能量效率

微操作队列

对来自已解码ICache与遗留解码流水线的微操作排队

隐藏前端空泡;以常速提供执行微操作

2.3.2.1. 遗留解码流水线

遗留解码流水线(Legacy Decode Pipeline)由指令转换旁视缓冲(ITLB),指令缓存(ICache),指令预解码,以及指令解码单元组成。

指令缓存与ITLB

一条指令取出是通过ITLB对指令缓存的一个16字节对齐的查找。指令缓存每周期可以向指令预解码器交付16个字节。表2-13给出与前代ICache与ITLB的比较。

表2-13. 微架构SandyBridge的ICache与ITLB

组件

Intel微架构Sandy Bridge

Intel微架构Nehalem

ICache大小

32K字节

32K字节

ICache路数

8

4

ITLB 4K页项数

128

128

ITLB大页项数(2M或4M)

8

7

至于ITLB不命中,会有对第二级TLB(STLB)的一个查找,这对DTLB与ITLB是相同的。一个ITLB不命中与一个STLB命中的代价是7个周期。

指令预解码

预解码单元接受来自指令缓存的16个字节,并确定这些指令的长度。

接着的长度改变前缀(LCP)意味着指令长度不同于默认的指令长度。因此在长度解码期间,每个LCP导致一个额外的3周期代价。在之前的处理,对每个具于一个或多个LCP的16字节块会引起一个6周期的代价。因为通常在一个16字节块中LCP不会多于1个,在大多数情形下,Intel微架构SandyBridge较之前的处理器引入了一个提升。

·        操作数大小重写(Operand Size Override,66H)在一条带有一个字/双字立即数指令之前。当代码使用16比特数据类型,unicode处理,以及图像处理时,这个前缀可能出现。

·        地址大小重写(Address Size Override,67H)在一条在实模式、大实模式、16比特保护模式或32比特保护模式下,带有一个modr/m的指令之前。这个前缀可能出现在启动代码序列中。

·        Intel® 64指令集中的REX前缀(4xh)可以改变两类指令的大小:MOV偏移与MOV立即数。尽管有这个能力,它不会导致一个LCP代价,因此不被视为一个LCP。

指令解码

有4个解码单元将指令解码为微操作。第一个可以解码所有的大小不超过4个微操作的IA-32与Intel64指令。余下3个解码单元处理单微操作指令。所有4个解码单元都支持单微操作流的常见情形,包括微融合(micro-fusion)与宏融合(macro-fusion)。

由解码器发出的微操作被导向到微操作队列与已解码ICache。超过4个微操作的指令从MRSOM产生它们的微操作。MSROM带宽是每周期4个微操作。微操作来自MRSOM的指令可以从遗留解码流水线或已解码ICache出发。

微融合(micro-fusion)

微融合将来自同一条指令的多个微操作融合为一个复杂的微操作。这个复杂微操作被分发到乱序执行核,次数就跟它没有被微融合时一样。

微融合使得你可以使用内存到寄存器的操作,也称为复杂指令集计算机(CISC)指令集,在表达实际程序的操作时无需担心解码带宽。微融合改进了从解码到回收提供的指令带宽并节省能源。

通过使用单微操作指令来编码一个指令序列将增加代码大小,会降低遗留流水线的提取带宽。

以下是可以由所有解码器处理的微融合微操作的例子。

·        所有的内存写,包括立即数写。在内部写作为两个独立的功能执行,写地址(store-address)与写数据(store-data)。

·        所有结合了读与计算操作(load+op)的指令,例如:

-   ADDPSXMM9, OWORD PTR [RSP+40]

-   FADDDOUBLE PTR [RDI+RSI*8]

-   XORRAX, QWORD PTR [RBP+32]

·        所有形式为“读且跳转”的指令,例如:

-   JMP[RDI+200]

-   RET

·        带有立即操作数与内存操作数的CMP与TEST

在下列情形里,带有RIP相对取址的一条指令不进行微融合:

·        需要一个额外立即数,例如:

-   CMP[RIP+400], 27

-   MOV[RIP+3000], 142

·        指令是一条带有使用RIP相对取址指定的间接目标的控制流指令,例如:

-   JMP[RIP+5000000]

在这些情形里,不能被微融合的一条指令将要求解码器0来发布两个微操作,导致解码带宽的些微损失。

在64比特代码中,RIP相对取址的使用对全局数据是常见的。因为在这些情形里没有微融合,在移植32位代码到64位代码时性能可能会下降。

宏融合(marco-fusion)

宏融合将两条指令合并为单个微操作。在Intel Core微架构中,这个硬件优化局限于特定于第一与第二个可宏融合指令对的特定条件。

·        宏融合对的第一条指令修改这些标记。以下指令可以被后融合:

-  在Intel微架构Nehalem中:CMP,TEST

-  Intel微架构Sandy Bridge中:CMP,TEST,ADD,SUB,AND,INC,DEC

-  这些指令可以融合,如果

§  第一个源/目标操作数是一个寄存器

§  第二个源操作数(如果存在)是:立即数,寄存器,或非RIP相对内存之一。

·        可宏融合对的第二条指令是一个条件跳转。对每条指令,表3-1描述了可以融合什么跳转。

如果第一条指令在一个缓存行的字节63处结束,并且第二条指令是在下一个缓存行的字节0处开始的条件跳转,宏融合不会发生。

因为这些对在许多类型的应用程序中是常见的,宏融合提升了性能,即使在非重编译的二进制文件上。

每个宏融合指令以单次分发执行。这减少了时延并释放执行资源。你也获得了提升的重命名与回收带宽,提升的虚拟储存,以及由于在更少比特中表示更多工作带来的能源节约。

2.3.2.2. 已解码ICache

已解码ICache本质上是遗留解码流水线的一个加速器。通过保存已解码的指令,已解码ICache使得以下特性成为可能:

·        减少分支误预测的时延。

·        提升到乱序引擎的微操作交付带宽。

·        减少前端的能耗。

已解码ICache缓存指令解码器的输出。在下次要执行微操作时,从已解码ICache获取已解码的微操作。这使得可以跳过这些微操作的提取与解码步骤,并减少前端的能耗与时延。已解码ICache提供了微操作高于80%的平均命中率;而且,“热点”通常具有接近100%的命中率。

通常整数程序平均每指令少于4个字节,前端能够跑到后端前面,填充调度器用来查找指令并行性的一个大窗口。不过,对于基本块包含许多指令的高性能代码,例如,IntelSSE多媒体算法或极度展开的循环,每周期16个指令字节偶尔会成为一个限制。已解码ICache32字节的定位有助于这样的代码避免这个限制。

已解码ICache自动地提升了具有空间与时间局部性程序的性能。不过,要完全开发已解码ICache的潜力,你可能需要理解它的内部组织。

已解码ICache包括32个集(Set)。每个集包含8路(Way)。每路可以支持最多6个微操作。已解码ICache理想状况下支持最多1536个微操作。

以下是如何向已解码ICache填充微操作的某些规则:

·        在一路中所有的微操作代表在代码中静态连续的指令,并且它们的EIP在同一个对齐的32字节区域内。

·        最多3路可以用于同一个32字节的对齐块,允许原始IA程序每32字节区域总共缓存18个微操作。

·        一条多微操作的指令不能被分割到多路。

·        每路最多允许两个分支。

·        打开MSROM的指令消耗一整路。

·        非条件跳转分支是一路中最后的微操作。

·        宏融合的微操作(load+op与store)被保存为一个微操作。

·        一对宏融合指令被保存为一个微操作。

·        带有64比特立即数的指令要求两个槽(slot)来保存立即数。

当因为这些限制,微操作不能被保存在已解码ICache时,从遗留解码流水线交付它们。一旦从遗留解码流水线交付微操作,仅在下一个分支微操作后,重新开始从已解码ICache获取微操作。频繁切换,会导致性能损失。

已解码ICache事实上被包含在指令缓存与ITLB中。也就是说,任何微操作在已解码ICache中的指令,其最初的指令字节出现在指令缓存里。指令缓存回收也必须包括回收已解码ICache,这仅回收必要的行。

存在需要冲刷整个已解码ICache的情形。一个原因可以是一个ITLB项的回收。其他原因对应用程序程序员通常不可见,因为它们发生在重要的控制被改变时,比如,CR3中的映射,或者在CR0与CR4中启用的特性与模式。还有已解码ICache被禁止的情形,例如,当CS基地址没有被设为0。

2.3.2.3. 分支预测

分支预测预测分支目标,并得处理器早在分支真实执行路径已知之前开始执行指令。所有分支使用分支预测单元(BPU)来预测。这个单元不仅基于分支的EIP,还基于执行通过哪条执行路径到达这个EIP,预测目标地址。BPU可以高效地预测以下分支类型:

·        条件分支。

·        直接调用或跳转。

·        间接调用或跳转。

·        返回。

2.3.2.4. 微操作队列与循环流检测器(LSD)

微操作队列解耦了前端与乱序执行引擎。它位于微操作生成与重命名器之间,如图2-5所示。这个微操作队列有助于隐藏在前端微操作各种来源之间引入的空泡,确保每周期交付4个微操作用于执行。

微操作队列对某些指令类型提供了解码后功能。特别的,与条件操作结合的读与所有的写,在使用索引取址时,在解码器或已解码ICache里被表示为单个微操作。在微操作队列中,通过与称为unlamination的过程,它们被分解为两个微操作,一个执行读,另一个执行操作。一个典型的例子是下面的“读加上操作(loadplus operation)”指令:

ADD RAX, [RBP+RSI]; rax := rax + LD( RBP+RSI )

类似地,下面的写指令有三个寄存器源操作数,被分解为“生成写地址”与“生成写数据”子部分

MOV [ESP+ECX*4+12345678], AL

由unlamination生成的额外微操作使用重命名与回收带宽。不过,它具有总体上能源的好处。对于由索引取址控制的代码(正如通常在数组处理中发生的),使用base(或base+displacement)的重新编码算法有时,可以通过保持读加上操作(loadplus operation)与写指令混编,提高性能。

循环流检测器(LSD)

循环流检测器(Loop Stream Detector)在Intel®Core微架构中引入。LSD检测能放入微操作队列的小循环并锁定它们。循环流来自微操作队列,没有来自任何缓存对微操作更多的获取、解码或读,直到一个分支误预测不可避免地结束它。

带有以下属性的循环适合LSD/微操作队列重放(replay):

·        最多获取8块32指令字节。

·        最多28个微操作(~28条指令)。

·        所有的微操作也位于已解码ICache中。

·        可以包含不多于8个已采用的分支,并且它们都不能是CALL或RET。

·        不能具有不匹配的栈操作。例如,比POP指令更多的PUSH。

许多计算密集循环,查找或软件字符串移动符合这些特征。机会主义地使用循环缓存功能。对于高性能代码,循环展开性能上通常更可取,即使在它超出了LSD的能力时。

2.3.3.乱序引擎

乱序引擎(Out-of-Order engine)以优异的功率特性提供了超出前代的性能。它检测依赖链,以乱序将它们送到执行,同时维持正确的数据流。在一个依赖链等待资源时,比如一个第二级数据缓存行,它从另一个链发送微操作到执行核。这增加了每周期总体的指令执行速率(IPC)。

乱序引擎包括两块,如图2-5所示:核心功能图表(CoreFunctional Diagram),重命名/回收块,以及调度器。

乱序引擎包含以下的主要模块:

重命名器。重命名器模块将微操作从前端移到执行核。它消除了微操作间的假依赖性,因此使得微操作的乱序执行成为可能。

调度器。调度器模块排列微操作直到所有的源操作数就绪。向可用资源单元调度及分发就绪微操作尽可能接近先进先出(FIFO)的次序。

回收。回收模块按顺序回收指令与微操作,并处理失败与异常。

2.3.3.1. 重命名器

重命名器是图2-5中顺序部分与调度器数据流方面的桥梁。每周期它将最多4个微操作从微操作队列移动到乱序引擎。尽管重命名器每周期可以发送最多4个微操作(未融合,微融合,宏融合),这等同于发布端口可以每周期分发6个微操作。在这个过程中,乱序核执行以下步骤:

·        将微操作架构上的源与目标重命名为微架构上的源与目标。

·        为微操作分配资源。例如,读或写缓冲。

·        将微操作绑定到合适的分发端口。

在重命名期间某些微操作可以执行完成,并从流水线删除,实际上不占用执行带宽。这包括:

·        零习语(Zero idiom)(依赖性破坏习语)。

·        NOP。

·        VZEROUPPER。

·        FXCHG。

相比前代每周期一个分支,重命名器每周期可以分配两个分支。这可以消除执行中的某些空泡。

使用一个索引寄存器的微融合读与写操作被分解为两个微操作,因此消耗重命名器每周期可以使用的4个工位中的2个。

依赖性破除习语(Dependencybreaking idioms)

通过使用常见的指令来将寄存器内容清除为0,可以提升指令的并行性。重命名器可以无需对目标寄存器求值来检测它们。

在可能时使用以下依赖性破除习语来清除一个寄存器:

·        XOR REG,REG

·        SUB REG,REG

·        PXOR/VPXOR XMMREG,XMMREG

·        PSUBB/W/D/Q XMMREG,XMMREG

·        VPSUBB/W/D/Q XMMREG,XMMREG

·        XORPS/PD XMMREG,XMMREG

·        VXORPS/PD YMMREG, YMMREG

因为零习语由重命名器检测、删除,因此它们没有执行时延。

存在另一个依赖性破除习语——“一习语(oneidiom)”。

·        CMPEQ XMM1, XMM1; “一习语”将所有元素设置为全“1”

在这个情形里,必须执行微操作,不过因为已知不管输入数据是什么,输出数据总是“全1”,就像零习语那样,其源操作数上的微操作依赖性不存在,因此只有找到一个空闲的执行端口,它就可以执行。

2.3.3.2. 调度器

调度器控制微操作在它们的执行端口上的分发。为了做到这,它必须识别哪个微操作就绪,其源操作数来自何方:一个寄存器文件项,或直接来自一个执行调用的一个旁路。依赖于分发端口与回写总线的可用性,以及就绪微操作的优先级,调度器每周期选择要分发的微操作。

2.3.4.执行核

执行核是超标量的,可以乱序处理指令。通过高效地处理最常见的操作,同时最小化可能的延2,执行核优化了总体性能。

乱序执行核以以下方式在前代基础上改进了执行单元的组织:

·        减少读端口的暂停。

·        减少回写的冲突与时延。

·        减少功耗。

·        减少辅助处理非规范输入与下溢的输出的SIMD FD。

某些高精度FP算法需要处理FTZ= 0与DAZ= 0,即允许下溢的中间结果以及非规范输入,归咎于SIMDFD辅助,以在前代微架构上降低性能为代价,实现更高的数值精度。在Intel微架构SandyBridge中SIMDFD辅助的降低适用于以下SSE指令(以及AVX变种):ADDPD/ADDPS,MULPD/MULPS,DIVPD/DIVPS以及CVTPD2PS。

乱序核包含3个队执行栈,其中每个栈封装了某个数据类型。执行核包含以下执行栈:

·        通用寄存器。

·        SIMD整数与浮点。

·        X87。

执行核还包含至自缓存层次结构的连接。读入的数据从缓存获取,并回写到其中一个栈。

调度器可以每周期分发最多6个微操作,每个端口一个。下表总结了哪个端口分发哪些操作。

表2-14. 分发端口与执行栈

 

端口0

端口1

端口2

端口3

端口4

端口5

整数

ALU, Shift

ALU, Fast LEA,

Slow LEA, MUL

Load_Addr,

Store_Addr

Load_Addr,

Store_Addr

Store_data

ALU, Shift,

Branch,

Fast LEA

SSE-Int,

AVX-Int,

MMX

Mul, Shift, STTNI,

Int-Div, 128b-Mov

ALU, Shuf, Blend,

128b-Mov

 

 

Store_data

ALU, Shuf, Shift, Blend, 128b-Mov

SSE-FP,

AVX-FP_low

Mul, Div, Blend, 256b-Mob

Add, CVT

 

 

Store_data

Shuf, Blend, 256b-Mov

X87,

AVX-FP_High

Mul, Div, Blend, 256b-Mob

Add, CVT

 

 

Store_data

Shuf, Blend, 256b-Mov

在执行之后,数据被回写到对应分发端口与结果数据类型的一个回写总线上。在同一个端口上分发但具有不同时延的微操作可能在这个周期里需要回写总线。在这些情形里,其中一个微操作被推迟,直到回写总线可用。例如,MULPS(5个周期)与BLENDPS(1个周期)可能冲突,如果两者都在端口0就绪:第1个周期是MUPLS,4个周期后是BLENDPS。Intel微架构SandyBridge消除了这样的冲突,只要微操作将结果写到不同的栈。例如,整数ADD(1个周期)可用在MULPS(5个周期)4个周期后发布,因为整数ADD使用整数栈,而MULPS使用FP栈。

当在一个栈上执行的微操作的一个源操作数在来自在另一个栈上执行的微操作,会发生1到2周期的时延。IntelSSE整数与IntelSSE浮点操作之间的转换也会发生时延。在某些情形里,使用添加到指令流的一个微操作完成数据转换。下表描述了执行后回写的数据,如何旁路到在后续周期中执行的微操作。

表2-15. 执行核回写时延(周期)

 

整数

SSE-Int, AVX-Int, MMX

SSE-FP,

AVX-FP_low

X87, AVX_FP_High

整数

0

微操作(端口0)

微操作(端口0)

微操作(端口0)+ 1周期

SSE-Int, AVX-Int, MMX

微操作(端口5)或微操作(端口5)+ 1周期

0

1周期

0

SSE-FP,

AVX-FP_low

微操作(端口5)或微操作(端口5)+ 1周期

1周期

0

微操作(端口5)+ 1 周期

X87, AVX_FP_High

微操作(端口5)+ 1 周期

0

微操作(端口5)+ 1 周期

0

0

1周期

1周期

2周期

2.3.5.缓存层次结构

在每个核,缓存层次结构包含1个第一级指令缓存,1个第一级数据缓存(L1DCache)以及1个第二级(L2)缓存。L1D缓存可能由两个逻辑处理器共享,如果处理器支持Intel超线程技术。L2缓存由指令与数据共享。一个物理处理器封装里所有的核通过一个环线路连接到一个共享的最后一级缓存(LLC)。

缓存使用指令转换旁视缓冲(Instruction TranslationLookaside Buffer,ITLB),数据转换旁视缓冲(Data Translation Lookaside Buffer,DTLB)以及共享转换旁视缓冲(SharedTranslation Lookaside Buffer, STLB))来将线性地址转换为物理地址。所有缓存层级中数据一致性使用MESI协议来维护。更多信息,参考《Intel®64 IA-32 Architectures Software Developer's Manual, Volume 3》。缓存层级细节可以在运行时通过CUPID指令来获得。参考《Intel®64 and IA-32 Architectures Software Developer’s Manual, Volume 2A》。

表2-16. 缓存参数

层级

容量

关联性(路)

行大小(字节)

更新策略

包括在内

L1数据

32KB

8

64

回写

-

指令

32KB

8

N/A

N/A

-

L2(整体式)

256KB

8

64

回写

No

第三级(LLC)

可变,查询CPUID leaf 4

随缓存大小而变

64

回写

Yes

2.3.5.1. 读与写操作的概览

本节提供了读写操作的一个概览。

读(Load)

当一条指令从一个具有回写(write-back,WB)类型的内存位置读数据时,处理器在缓存与内存中查找它。表2-17显示了访问查找序以及最小的时延。实际时延依赖于缓存队列,LLC环的占据情况,内存组件以及它们的参数而变。

表2-17. 查找次序与读时延

层级

时延(周期)

带宽(每核每周期)

L1数据

4[1]

2 x 16字节

L2(整体式)

12

1 x 32字节

第三级(LLC)

26~31[2]

1 x 32字节

如果适用在其他核中的L2与L1 Dcache

43 – 干净命中;

60 – 肮脏命中

 

LLC包含了其上的所有缓存层次——包含在核缓存中的数据也存在于LLC里。LLC中每个缓存行保存在L2与L1缓存中可能有这行的核的一个指示。如果在LLC中有一个其他核可能持有感兴趣行,并且其状态可能已经改变的指示,也有对这些核的L1Dcache与L2缓存的一个查找。该查找被称为“干净的”,如果它不要求从其他核缓存获取数据。该查找被称为“脏的”,如果从其他核缓存获取改变了的数据,并传递到读入核。

上面显示的时延是最好的情形。有时必须逐出一个已改变的缓存行以为新的缓存行腾出空间。逐出已改变缓存行与引入新数据并行,不要求额外的时延。不过,当数据被回写入内存时,逐出使用缓存带宽,还可能使用内存带宽。因此,当短时间内多个缓存不命中要求逐出多个已改变行时,存在一个总体下降的缓存响应时间。内存时延基于内存控制器队列的占用,DRAM配置,DDR参数,以及DDR页行为(如果要求的页是一个命中页,不命中页,或空页)而改变。

写(Store)

当一条指令将数据写入一个具有回写内存类型的内存位置时,处理器首先确认在L1DCache中有包含这个内存位置,在Exculsive或ModifiedMESI状态的行。如果没有这个在正确状态中的缓存行,处理器使用一个Request或Ownership请求,从下一级内存层级获取它。处理器在以下位置,以指定的次序查找这个缓存行:

1.      L1 DCache

2.      L2

3.      最后一级缓存

4.      其他核中的L2与L1Dcache,如果适用

5.      内存

一旦缓存行在L1 DCache中,向它写入新数据,该行被标记为已修改(Modified)。

为所有权进行读与数据写入发生在指令回收之后,遵循写指令回收的次序。因此,写时延通常不会影响写指令本身。不过,几个不命中L1DCache的连续写会累积可以影响性能的时延。只要写没有完成,在写缓冲中其项保持被占用。当写缓冲被占满时,新的微操作不能进入执行流水线,执行可能会暂停。

2.3.5.2. L1 DCache

L1 DCache是第一级数据缓存。通过内部数据结构,它管理所有类型的所有读写请求。L1DCache:

·        使得能推测性地与乱序地发出读写。

·        确保在回收时被回收的读写有正确的数据。

·        确保读写遵循IA-32与Intel64指令集架构的内存次序规则。

表2-18. L1DCache组件

组件

Intel微架构Sandy Bridge

Intel微架构Nehalem

数据缓存单元(DCU)

32KB,8路

32KB,8路

读缓冲

64项

48项

写缓冲

36项

32项

行填充缓冲(LFB)

10项

10项

DCU被组织为32KB,8路组相联映射。缓存行大小是安排为8组的64字节。

在内部,访问最多到16字节,256比特IntelAVX指令使用两个16字节访问。每周期可以处理两个读操作与一个写操作。

L1 DCache维护不能被立即处理完成的请求。请求被延迟的某些原因:缓存不命中,跨缓存行分解的非对齐访问,数据未准备好从前一个写转发,经历组冲突的写,以及缓存行替换的读块。

从分配到回收,L1 DCache可以维护最多64个读微操作。从分配到写入值被提交到缓存,或在临时(temporal)写的情形下写入到行填充缓冲(LFB),它可以维护最多36个写操作。

L1 DCache可以处理多个未完成的缓存不命中,并继续处理进入的写与读。使用LFB最多可以同时应付10个不命中缓存行的请求。

L1 DCache是回写写分配缓存。命中DCU的写不会更新更低级的内存。不命中DCU的写分配一个缓存行。

读(Load)

L1 DCache架构可以每周期处理两个读,每个最多可以是16字节。在不同阶段最多可维持32个读,从乱序引擎分配它们,到读入数据被返回到执行核。

读可以:

·        在已知读地址与写地址访问不冲突时,在前面的写之前读数据。

·        可以推测性地开展,在前面分支被解析出来之前。

·        以乱序及一个重叠的方式接受缓存不命中。

读不可以:

·        推测性地接受任何类型的失败或陷入。

·        推测性地访问不可缓存内存。

通常读时延是5个周期。当使用一个简单的访问模式,基地址加上小于2048的偏移时,读时延可以是4个周期。这个技术对于消除指针的代码特别有用。不过,因为栈旁路,总体时延依赖于目标寄存器数据类型而不同。更多细节参考2.3.4节。

下表列出了总体读时延。这些时延假定常见的平坦段情形,即段基地址是0。如果段基址不是0,读时延增加。

表2-19. 取址模式对读时延的影响

数据类型/取址模式

Base + Offset > 2048;

Base + Index [+Offset]

Base + Offset < 2048

整数

5

4

MMX, SSE, 128比特AVX

6

5

X87

7

6

256比特AVX

7

7

写(Store)

写入内存以两个阶段完成:

·        执行阶段。以线性与为例地址及数据填充写缓冲。一旦写地址与数据已知,写数据可以被转发到后续需要它的读操作。

·        完成阶段。在写回收后,L1 DCache将它的数据从写缓冲移到DCU,每周期最多16个字节。

地址翻译

DTLB可以在每周期执行3个线性到物理地址的翻译,两个读地址,一个写地址。如果这个地址不在DTLB中,处理器在支持数据与指令地址翻译的STLB中查找它。一个DTLB不命中,但命中STLB的代价是7周期。大页面支持包括1G字节页面,除了4K与2M/4M页面。

DTLB与STLB是4路组相联映射。下表说明了DTLB与STLB中的项数。

表2-20. DTLB与STLB参数

TLB

页大小

DTLB

4KB

64

 

2MB/4MB

32

 

1GB

4

STLB

4KB

512

写转发

如果一个读跟在一个写之后并重新读入写操作写入内存的数据,这个数据可以从写操作直接旁路到这个读。这个过程,称为写到读转发,通过使读直接从写操作获得数据,而不是通过内存,节省了周期。你可以利用写转发来快速移动复杂的结构,无需以失去转发子域的能力为代价。相比以前的微架构,内存控制单元可以更少的限制处理写转发情形。

要启用写到读转发,必须满足以下规则:

·        这个写必须是在这个读之前最后写入该地址的。

·        写必须包含所有要读入的数据。

·        读来自一个回写内存类型,读与写都必须是临时(temporal)的访问。

在下列情形中写不能转发给读:

·        跨过8字节边界的4字节以及8字节读,相对于之前的16或32字节写。

·        任何跨过一个32字节写的一个16字节边界的读。

表2-21到表2-24给出了写到读转发行为的细节。对于一个给定的写尺寸,所有可以重叠的读由’F’指出。从32字节写转发类似于从该写的每个16字节部分转发。不能转发的情形显示为’N’。

表2-21. 写转发条件(1及2字节写)

 

 

读对齐量

写尺寸

读尺寸

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

1

1

F

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2

1

F

F

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2

F

N

 

 

 

 

 

 

 

 

 

 

 

 

 

 

表2-22. 写转发条件(4-16字节写)

 

 

读对齐量

写尺寸

读尺寸

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

4

1

F

F

F

F

 

 

 

 

 

 

 

 

 

 

 

 

2

F

F

F

N

 

 

 

 

 

 

 

 

 

 

 

 

4

F

N

N

N

 

 

 

 

 

 

 

 

 

 

 

 

8

1

F

F

F

F

F

F

F

F

 

 

 

 

 

 

 

 

2

F

F

F

F

F

F

F

N

 

 

 

 

 

 

 

 

4

F

F

F

F

F

N

N

N

 

 

 

 

 

 

 

 

8

F

N

N

N

N

N

N

N

 

 

 

 

 

 

 

 

16

1

F

F

F

F

F

F

F

F

F

F

F

F

F

F

F

F

2

F

F

F

F

F

F

F

F

F

F

F

F

F

F

F

F

4

F

F

F

F

F

N

N

N

F

F

F

F

F

N

N

N

8

F

N

N

N

N

N

N

N

F

N

N

N

N

N

N

N

16

F

N

N

N

N

N

N

N

N

N

N

N

N

N

N

N

表2-23. 32字节写转发条件(10-15字节对齐量)

 

 

读对齐量

写尺寸

读尺寸

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

32

1

F

F

F

F

F

F

F

F

F

F

F

F

F

F

F

F

2

F

F

F

F

F

F

F

F

F

F

F

F

F

F

F

N

4

F

F

F

F

F

N

N

N

F

F

F

F

F

N

N

N

8

F

N

N

N

N

N

N

N

F

N

N

N

N

N

N

N

16

F

N

N

N

N

N

N

N

N

N

N

N

N

N

N

N

32

F

N

N

N

N

N

N

N

N

N

N

N

N

N

N

N

表2-24. 32字节转发条件(16-31字节对齐量)

 

 

读对齐量

写尺寸

读尺寸

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

1

F

F

F

F

F

F

F

F

F

F

F

F

F

F

F

F

2

F

F

F

F

F

F

F

F

F

F

F

F

F

F

F

N

4

F

F

F

F

F

N

N

N

F

F

F

F

F

N

N

N

8

F

N

N

N

N

N

N

N

F

N

N

N

N

N

N

N

16

F

N

N

N

N

N

N

N

N

N

N

N

N

N

N

N

32

N

N

N

N

N

N

N

N

N

N

N

N

N

N

N

N

内存歧义消除

一个读操作可能依赖于之前的一个写。许多微架构阻塞读直到所有前面的写地址已知。内存歧义消除器预测哪些读将不依赖任何之前的写。当歧义消除器预测到一个读没有这样的一个依赖性,这个读从L1数据缓存获取其数据,即使写地址还未知。这隐藏了读时延。最终,这个预测被验证。如果检测到了冲突,这个读与所有后续的指令被重新执行。

以下读不能消除歧义。这些读的执行被暂停,直到所有前面的写地址已知。

·        跨越16字节边界的读。

·        没有32字节对齐的32字节IntelAVX读。

内存歧义消除器总是假定具有相同0:11地址比特的读与之前的写存在依赖性。

Bank冲突

因为16字节读最多可以覆盖3个bank,每周期可以进行2个读,因此每周期可以访问8个bank中的6个。当两个读需要在同一时间访问不同组中相同的bank时(它们的地址具有相同的2-4比特值),发生一个bank冲突。当发生一个bank冲突时,其中一个读访问在内部被再循环。

在许多情形里,两个读访问相同缓存行中的同一个bank,就像在栈上弹出操作数时可能发生的,或任何顺序访问那样。在这些情形里,冲突不会发生,读被同时处理。

2.3.5.3. 环互联与最后一级缓存

片上系统设计提供了一个高带宽双向的环总线来连接非计算核心(uncore)中的IA核与各子系统。在第二代IntelCore处理器2xxx系列中,非计算核心子系统包括一个系统代理,图形单元(GT)与最后一级缓存(LLC)。

LLC包括多个缓存分片。分片的数目等于IA核的数量。每个分片具有逻辑部分与数据数组部分。逻辑部分处理数据一致性,内存次序,对数据数组部分的访问,LLC不命中与内存回写,等等。数据数组部分写缓冲行。每个分片包含一个可以支持32字节/周期的完全缓存端口。

保存在LLC数据数组中数据的物理地址,通过一个哈希函数在缓存分片中分配,使得地址均匀分布。在一个缓存块中的数据数组可能具有对应0.5M/1M/1.5M/2M块大小的4/8/12/16路。不过,因为从软件角度来看缓存块中地址分布,这表现得不像一个普通的N-路缓存。

从处理器核与GT的角度,LLC充当一个带有多个端口的共享缓存,并且带宽与核的数量成正比。LLC命中时延,范围在26~ 31周期,依赖于核相对于LLC块的位置,以及请求需要在环上行进多远。

缓存分片的数量随着核的数目增加,因此环与LLC不太可能是核心操作的带宽瓶颈。

GT位于同一个环互联上,也使用LLC进行数据操作。在这方面,它非常类似于一个IA核。因此,使用缓存带宽并且显著占用缓存的高带宽图形应用,在某种程度上,会干扰核心操作。

所有不能被LLC满足的流量,比如LLC不命中,脏的行回写,不可缓存的操作,以及MMIO/IO操作,仍然通过缓存分片逻辑部分与环行进到系统代理。

在Intel Xeon处理器E5家族中,非计算核心子系统不包括图形单元(GT)。相反,非计算核心子系统包含更多的组件,包括一个支持多处理器有更大容量以及窥视能力的LLC,可以支持多插槽平台的Intel®QuickPath Interconnect接口,电源管理控制硬件,以及一个能够支持来自内存及I/O设备的高带宽通讯的系统代理。

在Intel Xeon处理器E52xxx或4xxx家族中,LLC容量通常以每核2.5M字节与处理器数量成正比。

2.3.5.4. 数据预取

使用软件预取,硬件预取,或两者的任意组合,数据可以被推测性地读入L1DCache。

你可以使用四个流媒体SIMD扩展(SSE)预取指令来启用软件控制的预取。这些指令是将数据的一个缓存行放入期望层级缓存的一个暗示。软件控制预取目的在于预取数据,不能预取代码。

本节的余下部分描述由Intel微架构SandyBridge提供的各种硬件预取机制,以及对之前处理器的改进。预取器的目标是自动地预测程序将要消耗哪些数据。如果这个数据不在执行核或内部缓存附近,预取器从下面几级缓存或内存把它取来。预取具有以下效果:

·        如果数据在程序中以使用的次序被顺序安排,这会提高性能。

·        如果访问模式是稀疏而不是局部的,可能会因为带宽的问题造成性能轻微下降。

·        偶尔,如果算法的工作集被证明占据大多数缓冲,并且不需要的预取逐出了程序所要求的缓存行,由于L1的缓存容量,硬件预取器可能导致严重的性能下降。

预取数据到L1DCache缓存

在下列条件被满足时,数据预取由读操作触发:

·        从回写内存类型读入。

·        预取数据与触发它的读指令在同一个4K字节页面内。

·        在流水线中没有正在进行的栅栏(fence)。

·        没有太多的其他读不命中正在进行。

·        没有连续的写操作流。

两个硬件预取器将连续数据读入L1 DCache:

·        数据缓存单元(DCU)预取器。这个预取器,也被称为流媒体预取器,由对最近读入数据的一个上升访问触发。处理器假定这个访问是一个流媒体算法的部分,并自动获取下一行。

·        基于指令指针(IP)的跨步预取器。这个预取器记录每个读指令。如果一条读指令被检测到具有一个有规律的跨步,那么一个预取被发送到当前地址加上跨步的下一个地址。这个预取器可以向前、向后预取,并可以检测到最多2K字节的跨步。     

预取数据到L2与最后一级缓存

以下两个硬件预取器从内存预取数据到L2缓存以及最后一级缓存:

空间预取器:这个预取器努力,以配对行,将提取到L2缓存的每个缓存行完成为一个128字节对齐的块。

Streamer:这个预取器监视来自L1缓存,用于地址的上升及下降序列的读请求。被监控的读请求包括由读写操作以及硬件预取器初始化的L1DCache请求,用于代码提取的L1ICache请求。当检测到请求的一个前向或后向流时,期望的缓存行被预取。被预取的缓存行必须在同一个4K页面内。

Streamer与空间预取器将数据预取到最后一级缓存。通常数据也被放入L2,除非L2缓存为不命中的请求所重载。

对streamer的改进包括以下特性:

·        Steamer在每次L2查找中可以发出两个预取请求。Streamer可以在读请求前积累20个缓存行。

·        根据每个核未解决的请求数动态调整。如果没有太多未解决的请求,Streamer进一步向前预取。如果未解决的请求有许多,它仅对LLC预取,并降低领先程度。

·        当缓存行已遥遥领先,它仅预取到最后一级缓存,而不是L2。这个方法避免了在L2缓存中对有用缓存行的替换。

·        检测并维护最多32个数据访问流。对于每个4K字节页面,你可以维护一个前向与一个后向流。

2.3.6.系统代理(system agent)

实现在第二代Intel Core处理器家族的系统代理包含以下组件:

·        一个处理所有来自环域及来自I/O(PCIe*与DMI)的访问,并将这些访问路由到正确地方的仲裁器。

·        PCIe控制器连接到外部PCIe设备。PCIe控制器具有不同的配置可能性,随着产品部分细节而变化:x16+x4,x8+x8+x4,x8+x4+x4+x4。

·        DMI控制器连接到PCH芯片集。

·        用于内部图形操作的集成显示引擎,灵活的显示互联,以及显示端口。

·        内存控制器。

所有的主内存流量从仲裁器路由到内存控制器。在第二代Intel Core处理器2xxx系列中的内存控制器支持双通道DDR,依赖于单元类型,系统配置与DRAMS,数据速率为1066MHz,1333MHz以及1600MHz,每周期8字节。在一个尝试平衡通道间负载,以实现最大带宽与最小热点冲突的局部哈希函数的基础上,地址在内存通道间分配。

为了得到最好性能,通道配以相同数量的内存,最好是相同类型的DIMM。另外,对相同数量的内存使用更多的列(rank)导致稍微更好的内存带宽,因为可以同时打开更多的DRAM页。为了得到最好性能,为系统配置最高速的DRAM(数据速率1333MHz或1600MHz,依赖于最大支持的频率),最好的DRAM时序。

双通道具有单独的资源并独立地处理内存请求。内存控制器包含一个尝试最大化内存带宽,同时最小化时延的高性能乱序调度器。每个内存通道包含一个32缓存行写数据缓冲。向内存控制器写入被视为完成,当它们被写入到写数据缓冲时。在稍后的时间,写数据缓冲被刷入主内存,不影响写时延。

在内存控制器时部分写(partial write)不能高效地处理,如果部分写不能及时完成一个完整的缓存行,可能会导致DDR通道上的读-修改-写操作(read-modify-write)。只要可能,软件应该避免产生部分写事务,并考虑替代方案,比如把部分写缓冲为完整的缓存行写。

内存控制器也支持高优先级等时(isochronal)请求(比如USB等时以及显示等时请求)。来自集成显示引擎的内存请求的高带宽占据了部分内存带宽,并在某种程度上影响内核的访问时延。

2.3.7.Intel® 微架构Ivy Bridge

第三代Intel Core处理器基于Intel微架构IvyBridge。在2.3.1-2.3.6节描述的特性也适用于微架构IvyBridge。本节涵盖了会影响编程与性能的微架构间的特性差异。

对启用新指令的支持包括:

·        至及自半精度浮点值的数值转换。

·        基于硬件的,符合NIST SP 800-90A随机数生成器。

·        读写在任意环中的FS/GS基地址寄存器,以改进对用户模式线程的支持。

关于基于硬件的随机数生成器指令RDRAND的细节,请参考在IntelSoftware Network的文章,http://software.intel.com/en-us/articles/download-the-latest-bull-mountain-software-implementation-guide/?wapkw=bull+mountain。

少数对软件带来好处的微架构改进:

·        硬件预取改进:在Intel微架构IvyBridge中加入了一个下一页(next-page)预取器(NPP)。NPP由对向上或向下靠近页边界的缓存行的连续访问触发。

·        零时延寄存器移动操作:一个寄存器到寄存器MOV指令的子集在前端执行,保护乱序引擎中的调度与执行资源。

·        前端改进:在Intel微架构SandyBridge,微操作队列被静态地划分,向每个逻辑处理器提供28项,不管软件在单个线程还是在多个线程中执行。在Intel微架构IvyBridge里,如果一个逻辑处理器是不活动的,那么在处理器核上执行的单个线程可以使用微操作队列的56项。在这个情形里,LSD可以处理更大的要求多于28项的循环结构。

·        某些指令的时延与吞吐率在Intel微架构SandyBridge的基础上得到改进。例如,256比特浮点除法与平方根操作更快了;ROL与ROR指令也得到了改进。



[1] 受制于表2-15中显示的执行核旁路限制。

[2] L3的时延随着产品线与sku(productsegment and sku)。这个值适用于第二代Intel Core处理器家族。