六、缓存结构

几乎Nehalem的所有方面都是略为改进并增强,但存储子系统memory subsystem,或翻译为内存子系统)却是非常激烈的大修理。

Nehalem可以同时运行的读取和存储量增加了50%,读取缓冲由32项增加到了48项,而存储缓冲由20项增加到了32项增量还略多于50%)。增加的原因自然是为了让两个线程共享,这里采用的是静态分配,可能是由于关键路径的限制。

从读取缓冲和存储缓冲,存储操作就继续访问到缓存架构。Nehalem的缓存架构是完全革新了的。象P4一样,所有的缓存和数据TLBTranslation Lookaside Buffer,旁路转换缓冲,或叫页表缓冲)都是由2个线程动态共享根据已经观察到的行为)。Nehalem的L1 D一级数据缓存)保留了和Core 2一样的大小和联合度associativity),但是延迟却从3个周期增加到了4个周期,以适应时间限制timing constraint)。另外前面已经说到,每一个核心可以支持更多的未解决的命中失败outstanding miss),最多到16个,可以利用更多的存储带宽。

而Nehalem剩下的缓存结构则和Core 2截然不同。Core 2的最后一级缓存是L2,由2个核心共享,这样可以减少一致性错误coherency traffic),数量达到了24路联合的6MBPenryn),延迟是14-15个周期Conroe是14,Penryn是15)。而Nehalem有3级缓存,前两级相对较小,是每个核心私有的,而L3则非常大,由所有核心共享。

Nehalem的每个核心有一个私有的通用型L2,是8路联合的256KB,访问速度相当快。其使用延迟时间还没有完全披露,不过INTEL的工程师表明是小于12个周期的。Nehalem的L2相对于其L1D来说,既不是包含式inclusive)也不是独占式exclusive),就象Core 2一样,Nehalem可以在两个核心的私有缓存L1D和L2)之间传递数据,尽管不能够达到全速。

Nehalem的16路联合、8MB的L3对于前两级来说,是完全包含式的,并且由4个核心共享。尽管INTEL并没有完全说明Nehalem的物理设计,但似乎L3缓存是单独使用电力,并运行在单独的频率上。这是从节省电力和可靠性这两个方面推断出来的,因为大的缓存更容易在低电压下产生软错误soft error)。这样,L3使用延迟就取决于相对频率、核心的相差phase alignment)、L3自身,还有访问L3的仲裁器的延迟。在最好的情况下,即操作相差和频率差距是整数倍的情况下,Nehalem的L3使用延迟是在30-40周期根据INTEL工程师的说法)。

使用包含式缓存的好处是可以处理几乎所有的一致性流量问题coherency traffic),而不需要打搅到每个独立核心的私有缓存。如果在L3中发生命中失败cache miss),那么要访问的数据就肯定也不在任何一个L2和L1中,不需要侦听其它内核而独占式缓存,则还要回头去检查其它内核)。

另一方面,Nehalem的L3对于缓存命中成功cache hit),也扮演着侦听过滤器snoop filter)的角色。独占式缓存命中成功时,不需要检查其它内核,而包含式缓存则一般需要检查其它内核。但是在Nehalem的L3中的每一个缓存行cache line)里,有4 bit是用来做核心确认core valid)的,表明是哪一个核心在它的私有缓存里具有这个行的数据备份。如果一个核心确认位被设置成0,则那个核心就不具有该行的数据备份。Nehalem使用的是MESIF缓存一致性协议MESIF cache coherency protocol),如果两个以上核心的确认位都有效设置成1),那么该缓存行就被确定是干净的即未被修改的,任何一个内核的缓存行都不能够进入更改模式)。当L3缓存命中,而4个核心确认位都是0时,就不需要对其它内核做侦听;而只有1个位是有效时,则只需要侦听那一个核心。这两种技术的联合使用,使得L3可以尽可能的让每个核心避免数据一致性错误,这样就给出更多的实际带宽。

事实上,并非只有包含式缓存这一种解决之道。对于非包含式缓存来说,通过和最后一级缓存一起复制所有私有缓存的标志文件tag file),并同时检查所有的最后一级缓存的访问标志和私有缓存的访问标志,也可以达到同样的性能好处,并避免数据一致性错误。而包含式缓存则是设计得必须复制数据,这就能够表明各级别之间大小的一定关系。
Nehalem的每个核心有64KB L1D和256KB L2有可能L1D的数据包含在L2中,也可能L1D的数据并没有包含在L2中。因为L2并非包含式),这就意味着在8MB的L3中,有1-1.25MB的数据是前两级缓存中也有的数据。这就是包含式缓存额外的开销。

Nehalem的缓存架构设计得也更容易支持非对齐unaligned)的访问,有更快的非对齐缓存存取。INTEL前几代芯片一直是用两种类型指令来做16Byte128bit)的SSE读取和存储,一种是其数据必须正好和缓存行16B)对齐,比如MOVAPS/D、MOVDQA指令——数据)必须刚好是16Byte,和缓存行对齐。另一种则可以是未对齐的,比如MOVUPS/D、MOVDQU指令,数据对齐与否是没有要求的。

在Nehalem之前,处理对齐的指令更有优势,而处理非对齐的指令则更慢、具有更低的数据吞吐量即使其数据是在对齐的情况下),需要多个微操作。编译器也总是避免后一种指令,尽量避免非对齐的读取,象MOVSD+MOVHPD这样的2条连续指令就会更快一些。

而Nehalem则对非对齐指令进行了优化:在存取对齐数据的时候,非对齐指令和对齐指令具有一样的延迟和吞吐量。同时也提高了非对齐指令对于非对齐数据的访问速度。这样,不管是什么类型的SSE操作,都具有相同的延迟。另外Nehalem对在存取数据时跨越了64-Byte缓存行边界的情况也进行了优化,比起Core 2具有更低的延迟和更高的吞吐量。这样,编译器就不会再惧怕使用非对齐的指令了。


相关内容