可以自学做网站吗,网上推广平台有哪些,网站请及时续费,域名网安备案18. AMD Bulldozer#xff0c;Piledriver与Steamroller流水线
18.1. AMD Bulldozer#xff0c;Piledriver与Steamroller中的流水线
AMD Bulldozer#xff0c;Piledriver与Steamroller处理器可以有1到8个计算单元#xff0c;每个单元两个执行核。每个单元可以运行两个线程…18. AMD BulldozerPiledriver与Steamroller流水线
18.1. AMD BulldozerPiledriver与Steamroller中的流水线
AMD BulldozerPiledriver与Steamroller处理器可以有1到8个计算单元每个单元两个执行核。每个单元可以运行两个线程或每核一个线程。
指令缓存与获取由一个执行单元中的两个核共享。在Bulldozer与Piledriver中指令解码器也在两个核间共享而Steamroller每个核一个解码器。
对每个核整数执行单元与1级数据缓存是独立的。浮点与向量执行单元以及2级缓存也在一个执行单元的两个核间共享。一个可能的3级缓存在所有计算单元间共享。某些版本有一个集成图形处理单元。
每个核包含4条并行流水线每时钟周期可以执行最多4条指令。在流水线中指令被尽可能少、尽可能早地分解。在解码阶段一条读-修改或读-修改-写指令仅产生一个宏操作。流水线的长度未知。
相比之前的设计这个设计更关注节能。通过在大多数时间里降低时钟频率它相当进取地节省电能。某些版本在时钟频率降低时还降低电压。仅在一长串CPU密集代码后才能获得最大时钟频率。
18.2. 指令获取
指令获取器在一个执行单元的两个核间共享。指令获取器每时钟周期可以从1级代码缓存获取32个对齐字节的代码。测得获取速度是在两个核都活动时每时钟周期最多16字节在仅一个核活动时在线性代码中每时钟周期最多21字节。当指令没有对齐时获取速度低于这些最大速度。
关键例程入口与循环入口不应该在一个32字节块末尾附近开始。可以将关键项对齐到16字节或至少确保在一个关键标签后前4条指令中没有16字节边界。
18.3. 指令解码
在代码缓存中标记了指令边界。每个解码器每时钟周期可以处理4条指令Bulldozer与Piledriver在每个单元中有一个由两个核共享的解码器。在两个核都活动时每个核每2个时钟周期得到解码器服务。属于不同核的指令不能在同一时钟周期里解码。仅在每个执行单元运行一个线程时解码速度是每时钟周期4条指令。
Steamroller每个核有一个解码器这样每时钟周期它可以解码4条指令即使在每个单元里运行两个线程时。因此在Steamroller上瓶颈很可能是指令获取而不是解码。
产生两个宏操作的指令称为双指令。Piledriver与Steamroller中的解码器在一个时钟周期里可以处理4条单指令1-1-1-1或者1条双指令与2条单指令2-1-1或者2条双指令2-2。Bulldozer可以处理1-1-1-1页2-1-1但2-2不行。
产生超过2个宏操作的指令使用微代码。在生成微代码时解码器不能做别的事情。这意味着在遇到一条产生超过2个宏操作的指令后解码器会停止解码几个时钟周期。在Steamroller上这将仅影响有复杂指令的线程但在Bulldozer与Piledriver上将拖延一个单元中的两个线程因为它们共享同一个解码器。每条指令产生的宏操作数列出在手册4“指令表”里。
带有最多3个前缀的指令可以在一个时钟周期里解码。对有超过3个前缀的指令有非常大的惩罚。4 ~ 7前缀的指令需要额外14 ~ 15时钟周期来解码。8 ~ 11前缀的指令需要额外20 ~ 22时钟周期12 ~ 14前缀的指令需要额外27 ~ 28时钟周期。因此不建议使NOP指令超过3个前缀。这个规则的前缀数包括操作数大小、地址大小、段、重复、锁、REX与XOP前缀。3字节VEX前缀算作1个而2字节VEX前缀不算入内。转义码0F0F380F3A不算入内。
18.4. 循环缓冲
Steamroller在解码器后有一个已解码宏操作队列。每个核一个队列。队列最多可以保存40个宏操作虽然有时略少。小循环可以绕过解码器从宏操作队列运行。这节省了能源消除了微小循环的指令获取瓶颈。在Steamroller上不超过4条指令的循环每迭代可以仅在1时钟周期里执行因为它绕过了解码器。
18.5. 指令融合
紧跟一个条件跳转的CMP或TEST指令可融合为单个宏操作。这适用于所有版本的CMP与TEST指令以及所有条件跳转除非CMP或TEST有一个rip相对取址或同时有位移与立即数。例如
; Example 18.1. Instruction fusion on Bulldozer
test eax,4
jnz L1 ; fused into one op
cmp [Mydata], eax ; rip-relative address in 64 bit mode
jb L2 ; not fused if rip-relative address
cmp dword ptr[rsi8], 2 ; both displacement and immediate operand
jl L3 ; not fused
cmp [Mydatarbx*4], eax ; 32-bit absolute address scaled index
jg L3 ; fused
dec ecx
jnz L4 ; not fused. Only cmp and test can fuse
AMD软件优化指引3.062012年1月在这里是不正确的
其他ALU指令不能与条件跳转融合。指令融合不能增加最大解码速率。
18.6. 栈引擎
处理器有一个重命名栈指针的高效栈引擎但我们不知道它在流水线的何处。
Pushpop及return指令仅使用一个宏操作。就栈指针而言这些指令有零时延因此依赖栈指针作为操作数或指针的后续指令不会被拖延。没有观察到在Intel处理器中看到的栈同步μop。
18.7. 乱序调度器
每个核有一个40项的乱序整数调度器及96个64位寄存器的物理寄存器文件。
共享的浮点单元有自己的60项乱序调度器以及160个128位寄存器的物理寄存器文件。
对Steamroller这些数字可能更大但得不到实际的细节。
18.8. 整数执行流水线
有4条整数执行流水线 整数流水线 用于 EX0 大多数AL操作除法 EX1 大多数ALU操作乘法跳转 AGLU0 内存读 AGLU1 内存读
表18.1. 整数执行单元
执行流水线EX0页EX1用于大多数整数与通用指令。内存读指令使用AGLU0与AGLU1。内存写指令同时使用AGLU0/1与EX0/1。AGLU0与1还可以处理使用32位与64位通用寄存器的简单寄存器到寄存器移动除了Bulldozer的早期版本。AGLU0与1不能处理使用8位或16位寄存器或立即数的寄存器移动指令。
在EX0与EX1中LEA指令作为ALU操作执行。简单LEA指令需要1时钟周期。如果涉及偏移或多个加法那么需要2时钟周期。如果操作数大小或地址大小是16位需要一个额外时钟周期。
最多32位的操作数的整数乘法需要4时钟周期吞吐率是每2时钟周期一个乘法。整数除法没有流水线化。
18.9. 浮点执行流水线
在Bulldozer与Piledriver上有4个浮点/向量执行流水线但在Steamroller仅有3个。 浮点流水线 用于 P0 浮点加法乘法除法整数向量乘法 P1 浮点加法乘法除法混排偏移封装 P2 整数向量加法布尔移动 P3 整数向量加法布尔移动保存
表18.2. Bulldozer与Piledriver浮点执行流水线 浮点流水线 用于 P0 浮点加法乘法除法布尔整数向量加法乘法 P1 浮点加法乘法除法混排偏移封装 P2 整数向量加法向量布尔保存
表18.3. Steamroller浮点执行流水线
所有这些单元可以处理128位操作数。256位操作数被分为2个宏操作。所有浮点加法与乘法需要5时钟周期如果下一条依赖的指令也是一个加法或乘法否则可能要6时钟周期。一个融合乘加指令也需要5或6时钟周期。在结果用在相同的单元上不知道执行单元如何节省1时钟周期。这可能由于更短的数据通路或者可能执行单元可以节省一个浮点值正规化、格式化或分类的流水线阶段。移动与比较操作与简单整数向量指令的时延是2时钟周期。
大多数执行单元是双倍的如表18.2与18.3所示因此吞吐率是每时钟周期是两个128位操作或一个256位操作。通常宏操作去往先空闲的单元。
储存单元不是双倍的256位写总数需要多个时钟周期。如果对齐Bulldozer有最多每3时钟周期1个256位写的吞吐率如果不对齐每10时钟周期1个。256位储存Piledriver特别糟根据我的测量吐率是每17时钟周期一个对齐256位写。Steamroller好得多如果对齐吞吐率是每2时钟周期一个256位写如果不对齐是4时钟周期。
对浮点加法Steamroller的吞吐率低于预期。在单线程应用中吞吐率仅是每时钟周期一个128位向量即使有两个128位执行单元用于浮点加法。在运行两个线程上同时使用这两个加法单元有时是可能的。
在同一个流水线上混用不同时延的指令很少会导致问题。
3DNow指令不再支持除了预取指令。
次正规操作数
在一个浮点操作的结果是次正规或下溢时Bulldozer与Piledriver有大约175额外时钟周期的惩罚除非激活了flush-to-zero模式。对溢出没有惩罚。Steamroller没有这些惩罚。
融合乘加
浮点单元可以进行类型为d a * b c的融合乘加FMA指令。Bulldozer支持FMA4指令其中4个操作数可以是不同的寄存器。Piledriver与Steamroller支持FMA3与FMA4。FMA3指令有3个操作数其中目标d必须使用与输入操作数ab或c之一相同的寄存器。对FMA3Piledriver仅有预期吞吐率的一半即每时钟周期一个128位向量但对FMA4是完全吞吐率即每时钟周期2个128位向量。对FMA3与FMA4Steamroller都有完全吞吐率。
18.10. AVX指令
对最常见的指令256位AVX指令的吞吐率一般是每时钟周期一个256位向量128位指令的吞吐率是每时钟周期2个128位向量。因此总体吞吐率大致相同不管使用128位还是256位指令。
在Bulldozer与Piledriver上使用256位指令有几个劣势
在Bulldozer上指令解码器每时钟周期不能处理两条双指令。在Bulldozer与Piledriver上256位写指令的吞吐率小于128位写指令吞吐率的一半。在Piledriver上这特别糟吞吐率是每17 ~ 20时钟周期一个256写。在Bulldozer与Piledriver上128位寄存器到寄存器移动有零时延而256位寄存器到寄存器移动有2时钟周期的时延加上使用不同域的2 ~ 3时钟周期的惩罚参考下面。幸亏在大多数情形下非破坏性3操作数指令可以避免寄存器到寄存器移动。
因此在瓶颈是执行单元吞吐率或指令解码时在Bulldozer与Piledriver上使用256位指令没有好处。256位写差劲的吞吐率使得在Piledriver上使用256位寄存器没有优势。在Steamroller上这些问题已经被解决了。
尽管由于模式切换参考第119页Intel处理器对混用256位AVX指令与非AVXXMM指令有重大的惩罚在这些AMD处理器上没有这样的惩罚以及明显的模式切换。
AVX指令集提供大多数整数与浮点XMM指令的3操作数版本。这有没有操作数寄存器被改写因此可以避免大多数寄存器到寄存器移动的好处。除了与旧处理器不兼容使用这些3操作数指令没有坏处。
18.11. 不同执行域之间的数据时延
来自一个执行单元的输出数据被用作另一个执行单元的输入时通常有一个时延。不同的执行单元可以被分为6个域domain在数据从一个域移动到另一个时有一个传输时延
int域。这包括在通用寄存器上的所有操作。ivec域。这包括所有整数向量操作以及浮点移动、封装、混排shuffle、混合blend与布尔操作。fma域。这包括所有浮点加、减与乘操作包括融合乘加指令。fp域。这包括其他浮点指令比如除法、平方根、取整等。读。这包括所有内存读指令。写。这包括内存写指令。
这些域之间测得的传输时延如下 自域 至域 int ivec fp fma 写 int 0 (10) n.a. n.a. (4) ivec (8) 0 1 1 (5) fp n.a. 1 0 0 1(5) fma n.a. 1 0 -1 1(5) 读 (4) (6) (6) (6) n.a.
表18.4. 数据传输时延时钟周期。括号里的数字包括在手册4“指令表”中列出的时延计数中。
注意许多浮点指令属于整数向量ivec域。例如不存在布尔指令的特殊浮点版本。PORORPS与ORPD指令都相同。例如
; Example 18.2a. Data transport delays on Bulldozer
movaps xmm0, [mem1] ; 6 clock
mulps xmm0, xmm1 ; 61 clock
xorps xmm0, xmm2 ; 21 clock
addps xmm0, xmm3 ; 61 clock
movaps [mem2], xmm0 ; 5 clock ; 28 clock total
这可以通过重排指令使域之间的传输数减少这里xorps指令用于改变符号使得这个重排被允许得到改进。
; Example 18.2b. Data transport delays on Bulldozer, improved
movaps xmm0, [mem1] ; 6 clock
xorps xmm0, xmm2 ; 21 clock
mulps xmm0, xmm1 ; 6-1 clock
addps xmm0, xmm3 ; 61 clock
movaps [mem2], xmm0 ; 5 clock ; 26 clock total
整数单元与浮点/向量单元间的传输时延在我的测量中比AMD的软件优化指引中说明的要高得多。不过我不能确定就像指引建议的通过一个内存立即数从一个通用寄存器移动数据到一个向量寄存器会更快。
在一个浮点计算的输出是一个不同精度浮点计算的输入时有大的惩罚例如一个双精度浮点加法的输出是一个单精度加法的输入。这几乎没有现实的重要性因为这样一个序列很可能就是一个编程错误但它说明处理器在XMM寄存器的128位以外保存关于浮点值的额外信息。这个影响没有在Intel处理器上看到。
18.12. 不使用执行单元的指令
无需将NOPFNOP与FWAIT指令发送到任何执行单元来解决它们。它们有每时钟周期4条指令的吞吐率。
128位寄存器到寄存器移动被实现为无需发送到任何执行单元的寄存器重命名。因此它们有零时延以及每时钟周期4条指令的吞吐率。在一个时钟周期里同一个寄存器甚至可以被移动/重命名4次。指令MOVDQAMOVDQUMOVAPSMOVUPSMOVAPD与MOVUPA在使用寄存器操作数时都是相同的。
256位寄存器到寄存器移动是不同的。YMM寄存器的低半部以与128位寄存器移动相同的方式重命名具有零时延但高半部由P2或P3流水线中的一个执行单元移动具有时延2。除了这个时延在浮点代码中可能有传输时延因为这个移动在整数向量域执行参考表18.4。例子
; Example 18.3a. YMM move with transport delays on Bulldozer
vaddps ymm0, ymm0, ymm1 ; 6 clock
vmovaps ymm2, ymm0 ; 22 clock
vmulps ymm2, ymm2, ymm3 ; 6 clock ; 16 clock total
这里可以通过利用非破坏性3操作数指令消除移动节省5个时钟周期
; Example 18.3b. YMM move eliminated
vaddps ymm0, ymm0, ymm1 ; 6-1 clock
vmulps ymm2, ymm0, ymm3 ; 6 clock ; 11 clock total
X87浮点指令FINSTPFDECSTP与FFREE也是通过重命名无需执行单元来解决的。重命名仅部分解决FXCH它有零时延但使用在P0或P1流水线中的一个执行单元。
其他所有寄存器移动使用执行单元包括通用寄存器移动。
18.13. 寄存器的局部访问
处理器总是将整数寄存器的不同部分保持在一起。例如AL与AH不被乱序执行不视为无关。因此写一个寄存器一部分的指令对之前该寄存器或寄存器任一部分的写将有一个假依赖。
一个32位寄存器的写指令没有对相应64位寄存器的假依赖因为该64位寄存器高半部置零。
写XMM寄存器一部分对整个寄存器有一个假依赖但这不适用于YMM寄存器的两个半部。256位YMM寄存器被处理为两个无关的128位XMM寄存器。不过这很少有实际后果因为指令VEXTRACTF128与VINSERTF128被定序器处理为仿佛它们读/写寄存器的这两个部分。
处理器将算术标记的部分处理为无关的。例如一条仅修改进位标记的指令没有对零标记的假依赖。
18.14. 打破依赖的指令
将一个寄存器置零的常见方法是XOR EAX, EAX或SUB EBX, EBX。处理器知道某些指令与该寄存器之前的值无关如果两个输入寄存器是相同。以下指令被识别为与输入无关如果两个操作数都是相同的寄存器XORSUBSBB仅依赖进位标记CMPPXORPANDNPSUBXPCMPEQBPCMPEQWPECMPEQDPCMPGTBPCMPGTWPCMPGTDXORPSXORPDANDNPSANDNPD。
对8位及16位寄存器由于对寄存器局部的处理这不奏效但对32位或更大的寄存器这是工作的。
在Steamroller上指令PCMPEQQPCMPGTQ被视为无关但在Bulldozer与Piledriver上不会。
浮点减法与比较从不视为无关因为它们必须处理像NAN及INF的特殊情形。
仅当立即数是6置零或7置全1时XOP指令VPCOMBVPCOMWVPCOMDVPCOMQ被视为与输入无关。
在两个操作数不相同时清零指令都使用相同的执行单元
18.15. 分支与循环
分支预测机制在第26页描述。不再有每16字节代码可以高效预测的分支数的限制。因为长的流水线误预测的惩罚相当高。
小循环的速度受指令获取的限制。在Bulldozer与Piledriver上小循环每迭代至少需要2时钟周期如果它包含不超过一个被采用跳转以及没有32字节边界。更大的循环受限于指令获取速率或它们包含的指令。在Steamroller上最多4条指令的微循环每迭代只需1时钟周期。
18.16. 缓存与内存访问 缓存 Bulldozer Piledriver Steamroller 1级代码 64 kB2路每行64 B两核间共享。 64 kB2路每行64 B两核间共享。 96 kB3路每行64 B两核间共享。 1级数据 每核16 kB4路每行64 B。时延3 ~ 4时钟周期。 每核16 kB4路每行64 B。时延3 ~ 4时钟周期。 每核16 kB4路每行64 B。时延3 ~ 4时钟周期。 2级 1 ~ 2 MB16路每行64 B两核间共享。时延21时钟周期。读吞吐率每4时钟周期1个。写吞吐率每12时钟周期一个。 2 MB16路每行64 B两核间共享。时延20时钟周期。读吞吐率每4时钟周期1个。写吞吐率每12时钟周期一个。 2 MB16路每行64 B两核间共享。时延19时钟周期。读吞吐率每4时钟周期1个。写吞吐率每6时钟周期一个。 3级 0 ~ 8 MB64路每行64 B所有核间共享。时延87时钟周期。读吞吐率每15时钟周期1个。写吞吐率每21时钟周期一个。 0 ~ 8 MB64路每行64 B所有核间共享。时延87时钟周期。读吞吐率每15时钟周期1个。写吞吐率每12时钟周期一个。 None
表18.5. AMD BulldozerPiledriver与Steamroller的缓存大小
数据缓存有两个128位端口可用于读或写。这意味着在同一时钟周期里可以进行两次读或者一次读与一次写。
在仅一个线程活动时测得的吞吐率是每时钟周期两次读或者一次读与一次写。在多个线程活动上我们不预期吞吐率会更低因为每个核有独立的读写单元与1级数据缓存。但我的测量显示在运行多个线程时1级缓存吞吐率要慢几倍即使线程运行在不共享任何1级或2级缓存的不同单元上。在BulldozerPiledriver与Steamroller上都观察到这个现象。没有找到对这个影响的解释。在相同单元运行的两个线程共享2级缓存吞吐率但不受运行在不同单元的线程的影响。
非对齐读与写有每时钟周期一次读或写的吞吐率。在跨缓存行边界时吞吐率是2或3时钟周期一次读或写在跨内存页边界时21时钟周期一次。
处理器可以在一个挂起的、不同地址的写之前进行一个读
在Bulldozer上在基准测试中出于未知原因某些2级缓存有令人失望的、差劲性能。Piledriver与Steamroller有高效得多的缓存系统。Steamroller看起来比以前的模型有更多写缓冲。
1级数据缓存被组织为16个每个16字节的库。数据缓存在同一时钟周期里不能进行两个内存操作如果它们使用相隔0x100倍数字节的库除了来自相同缓存行的两个读。这种缓存库冲突发生得非常频繁
; Example 18.4. Cache bank conflicts
mov eax, [rsi] ; Assume rsi is divisible by 100H
mov ebx, [rsi200h] ; Cache bank conflict. Delayed 1 clock
mov eax, [rsi] ; Assume rsi is divisible by 100H
mov ebx, [rsi210h] ; Different cache bank, no conflict
mov eax, [rsi] ; Assume rsi is divisible by 100H
mov ebx, [rsi10h] ; Same cache line, no conflict
在一个内存读地址相隔之前一个写0x1000倍数字节时有一个假依赖
; Example 18.5. False memory dependence
mov [rsi], eax
mov ebx, [rsi2000h] ; False dependence on previous write
mov ecx, [rsi2004h] ; No false dependence
18.17. 写转发暂停
从一个写转发数据到相同地址的一个后续读Steamroller比之前的设计快特别对向量寄存器。
紧跟着写从相同地址读如果读比写大会有25 ~ 26时钟周期的惩罚因为写到读转发机制在这个情形下不工作。例子
; Example 18.6. AMD store forwarding
mov [esi], eax ; Write 32 bits
mov bx, [esi] ; Read 16 bits. No stall
movq mm0, [esi] ; Read 64 bits. Stall
movq [esi], mm1 ; Write after read. No stall
在Bulldozer与Piledriver上如果读不是从与写相同的地址开始有类似的惩罚
; Example 18.7. Bulldozer and Piledriver store forwarding stall
mov [esi], eax ; Write 32 bits
mov bl, [esi] ; Read part of data from same address. No stall
mov cl, [esi1] ; Read part of data from different address. Stall
在Steamroller上局部读写入的地址没有惩罚
; Example 18.8. Steamroller store forwarding stall
movdqa [esi], xmm0 ; Write 128 bits
mov eax, [esi8] ; Read part of the data. No stall
vmovaps [esi], ymm0 ; Write 256 bits as 2*128 bits
vmovaps xmm1, [esi8] ; Crossing between two 128 bit writes. Stall
18.18. 在AMD BulldozerPiledriver与Steamroller里的瓶颈
AMD Bulldozer大体上是之前微架构的一个重新设计。某些最重要的改进是
提供每时钟周期4条指令的最大吞吐率的4条流水线。具有高吞吐率的、改进的浮点单元。将宏操作更好地调度到第一个空闲的执行单元。某些寄存器到寄存器移动被翻译为寄存器重命名。分支预测不再与代码缓存绑定没有每代码缓存行分支数的限制。具有非破坏性3操作数指令的AVX指令集。高效的融合乘加指令。
Piledriver与Steamroller类似具有某些改进。各种可能的瓶颈在以下章节讨论。
节能
节能特性在大多数时间里降低时钟频率。因为时钟频率变化通常在性能测试中给出不一致的结果。要测量最大性能有时必须关闭节能特性或者在测试代码前放入一长串CPU密集代码。
共享资源
指令获取在构成一个计算单元的两个核间共享。分支预测器与浮点单元也是共享的。在Bulldozer与Piledriver上指令解码器是共享的而Steamroller每线程有一个解码器。某些操作系统没有足够的、关于资源共享的信息因此它们可能将两个线程放入同一个计算单元而其他计算单元是空闲的。
指令获取
共享的指令获取单元每时钟周期在单线程应用中最多可以获取约20字节在多线程应用中16字节。在平均指令长度超过4字节或者频繁的跳转在流水线中产生空泡时这很可能是瓶颈。
指令解码
在Bulldozer与Piledriver上共享的解码单元每时钟周期可以处理4条指令。它在两个线程间交替使每个线程每两个时钟周期最多得到4条指令或者平均每时钟周期2条指令。这是一个严重的瓶颈因为流水线的余下部分每时钟可以最多处理4条指令。
对产生多个宏操作的指令情况变得更坏。所有产生超过2个宏操作的指令使用微代码使用。微代码定序器阻塞解码器几个时钟周期使得其他线程在这个时间暂停。
在Steamroller中指令解码成为瓶颈的可能性更小因为它每核有一个解码器支持每线程每时钟周期4条指令的吞吐率。
乱序调度
在Bulldozer与Piledriver上整数乱序调度器有40项共享的浮点调度器可能有更多。这是在以前设计上的一个重要改进。根据传闻Steamroller有更多项与物理寄存器但这没有被独立证实。
执行单元
在4条流水线间整数执行单元分布不均。其中2条流水线有所有的整数执行单元而其他2条流水线仅用于内存读指令及地址生成非LEA在某些模式上还用于简单寄存器移动。这意味着处理器每时钟周期仅可以执行两条整数ALU指令而之前的模型可以执行3条。对纯整数代码这是一个严重的瓶颈。对整数代码实际上可以通过在向量寄存器中执行一半指令加倍单核吞吐率即使每个向量仅使用一个元素。
浮点执行单元分布要好些因此有3或4条流水线可用。最常用的单元都是成对的包括浮点加法、乘法与除法以及整数加法与布尔操作。所有单元的宽度都是128位。对128位向量这给出了一个高的吞吐率在许多情形下同时服务两个线程可能足够了。所有的256位向量指令被分解为两个128位操作因此使用256位向量通常没有好处。Bulldozer与Piledriver有4条流水线用于浮点与向量操作而Steamroller仅有3条。
融合乘加指令非常高效。在执行一次加法或一次乘法的时间里它们执行一次加法与一次乘法。这实际上倍增了具有相同加法与乘法数的浮点代码的吞吐率。Bulldozer的FMA4指令与Intel的FMA3指令不兼容实际不是AMD的错就像在我博客里讨论的。
256位内存写
在Piledriver上256位内存写异常慢。事实上如此慢在Piledriver上最好完全不用256位寄存器。在Steamroller中这个问题已经解决了。
混用不同时延操作
对比之前的处理器混用不同时延操作导致的问题减少。
依赖链
浮点指令与整数向量指令的时延是相对长的。因此应该避免长依赖链。访问寄存器的局部会导致对该寄存器余下部分的一个假依赖。
跳转与分支
跳转与分支有每2时钟周期一个被采用分支的吞吐率。如果在跳转目标后附近有32字节边界吞吐率更低。分支预测尚可即使对间接跳转。因为长流水线分支误预测惩罚相当高。
内存与缓存访问
在Bulldozer上2级缓存有相当差的性能在Piledriver与Steamroller上要好得多。缓存库冲突非常频繁通常无法避免。在我的一些测试中缓存库冲突被证明是一个严重的瓶颈。在我们认为必须服务两个线程时代码缓存仅有相当低的2或3路。
回收
没有证据显示回收会是一个瓶颈。
18.19. 文献
Software Optimization Guide for AMD Family 15h Processors. AMD, January 2012.
David Kanter: AMDs Bulldozer Microarchitecture. Real World Technologies, 2010.
M. Golden, S. Arekapudi and J. Vinh: 40-Entry unified out-of-order scheduler and integer execution unit for the AMD Bulldozer x86–64 core. Solid-State Circuits Conference Digest of Technical Papers (ISSCC), 2011 IEEE International.
D. Weiss, et. al.: An 8MB level-3 cache in 32nm SOI with column-select aliasing. Solid-State Circuits Conference Digest of Technical Papers (ISSCC), 2011 IEEE International.