Architecture: ccNUMA Architecture
架构:缓存一致的非一致性内存访问
由于IMC和QPI的存在,从形式上来看,多路Nehalem处理器系统将会组成一个NUMA(Non-Uniform Memory Access或者Non-Uniform Memory Architecture,非一致性内存访问或非一致性内存架构)系统,NUMA系统是多处理器系统的一种形式,以往的通过单条FSB连接多个Xeon处理器的系统叫做UMA(Uniform Memory Architecture,内存一致架构)系统——传统地,按照处理器架构来分的话属于SMP(Symmetric MultiProssecor,对称多处理器)系统。NUMA的特点是访问内存不同的区域具有着不一致的延迟,NUMA和UMA的共同点是所有内存是硬件共享的,操作系统只看到一片单一的内存区域,比起MPP大型并行处理系统在编程方面更为简便。
多个Nehalem处理器之间使用MESIF协议来保持缓存一致性
按照缓存页面同步的形式,NUMA可以分为两种:Cache Coherent缓存一致和Non-Cache Coherent缓存非一致性,由于编程上的艰难,因此后一种形式的实际产品几乎不存在,所以NUMA几乎就是ccNUMA(Cache Coherent NUMA)的代名词。多路Nehalem处理器就是一个典型的ccNUMA架构。ccNUMA的特点是多个处理器之间进行共享、传输的是缓存页面(缓存页面所对应的内存页面则固定地保留在某一个处理器连接的内存上)。
Nehalem通过MESIF协议来维护缓存页面的一致性(也就是Cache Coherent缓存一致的含义),而使用HT总线的AMD Opteron(多Opteron也组成一个ccNUMA架构)则使用的是MOESI协议,老的Xeon则使用MESI协议。MESIF的意思就是M(Modified)E(Exclusive)S(Shared)I(Invalid)F(Forward),MOESI则是M(Modified)O(Owner)E(Exclusive)S(Shared)I(Invalid),这些词分别代表了一个缓存页面的状态,Nehalem多了一个F状态,而Opteron则多了一个O状态。
Cache Coherent Protocol缓存同步协议 | |||||||
干净/脏 | 唯一 | 可写 | 转发 | 可安静地转化成的状态 | 说明 | ||
MESIF over QPI/CSI(Intel Nehalem) | |||||||
M(Modified) 修改 | Dirty 脏 | 是 | 是 | 是 | 被请求时需要先写入内存 并转化为F状态 | ||
E(Exclusive) 独占 | Clean 干净 | 是 | 是 | 是 | M、S、I、F | 被写入时转化为M状态 | |
S(Shared) 共享 | Clean 干净 | 否 | 否 | 否 | I | 主副本被写入时转为无效 | |
I(Invalid) 无效 | - | - | - | - | - | ||
F(Forward) 转发 | Clean 干净 | 是 | 否 | 是 | S、I | 主副本 被写入时转换为M状态 并使其他S副本无效 | |
MOESI over HTT(AMD Opteron) | |||||||
M(Modified) 修改 | Dirty 脏 | 是 | 是 | 是 | O | 被请求时不需要写入内存 而仅仅转化为O状态 | |
O(Owner) 拥有者 | Dirty 脏 | 是 | 是 | 是 | 主副本 转换为其他状态需要先写入内存 | ||
E(Exclusive) 独占 | Clean 干净 | 是 | 是 | 是 | M、S、I | 被写入时转化为M状态 | |
S(Shared) 共享 | 干净或脏 | 否 | 否 | 否 | I | 可以同时为干净或者脏 主副本被写入时转为无效 | |
I(Invalid) 无效 | - | - | - | - | - | ||
MESI over FSB(Intel Xeon) | |||||||
M(Modified) 修改 | Dirty 脏 | 是 | 是 | 是 | 被请求时需先写入内存 | ||
E(Exclusive) 独占 | Clean 干净 | 是 | 是 | 是 | M、S、I | 被写入时转化为M状态 | |
S(Shared) 共享 | Clean 干净 | 否 | 否 | 是 | I | 可以转发 | |
I(Invalid) 无效 | - | - | - | - | - |
三种缓存同步协议对比:Nehalem MESIF、Opteron MOESI、Xeon MESI
MESIF可以说是Intel在多Xeon使用的MESI协议的扩充,增加了一个F状态(同时修改了S状态让其无法转发以避免进行过多的传输)。F状态就是这样一个状态:在一个多处理器之间共享的缓存页面中,只有其中一个处理器的该页面处于F状态,另外所有处理器的该页面均处于S状态,F状态负责响应其他没有该页面的处理器的读请求,而S状态则不响应并且不允许将缓存页面发给他人(或许S用Silent来代表更合适)。
当一个新处理器需求读取这个F页面时,原有的F页面则转为S状态,新的处理器获得的页面总是保持为F状态。在一群相同的页面中总有并且只有一个页面是处于F状态,其他的S副本则以F副本为中心。这种流动性让传输压力得以分散到各个处理器上,而不是总维持在原始页面上。
不会改变的页面的共享很好处理,关键的是对Dirty页面的对待(Dirty页面是指一个内容被修改了的缓存页面,需要更新到内存里面去),显然,一堆页面的副本中同一时间内只能有其中一个可以被写入。MESIF中,只具有一个副本的E状态在被写入的时候只需要简单地转化为M状态;而F状态被写入时则会导致其所有的S副本都被置为无效(通过一个广播完成);S副本是“沉默”的,不允许转发,也不允许被写入,这些副本所在的处理器要再次使用这个副本时,需要再次向原始F副本请求,F副本现在已经转化为M副本,被请求状态下M副本会写入内存并重新转化为F状态,不被请求时则可以保持在M状态,并可以不那么快地写入内存以降低对内存带宽的占用。
MESIF实际上只允许一堆共享副本当中的中央副本(F状态)被写入,在多个处理器均需要写入一个缓存页面的时候,会引起“弹跳”现象,F副本在各个处理器之间不停传输——这有点像令牌环——会降低性能,特别是F副本不在其所在的原始内存空间的时候。
Opteron的MOSEI协议不需要被写入的M状态写入内存就可以进行共享(这时M状态会转变为O状态,共享后的Dirty副本被标记为S状态),这避免了一次写入内存,节约了一些开销,尚不清楚为什么Intel没有在新生的总线上采用这种更为优化的协议;当再次写入O状态副本时,其他的S副本同样会被设置为无效。MOSEI也只允许一堆共享副本当中的中央副本(O状态)被写入,也存在着弹跳现象。
不过,在一个方面Nehalem具有优势:包含式(或者非独占式)L3缓存,当一个处理器被请求一个页面,或者被通知一个页面要被设置为无效的时候,它只需要检查L3就可以知道该如何操作。在L3缓存没有这个页面的时候,不需要像非包含式L3设计那样,再检查L1、L2页面。