简介:
AMD公司于近日做出承诺将会于8月底的时候推出全新的四核心处理器架构K10架构,而产品的上市日期则被定在了今年的11月。第一款推出的基于该微架构的处理器将会是面向服务器的代号为Barcelona的Opteron处理器。
不过不幸的是AMD目前还未能进行大规模提高新处理器的核心频率。主要的障碍就是如果四核心处理器的核心频率提升过高的话就会超过当前平台对TDP的要求。不过当每次推出新版本的处理器产品同时生产工艺得到进一步改进的话,那么处埋器的功耗就会降下来同时核心频率也会得到进一步提升。因此对于AMD公司来说必须马上开始销售新的处理器以改善当前的经济条件,而根据介绍首款四核心服务器处理器的核心频率将会达到2.0GHz。根据计划AMD公司将会在2007年4季度推出核心频率在2.4-2.5GHz的 Opteron处理器,同时将会同步推出桌面版的 K10微架构处理器:
Phenom FX (代号 Agena FX) – 4 核心, 2MB L3缓存, 核心频率2.2-2.4GHz起, AM2+ Socket, F+步进
Phenom X4 (代号 Agena) – 4 核心, 2MB L3 缓存, 核心频率2.2-2.4GHz起, AM2+ Socket.
而在2008年年初,AMD还将会推出改进版本的新产品:
Phenom X2 (代号 Kuma) – 2 核心, 2MB L3 cache, 核心频率 2.2-2.6GHz起, AM2+ Socket;
Athlon X2 (代号 Rana) – 2 核心, 无三级缓存, 核心频率 2.2GHz起, AM2+ Socket;
Sempron (代号 Spica) – 1 核心,无三级缓存, 核心频率 2.2-2.4GHz起, AM2+ Socket.
当然这些都是将来才会推出的产品。在今天的这篇文章里我们将会和大家一起看到AMD新处理器微架构做出了什么样的创新之举,而通过这篇文章,相信你也会对AMD的K10架构会有一个更加深入的了解。
指令取出:
处理器开始代码处理是从L1I cache (L1指令缓存)取出指令再进行解码。x86指令拥有可变长度,因此在开始解码之前很难给这些指令定界。因此为了能够确认指令的长度同时不影响到指令执行的速度,K8/K10处理器在指令由L1I cache载入的时候就开始解码。指令的标签信息将会被存储在L1I cache里的一个特别区域内(每个比特指令拥有3比特的预解码信息)。在将这些预解码信息载入缓存的时候,每个指令的界就会被确定而无需通过译码管线,而这也将会保证解码速度的稳定性并且不依赖于指令的格式与长度。
处理器这时会从缓存内载入指令块然后选出需要进行解码的指令。基于K10微架构的处理器由L1I cache取出的指令为32B,而K8和Core 2处理器的指令为16B。在指令为16B的情况下,K8和Core 2处理器足以在每一个时钟循环发出3条平均长度为5bytes的指令。不过一些X86指令的长度也许会达到16 bytes同时在一些算法里一些相近指令的长度也许会大于5 bytes。结果在这种环境下将无法在同一个时钟循环执行三条指令。(图1)
从SSE2的命名来看,这是一个register-register型指令(比如 movapd xmm0, xmm1 )该指令的长为 4 bytes。不过如果该指令使用基址寄存器和offset发出内存寻址请求(比如movapd xmm0, [eax+16] ),那么指令的长度就会增加至6-9 bytes(这取决于offset)。如果加法寄存器(additional registers)是64位模式,那么在该指令的基础上附加一个单byteREX前缀。因此在64位模式下,SSE2指令长度将会变成7-10 bytes。SSE1指令如果是一个矢量指令的话则要则要短1 byte。但是如果是一条标量SSE1指令的话,那么在相同条件指令长度就会达到7-10 bytes 。
在这种情况下最大16-byte的数据取出对于K8处理器而言将不再会是一个限制,因为该处理器无法在两个时钟循环处理3条以外的矢量指令。而对于K10架构而言,16-byte数据块也会成为一个瓶颈,因此将最大指令取出块提至32 bytes是绝对正确之举。
这里顺便说一下的就是Core 2处理器指令取出是16-byte,这个与K8处理器是一样的,而这也是为什么在平均指令长度的情况下该处理器可以在一个时钟循环能够同时解码4个指令的原因,当然指令长度不能超过4 bytes。否则解码器就无法有效得在一个时钟周期同时处理4个或者3个指令。不过 Core 2处理器配备了一个特别的内置64-byte缓冲器,该缓冲器可以存储最新被请求的4个16-byte数据块。指令可以在32 bytes/时钟的速率进行指令取出。
分支预测:
在进行分支指令串处理时,处理器需要对处理方面进行预测以避免出现解码的中断同时继续进行大部分主支指令的处理。在这种情况下,通过分支预测算法可以用来取出下一个指令块。K8处理器使用的是两级自适应分支算法。这种算法除了可以支持管理之前的分支预测,除了用于当前指令预测以外,还可以管理之前进行的8个预测指令。K8分支预测算法的一个主要缺陷就是不能够预测动态交换寻址的间接分支。间接分支是使用指示器的分支,当进行解码操作的时候进行动态计算。这些分支通常会通过编译器嵌入switch-case 结构。同时在寻址函数引用用虚拟调用时也会得到应用。K8处理器在指令取出时总是会使用最新的寻址取得分组码。如果地址发生变化,那么管线就会被清除。如果分支地址是偶尔交互的话,那么处理器在进行预测的时候总是出错。对动态交互寻址分支进行预测是从Pentium M处理器时开始引进的。由于K8处理器没有支持这样的算法,因此在进行以目标为导向(object-oriented)的解码操作中执行效率会低。
而正如我们所预料的,K10处理器将会对预测算法进行改进,而据介绍新的改进将会使得K10处理器在执行基于以高性能为导向的代码系统时的速度将会更快。
解码:
从指令缓冲器获得的数据块就会被复制进Predecode/Pick 缓冲器,这里指令将会单独从数据块中取出,而类型则是已经定义好的然后再被送入相应的解码器管线。简单的指令可以被解码成单一或双微操作然后送入被称作DirectPath的解码器内。而复杂指令进行解码时则需要3个或者3人以上的微操作然后被送入 aka VectorPath进行解码。

