当出现缓存缺失(cache miss)时,高性能处理器依然会继续发出存储访问请求。早期的缓存设计中,处理器发出的后续存储访问会被阻塞,直到前面缓存缺失的存储访问得到相应的数据。很显然,这会大大降低处理器的性能。
现代缓存设计中,为了解决这一问题,引入了缺失状态处理寄存器(Miss Status Handling Register,MSHR)。当出现缓存缺失时,一个MSHR会用来记录缓存缺失状态,高速缓存可以继续响应其它的存储访问请求,当缓存缺失被满足后,这个MSHR会被释放。这种高速缓存设计也被称为非阻塞或者无锁高速缓存。
在给定的任意时间内,待处理的缓存缺失数量受MSHR数量的限制。因此,MSHR的数量会影响存储层的并行度。在设计MSHR数量时,要考虑处理器一个时钟周期内可以执行的指令数,访问外层存储层次的延迟和带宽,以及内层存储层次访问过滤的配置。
对于无锁缓存来说,未命中的情况可以分为三类:
初次缺失(Primary Miss):发生的第一次未命中,被请求数据不在缓存中,此时缓存需要向下一层存储请求数据。
二次缺失(Secondary Miss):请求的地址已经保存在MSHR中,还在请求数据的缓存块再一次发生未命中的情况,缓存正在等待更高层的储存系统发回数据。
结构停顿缺失(Structural-Stall Miss):MSHR已满,无法处理新的缓存缺失。这种未命中会因为结构冒险而导致系统停顿。
一般,MSHR实现方式有三种:隐式寻址MSHR(Implicitly Addressed MSHRs),显示寻址MSHR(Explicity Addressed MSHRs),缓存内MSHR(In-Cache MSHRs)。
对于隐式寻址MSHR,首先要有一个有效位(Valid),能让表明MSHR里面所存储的信息是否有效。其次,需要把在同一个缓存块里面缺失的信息存储在同一个MSHR里面,这样方便以后的机制来进行管理。如果缓存块有N个word,那么就有N个条目的寄存器,每个条目记录对应word上的miss信息。最后,还需要保存一些格式信息,例如此次访存指令的位宽,是否需要符号扩展等。还需要有一个寄存器保存块地址。发生初次缺失时,会设置这个地址寄存器以及相应字的目的寄存器。如果后续发生了二次缺失,就比较地址,并设置目的寄存器。所谓的隐式,也就是说一个访存指令在块内的地址隐式地由目的寄存器的编号决定。根据上面的描述,可以看出隐式寻址MSHR的缺点就是会有一定的硬件浪费。
显式寻址MSHR不要求目的寄存器的数量和块的大小相同,但是需要显式地在寄存器中保存一次访存请求的块内偏移。这样可以允许任意数量的未完成请求,可以和缓存块大小解耦。
第三种是缓存内MSHR。因为在缓存块还没有读取完毕的时候,缓存块是没有数据的,所以可以利用这个空间来保存MSHR信息,也不必使用额外的地址寄存器。这种设计要求缓存块额外带一个transient标记位,用来标记这个缓存块是不是还在获取。当transient比特位设为1时意味着对于这个block的数据正在从上级缓存中被取回。相比之下,这缓存内MSHR可以减少额外的硬件开销。
原作者:老秦谈芯
|