组相连的cache 结构
cache 基本结构如下图。下图中,存在4路(way,黄框所示为一个way),每一路中有4Line(绿色填充的为一个cache line),每一Line有4个Wrod,假设每个Word有4个Byte。 四个绿色填充的位于不同Way 的Line,组成一个组(Set)。
在查找某个地址索对应的cache 时,使用地址中的index 位找到对应Line,offset 找到对应Word,bytes 位找到对应Word 中的某个Byte。然后使用地址中的tag 位(其实就是高位地址),与cache 中的tag 位对比,如果一致,则命中。
可以看出,具有相同index 的两个不同地址,会索引到相同的Cache Line。如果只有一个Way,在两个地址频繁交替访问的场景下,这两个地址势必频繁cache 未命中。多个way 相连则可以解决这个问题,组相连的意义就是在此。
PIPT 与VIVT 的访问方式
PIPT(physical index physical tag),物理高速缓存,即使用mmu 翻译过的物理地址来索引cache。因为mmu 翻译过程经常会读取main memory(一般就是DDR),因此必须承担这一项时间消耗。 VIVT(virtual index virtual tag),虚拟高速缓存,即直接使用虚拟地址来索引cache。优点是无需经过mmu 翻译,但是可以想象,由于虚拟地址与物理地址的复杂映射关系,势必存在问题:
- 重名问题,即不同的虚拟地址映射到相同的物理地址时,(比如对同一个物理地址mmap了两次这种情况)cache中将拥有两份该物理地址的缓存。如果都是读操作则只有浪费问题;但如果有一方存在写操作,那么还会带来一致性的问题
- 同名问题,即相同的虚拟地址映射到了不同的物理地址时,此时通常是不同的进程拥有相同的虚拟地址,但是对应的物理地址不同。此时的问题就是,虽然cache 命中了(cpu发出的虚拟地址一样),但是cache中的内容却是上一个进程的。
VIPT(virtual index physical tag),PIPT存在mmu 虚实转换耗时,VIVT存在重名和同名问题,有没有折中的办法?有,那就是VIPT 。cpu发出的地址中包含tag域和index,在VIPT中,index域直接送往cache进行索引,同时,tag域送往mmu 进行TLB和mmu进行转译。这样索引cache line 和mmu 转译的过程并行进行,节省了时间。但是同样存在问题:当高速缓存的way 的大小大于page 时,存在alias 问题。比如如下场景: 1、cache way 大小为8K,linux page大小为4K 2、两个虚拟地址VA1, VA2映射到了同一个物理地址(例如多次mmap 的情况) 3、两个虚拟地址只有bit12不一样 此时,由于cache way是8KB,所以索引域需要占用bit0-bit12(pow(2,13)/1024 = 8)。此时又由于VA1 VA2只有bit12不同,并且两者的tag域必然相同(因为tag就是物理地址,前述条件就是VA1/2映射到了同一个物理地址),因此两个虚拟地址VA1, VA2 映射到了不同的cache line。这就导致了重名问题。 现代处理器中,如ARM Cortex-A7, A9, A15, A53,数据cache 均采用了PIPT,指令cache采用了VIPT(可能是因为aliasing 问题只对写操作带来问题,而指令不需要修改?) 参考文献: 《奔跑吧linux内核(第2版)》笨叔 著
|