解码器
每一个时钟循环可以最多执行3个微操作(MOPs)。而每一个时钟循环DirectPath解码器则可以处理3个简单的单一MOP指令或者一个 2-MOP指令以及一个单一MOP再或者是1.5 2-MOP指令。而进行复杂指令解码的时候将会需要超过3个以上的微操作,而这也是为什么需要更多的时钟循环去完成。因此为了避免冲突,K8和K10简单和复杂指令可以被同时解码。
MOPs由两个微操作组成:一个整数或者浮点计算操作以及一个内存寻址请求。微操作可以通过调度计划单独从MOPs中取出然后各自被执行。MOPs离开解码器的操作由三部分组成。有时解码器会由于交互DirectPath以及VectorPath或者是选择指令时不同的延迟会产生一群或者2个甚至是一个MOP。一个像这样不完整的群会进行MOPs补缺形成三部分,然后再执行操作。
在64位设备上,K8处理器的Vector SSE, SSE2以及SSE3指令将会分成一对MOP,然后在128-bit SSE寄存器的64-bit上半区和下半区分别进行处理。这时会因为指令数的减半而降低指令执行的速度。不过由于K10处理器将会配备128-bit FPU单元,因此将没有必要把vector SSE指令分成2个或者以上的MOPs。K8处理器上大多数SSE指令当作双DirectPath执行,而在K10处理器上只需要在一个MOPS中进行DirectPath处理。
另外就是堆栈指令执行将会得到简化。大部分的堆栈指令通常都是用于CALL-RET以及PUSH-POP,而现在只需要通过在单一的MOP中通过单一的解码器来处理。另外特别的Sideband stack optimizer (频带堆栈优化) 可以把这些指令导入独立的微操作并且可以被并行执行。
Sideband Stack Optimizer (频带堆栈优化)
K10处理器的解码器安排需要一个被称作“频带堆栈优化”(Sideband Stack Optimizer)的技术。该项技术的工作原理与intelCore微架构处理器使用的 Stack Pointer Tracker 单元十分相似。那么Sideband Stack Optimizer会给我们带来什么呢?X86使用的CALL, RET, PUSH以及POP指令被称作x86 function。所有的这些指令并不是直接使用,不过ESP寄存器可以指示当前堆栈指示器的值。
|
指令 |
同等操作 |
|
// func(x, y, z); |
|
|
push esi |
sub esp, 4; mov [esp], esi |
|
add esp, 12 |
add esp, 12 |
从上面这个例子可以看到,当函数被引用的时候会继续修改ESP寄存器,这样每一个指令会依赖于前一个指令的结果。这个串的指令将无法被重新执行这也是为什么函数会以“mov eax”开始,而只有当最后一条PUSH指令被执行完毕后[esp+16]执行才会开始。Sideband Stack Optimizer单元可以追踪这些栈值的变化并且调节每一个指令的偏移以修改指令串的值以及进行在指令直接进入栈寄存器执行之前进行sync-MOP操作。由于这种指令执行方式是直接通过堆栈执行,因此指令重新排序时将不会有任何限制。
|
指令 |
同等操作 |
|
|
// func(x, y, z); |
mov [esp-4], X |
|
|
push esi |
mov [esp-20], esi |
|
|
|
add esp, 12 |
sync-MOP |
在我们这个例子中,mov eax, [esp+16]指令只有在 sync-MOP操作时才会开始计算。现在这些指令能够与它排在前面的指令同时执行。因此更快的栈式操作、Sideband Stack Optimizer unit、更深的return-address stack以及成功的交互分支预测都将会使得K10微架构处理器在进行多功能代码执行时会更有效率。
整数执行单元:
K8和K10处理器的整数执行单元由三个对称整数管线组成。每一个管线都拥有 8-MOP队列计划,一个相同ALU(arithmetic and logical units)、AGU(address generation units)以及分枝预测单元组成。此外还有一个multiplication单元用于连接pipe 0和 pipe 2依赖于执行单元进行新指令LZCNT和 POPCNT的操作。

