集中式缓存处理器结构(SMP)
不同核访问存储器时间相同。
分布式缓存处理器结构(NUMA)
共享存储器按模块分散在各处理器附近,处理器访问本地存储器和远程存储器的延迟不同,共享数据可进入处理器私有高速缓存,并由系统保证同一数据的多个副本的一致性。
每个处理器核拥有本地的LLC(最后一级缓存),并通过片上互连访问其他处理器核的LLC。
缓存一致性
在共享存储的多核处理器中,存在Cache一致性问题,如何使同一数据块在不同Cache以及主存中的多个备份保持数据一致的问题。一个数据块可能在主存和Cache之中保存多份,而不同的处理器核有可能同时读取或者修改这个数据,导致不同的处理器核观察到的数据的值是不同的。所以需要缓存一致性协议保证缓存一致。
缓存一致性协议分类
(1)从如何传播新值的角度看,Cache一致性协议可分为写无效协议与写更新协议;
(2)从新值将会传播给谁的角度看,它可以分为侦听协议与目录协议。
写无效:把一个处理器核对某一单元所写的值传播给其他处理器核时,就使其他处理器核中该单元的备份无效;其他处理器核随后要用到该单元时,再获得该单元的新值。
(1)优点:一旦某处理器核使某一变量在所有其他Cache中的备份无效后,它就取得了对此变量的独占权,随后它可以随意地更新此变量而不必告知其他处理器核,直到其他处理器核请求访问此变量而导致独占权被剥夺。
(2)缺点:当某变量在一处理器核中的备份变无效后,此处理器核再读此变量时会引起Cache不命中,在一个共享块被多个处理器核频繁访问的情况下会引起所谓的“乒乓”效应,即处理器核之间频繁地互相剥夺对一个共享块的访问权而导致性能严重下降。
写更新:当根据一致性要求要把一个处理器核对某一单元所写的值传播给其他处理器核时,就把该单元的新值传播给所有拥有该单元备份的处理器核,对相应的备份进行更新。
(1)优点:一旦某Cache缓存了某一变量,它就一直持有此变量的最新备份,除非此变量被替换掉。
(2)缺点:写数的处理器核每次都得把所写的值传播给其他处理器核,即使其他处理器核不再使用所写的共享块。
写无效协议适用于顺序共享(Sequential Sharing)的程序,即在较长时间内只有一个处理器核访问一个变量;而写更新协议适用于紧密共享(Tight Sharing)的程序,即多个处理器核在一段时间内频繁地访问同一变量。
侦听协议:当一个处理器核对共享变量的访问不在Cache 命中或可能引起数据不一致时,它就把这一事件广播到所有处理器核。系统中所有处理器核的Cache都侦听广播,当拥有广播中涉及的共享变量的Cache侦听到广播后,就采取相应的维持一致性的行动(如使本Cache的备份无效、向总线提供数据等)。
在写无效侦听协议中,当一个Cache侦听到其他处理器核欲写某一单元且自己持有此单元的备份时,就使这一备份无效以保持数据一致性;在写更新侦听协议中,当一个Cache侦听到自己持有备份的某一共享单元的内容被其他处理器核所更新时,就根据侦听到的内容更新此备份的值。
(1)优点:侦听协议实现较简单,每个处理器核Cache只需要维护状态信息。侦听协议适合于通过总线互连的多核处理器,因为总线是一种方便而快捷的广播媒介。
(2)缺点:由于侦听协议需要广播,因此只适用于共享总线结构。总线是一种独占式资源,且总线延迟随所连接的处理器核数目的增加而增加,存在可伸缩性差的问题。
目录协议:在采用片上网络互连的多核处理器中通常使用基于目录的Cache一致性协议。目录协议的主要思想是,为每一存储行维持一目录项,该目录项记录所有当前持有此行备份的处理器核号以及此行是否已被改写等信息。
优点:当一个处理器核欲往某一存储行写数且可能引起数据不一致时,它就根据目录的内容只向持有此行的备份的那些处理器核发出写使无效/写更新信号,从而避免了广播。
典型的目录组织方式为位向量目录。位向量目录中的每一目录项有一个n位的向量,其中n是系统中处理器核的个数。位向量中第i位为“1”表示此存储行在第i个处理器核中有备份。每一目录项还有一改写位,当改写位为“1”时表示某处理器核独占并已改写此行。位向量目录的缺点是,所需的目录存储器容量随处理器核数n以及共享存储容量m的增加以O(m*n)的速度增加,有较大存储开销。
缓存行的状态(以SEI协议为例)
Cache一致性协议的实现方式为,在Cache中每一个Cache行添加字段 表示一致性状态来记录该Cache行的读写状态,确保Cache行不会被多个处理器核同时修改。Cache行的一致性状态的实现有多种具体形式,如最简单的三状态ESI,较为常见的MESI及其变种MOESI等。
SEI协议的三种状态:E(Exclusive独占),S(Shared共享),I(Invalid无效)。
Invalid状态表示当前Cache行是无效的,对其进行任何读写操作都会引发缓存缺失(Cache Miss)。
Shared状态表明当前Cache行可能被多个处理器核共享,只能读取,不能写入,对其写入也会引发缓存缺失。
Exclusive状态表明对应Cache行被当前处理器核独占,该处理器核可以任意读写这个Cache行,而其他处理器核如果想读写这个Cache行需要请求占有这个Cache行的处理器核释放该Cache行
缓存访问举例
(使用写无效的向量目录协议,处理器核Pi 执行Load x为例)
(1)Cache命中
当处理器核Pi发起一个取数操作LOAD x:
如果数据x在Pi的Cache中,且处于共享状态(SHD)或独占状态(EXC),则直接在Cache中读取数据,这是一个Cache命中事件。
(2)Cache未命中
如果数据x在Pi的Cache中处于无效状态,则需要从主存储器中获取数据:Pi向存储器发送读数请求read(x)。
存储器检查其目录项以确定x的状态:如果目录项显示x所在的存储行处于CLEAN状态(改写位=0),表示x的数据在存储器中是最新的。
存储器向Pi发送读数应答rdack(x),附带x的有效备份,并将目录项中对应Pi的位置标记为1。
如果目录项显示x所在的存储行已被另一个处理器核Pk改写(改写位=1),说明x的数据在Pk的Cache中有最新的副本。
存储器向Pk发送写回请求wtbk(x)。Pk收到wtbk(x)后,将其Cache中x的副本状态从独占状态(EXC)改为共享状态(SHD),并向存储器发送写回应答wback(x),附带x的有效备份。
存储器收到wback(x)后,更新目录项中的改写位为0,并将位向量的第i位(对应Pi)设置为1,然后向Pi发送rdack(x)。
Cache替换
如果x不在Pi的Cache中,Pi可能需要替换Cache中的一行来为x腾出空间,然后再执行上述的读数请求流程。
(流程图如下)
当处理器核Pi执行STORE x:
(1)如果x在Pi的Cache中处于独占状态(EXC),则直接在Cache中修改数据,这是一个Cache命中事件。
Cache未命中
如果x在Pi的Cache中处于共享状态(SHD)或无效状态(INV),Pi需要获取对x的独占访问权限:
Pi向存储器发送写数请求write(x)。
存储器处理:存储器检查与x对应的目录项,确定x的状态:如果x的存储行处于CLEAN状态(改写位=0),并且没有被其他处理器共享(位向量全0)
存储器向Pi发送写数应答wtack(x),允许Pi独占x,更新目录项的改写位为1,并将位向量的第i位设置为1。
如果x的存储行处于CLEAN状态,但被其他处理器共享(位向量中有些位为1):存储器向所有共享x的处理器核发送使无效信号invld(x)。接收到invld(x)的处理器核将x的Cache状态改为无效状态(INV),并向存储器发送使无效应答invack(x)。
存储器收到所有invack(x)后,向Pi发送wtack(x),更新目录项的改写位为1,位向量的第i位为1,其他位清零。
如果x的存储行已被另一个处理器核Pk改写(改写位=1):存储器向Pk发送使无效并写回请求invwb(x)。Pk收到invwb(x)后,将x的Cache状态从独占状态(EXC)改为无效状态(INV),并向存储器发送使无效并写回应答invwback(x),附带x的有效备份。存储器收到invwback(x)后,向Pi发送wtack(x),更新目录项的改写位为1,位向量的第i位为1,其他位清零。