Integer Execution Unit
每一个MOP的队列选择都是由在 triplet中的静态位置所决定。triplet内的每一个宏操作都是从 reorder buffer(重新排序缓冲区)获取并且进行执行。一方面这样可以让指令操作简单化,但是在另一方面万一系列操作的在系统的中的代码没有合理安排好则会导致队列的不平衡载入。
正如我们在前面所谈到了,MOPs分为整数操作和在整数管线计划队列中的内存寻址请求。在获取数据之前,也许会出现让队列一个对ALU执行整数操作而一个寻址操作对AGU做出。这里最多允许出现的内存寻址请求只能有两处,因此每个时钟循环出现超过3个整数操作和2个内存操作时就会出现问题。不同算法的微操作将会在执行队列中出现无序状态。一旦算法与寻址MOP微操作被执行了之后,这个MOP就会从计划队列中移出为新的操作提供空间。K8处理器是在程序面选择内存寻址微操作。在程序代码在不能在前一个代码执行之前内存寻址操作将不会进行。结果如果较前操作的寻址无法被计划的话,那么接下来所有的寻址操作将会因此受阻。
举个例子:
add ebx, ecx
mov eax, [ebx+10h] –
mov ecx, [eax+ebx] –
mov edx, [ebx+24h] –
这将会由于K8处理器的一个瓶颈而导致性能下降。结果虽然K8处理器能够在同一个时钟循环读取两条指令,但是在一些代码中其内丰寻址执行效率要低于Core 2处理器。
而K10微架构处理器将不会再有这样的瓶颈。K10处理器现在除了能够处理乱序读取以外,如果处理器确定现有的读取和写入没有冲突的话还可以对写入进行处理。在读取之前进行写入,处理器将可以显着提升在处理一些代码时的速度。
L1:
mov eax, [esi] // data loading
.....// data processing
mov [edi] , eax // storing result
cmp
jnz L1
在这种情况下,处理器就无法在写入之前先执行读取操作,同时也无法在获取当前结果完全写入内存之前处理下一个时钟循环。CPU支持重新读取,就可以在下一个重复之前开始载入新的数据而无需等当前数据处理完成。
不过不幸的是如果寻址未知的话K10处理将无法在写入完成之前进行“投机”写入操作,而intel公司的Core 2处理器却可以。尽管这种“投机”写入有些时候会带来负面效果,但是在实际应用过程中出现的概率是很低的(大约只有5%),而这也是是为什么“投机”写入操作可以带来绝对性能提升的主要原因。
总的来说,10的整数单元将会变得非常具有效率。一旦再加入对乱序内存寻址处理之后,就将再也不会有任何瓶颈。
浮点单元:
K8和K10的浮点单元(FPU)调度计划是由整数单元调度计划分离得来不过有所不同。其调度缓冲区(scheduler buffer)由最多12个群组成,而每个群由3个MOPs组成(理论上来讲就是36个浮点操作)。与拥有对称管线的整数单元有所不同的是,FUP是由三个不同的单元组成,分别为FADD、FMUL和FMISC(又被称作FSTORE)。因此调度缓冲区将无法指定每一个群内特别的MOP到某个特别的单元(图4)
根据介绍K10处理器的浮点单元宽度将会增加至128 bit。K10将能够在一个操作里完成矢量128bit操作数,而这也是K8处理器在理论处理性能的两倍。由于调度队列长度的有效增回,也将可以使得K10进行更深入的乱序执行。
K8处理器在载入SSE指令的时使用的是FSTORE单元。一方面出现在指令执行的时候不会出现其它指令的请求,但是在另一方面也限制了同时载入的指令数只有一条。如果其中的一条指令是由内存请求和数据执行组成的话(就是所谓的Load-Execute指令),那么K8就能够进行两个并行内存读取操作,比如 ADDPS xmm1, [esi]。而K10在SSE指令读取方面则进行了明显得改善。
首先数据读取指令将不再使用FPU。这里 FSTORE接口可被其它指令所使用。同时指令读取可以在每两个时钟周期执行。第二就是如果内存内的数据排列限制在16-byte,那么MOVU**数据执行将会变成与MOVA**数据拥有同样的执行效率。
第三个改进就是K10处理器将可以使用unaligned载入,即使是包含有数据操作的Load-Execute指令时也是如此。如果处理器不清楚内存内的数据是否是成列的,那么编译器通常会使用 MOVU**指令从数据寄存器获取数据以进行进一步的处理。当使结合使用unaligned载入与 Load-Execute指令之后,将可以减少在处理时的单独数据读取操作从而带来性能的提升。另外K10处理器的另一个改进就是L1缓存的数据带宽将会提升至128 bit,而这也将会使得K10处理器能够在一个时钟循环读取两条128-bit数据块。这是K10处理器非常重要的架构设计,因此4个操作将会需要在同时有两条指令并行被处理,而在一些算法中2个或者4个流数据处理通常需要从内存中读取。而K10处理器两个bus接口可以保持64 bits宽同时在对内存写入时128-bit的结果可以分成两个 64-bit数据包。因此处理器的每一个时钟将可以进行一个128-bit写入或者两个128-bit读取,再或者是一个128-bit读取和一个64-bit写入,由于读取的次数通常都是写入的两倍,因此写入的限制将不会影响到处理器在进行128-bit数据处理时的执行效率。另外就是128-bit数据复制、MOV***寄存可以在任意三个FUP单元执行,而不只是限制在FADD 和FMUL单元。这样的结果就是FADD和 FMUL将可以进行专注处理。因此我们可以看到K10处理器的FPU将具有极高的灵活性。与 Intel 处理器相比K10的浮点单元拥有很多独特的功能,比如有效unaligned载入以及 Load-Execute 指令等。
总的来说K10 FPU将会比Core 2处理器的FPU更具效率,同时也更先进。
内存系统:Memory Subsystem
载入/存储单元
当内存寻址请求经过K8处理器的AGU处理过之后,所有的载入和存储操作都会被送入 LSU (Load/Store Unit)。LSU有两个队列:LS1和LS2。首先载入和存储操作会被送入LS1,在经过每时钟两次操作的速率处理之后,LS1对1级缓存发送请示以决定系统定码。万一缓存失败,操作会置入LS2队列的32 elements deep。这就是二级缓存和内存的寻址请求的来源。
K10处理器的LSU同样也进行了改进。现在LS1队列接收只是进行载入操作,而存储操作则被送入LS2队列。来自LS1的载入操作会以及乱序引擎方式处理并且会考虑到LS2的存储操作。正如前面我们所介绍的,K10处理器处理128bit存储操作时是分成两个64-bit操作,这也是为什么可以在每个LS2队列获得两个位置的原因。
L1缓存
K8和K10处理器的一级缓存是分离的:64KB用于指令(L1I)和数据(L1D)。每个缓存都是双路集联方式,长度为64 bytes。这种低操作符合性( associativity )也许会导致同一设置发频繁冲突从而导致缓存失败从而影响到性能。低操作符合性可以通过更大容量的L1缓存来弥补。L1D最大的优势在于能够在一个时钟循环处理两个读取或者写入操作组合。
不过遗憾的是K10处理器的L1缓存容量并没有发生变化,唯一出现的改善就是读取总线宽度获得了提升。在前面我们已经给大家介绍过该处理器现在可以在一个时钟处理两个 128-bit 读取操作,这可以在进行本地内存SSE处理时有效提升处理效率。
L2 缓存
每一款双核心或者四核心的K8以及K10处理器都拥有独立的L2级缓存。其中K10的L2缓存容量不变,每一个核心拥有512K的L2级存。独立的L2缓存与Core 2处理器的共享二级缓存相比是优势与劣势并存。共享二级缓存的一个优势就是在同时进行繁重处理的时候缓存不会产生冲突,而相对而言当进行普通任务处理器每一个核心所能使用的L2缓存容量将会十分有限。
L2缓存是独立的,那么存储在L1缓存和L2缓存内的数据就不会重复。L1和L2缓存通过两条单向总线进行数据交换,其中一条用于数据接收另一个则用于数据发送。在K8处理器上,每条总线的宽度为64bit (8 bytes)。这样向L2缓存传输数据的时候速率为8 bytes/时钟循环。因此可见这种数据传输延迟是比较可观的。
虽然目前还没有得到确认,但是K10处理器的传输和接收总线的带宽会提升两倍至128bit,这必然会很明显得降低延迟

L3缓存
为了弥补L2缓存容量的不足,K10还配备了所有处理器核心共享的容量为2M的L3缓存(32向结合性)。L3缓存是自适应且独一的,该缓存将会用于存储所有来自L2缓存的所有核心需要处理器或者共享的数据。当一个核心发出一个数据请求时就会生产一个特别检查。如果数据只被其中的一个核心使用,那么该数据就会由L3缓存中移出通过L2级存传输给发生请求的核心。如果数据同时也要为另一个核心所请求,那么该数据将会保留在缓存中。
L3缓存将可以提高核心之间数据的传输速度。目前同时代的Athlon 64处理器是通过内存总线进行核心间数据的交换,结果会导致数据共享发生延迟。根据AMD公司的资料四核心K10处理器可以通过L3缓存进行数据交换。一旦有一个核心发生请求,那么该核心就会将数据送入L3缓存,而发生请求的核心就能够从L3缓存读取。这样数据共享的延迟将会因此大大降低。
L3缓存的延迟将会明显高于L2缓存,不过根据AMD公司的介绍会因处理负荷的不同而不一。如果负荷非常重,那么延迟自然就高。
内存控制器:
当所请求数据在缓存中均未发现时,请求就会转向内置在处理器里的内存控制器发出。通过内置于处埋器内的内存控制器可以内存的运行延迟,但是也限制了与处理器配合使用的内存类型,另外也会增强核心尺寸的大小提高生产难度影响到处理器的产量。内置内存控制器一直都是K8处理器的一个强项,不过有时其执行效率并不足够。相比而言K10处理器的内存控制器则有了明显改进。
首先K10内存控制器除了能够进行128-bit单通道数据传输以外还能够支持两个独立的 64-bit通道。这样两个或者更多的处理器核心将可以更有效的同时进行处理。第二就是K10内存控制器计划于重序算法经过了进一步优化。第三就是K10处理器将能够分析请求次序以及预取性能。
预取:
预取功能一直都是K8处理器的一个优势。通过内置的内存控制器所带来的低延迟让AMD处理器在内存性能上领先了很长时间。但是K8处理器却没能有效支持DDR2内存,这主要是由于K8不具备Core 2所拥有的强劲的预取机制。K8处理器拥有两个预取单元,一个用于代码另一个用于数据。其中数据预取单元单一连续得向二级缓存预取数据。而在预取机制方面,K10则同样进行了改进。
首先K10处理器将能够直接从L1缓存进行数据预取,这样可以避免因向L2缓存进行数据请求所带来的延迟。第二就是通过AMD所采用的自适应预取机制将能够动态改变预取间隔,这样数据将能够及时获取同时缓存也无需总是载入不需要的数据。第三就是一个独立的预取单元将会被直接加入到内存控制器内。内存控制器将会分析来自核心的连续请求然后通过最优化方式将数据载入。这些改进将会极大提升K10处理器存储系统的性能。
虚拟化:
这一次AMD公司继续努力改善其虚拟化技术。其中最大的改善就是Nested Paging技术的使用:

据介绍在使用了Nested Paging技术技术之后,相比Shadow paging模式将会带来虚拟系统至少40%的性能提升
功耗及频率管理:
AMD公司将会在K10处理器使用全新的功耗及频率管理系统。K10处理器的每一个核心将会独立运行,将可以根据系统负荷动态调节核心频率。

K10处理器每一个核心可以进行独立动态调节
不过目前还不清楚共享L3缓存性能是否会受此影响。另外每个核心的工作电压也将会根据负荷进行独立调节。而内存控制器的电压则是独立控制。
总结:
从今天我们所了解到的有关K10的信息来看,AMD公司的K10处理器所拥有的性能必然要高于该公司当前的产口,而在一些需要进行浮点计算的应用中,K10的性能优势将会更加明显。在相同的频率下,K10处理器应该可以与 Intel处理器在大部分的应用中一决高下。当然与竞争对手相比,K10处理器还是拥有一些弱点。比如K10的缓存以及预取系统将会在一些应用中为其带来负面影响。
作为一名消费者而言,最不愿意看到的就是一家独大的场面了。这里我也衷心的祝愿AMD公司能通过新一代的K10架构扳回劣势,更好得发展下去。
作者:晨风
相关专题
- 数据库处理专题 (8708篇文章)
- 有钱别急着花 年后装机五大注意事项 (0次浏览)
- 大胆预测 2010年大家用的超级电脑什么样 (0次浏览)
- 少花钱多办事 探寻“阉割”版硬件潜在价值 (0次浏览)
- 二手/假货泛滥 年末CPU市场暴利全揭秘 (0次浏览)
- 十年弹指一挥间 英特尔赛扬经典CPU回顾 (0次浏览)
- 流指令扩展指令集SSE解析:CPU的兴奋剂 (0次浏览)
- 陈芝麻烂谷子 装机三大老观念逐个批判 (0次浏览)
- 小心保修暗藏陷阱 春节前装机注意事项 (0次浏览)
- 恨铁不成钢 盘点07年最令人失望三大件 (0次浏览)
- Penryn处理器技术解析 4大亮点无人能及 (0次浏览)






