Cache基本概念
Line:表示缓存的一行数据
Tag:即内存地址的一部分,用来标记内存和cache一行数据的关联性。
Index:缓存中的第几行,也是第几个Set
Offset:一行缓存中的第几列,粒度到字节
Way:路,即一片缓存,图中有4个Way
Set:组,所有缓存片中相同Index的行,图中有4个Set
Cache框图
例如:64KB L1 Cache,64byte Cache Line,4Way的Cache框图
1 Way有多少个Cache Line?
64 * 1024 / (64 *4) = 256
44位的地址
43~14bit: 共30bits是Tag,和Set中所有Cache Line的Tag比较,匹配到哪一个Cache Line。
13~6bit: 共8bits是Set即Index,指定256 Set中的哪一个Set。
5~0bit: 共6bits是Offset,指定Cache Line 64字节中的哪一个字节。
Cache分配策略
cache的分配策略是指我们什么情况下应该为数据分配cache line。cache分配策略分为读和写两种情况。
读分配(read allocation)
当CPU读数据时,发生cache缺失,这种情况下都会分配一个cache line缓存从主存读取的数据。默认情况下,cache都支持读分配。
写分配(write allocation)
当CPU写数据发生cache缺失时,才会考虑写分配策略。当我们不支持写分配的情况下,写指令只会更新主存数据,然后就结束了。当支持写分配的时候,我们首先从主存中加载数据到cache line中(相当于先做个读分配动作),然后会更新cache line中的数据。
Cache更新策略(Cache update policy)
cache更新策略是指当发生cache命中时,写操作应该如何更新数据。cache更新策略分成两种:写直通和回写。
写直通(write through)
当CPU执行store指令并在cache命中时,我们更新cache中的数据并且更新主存中的数据。cache和主存的数据始终保持一致。
写回(write back)
当CPU执行store指令并在cache命中时,我们只更新cache中的数据。并且每个cache line中会有一个bit位记录数据是否被修改过,称之为dirty bit。我们会将dirty bit置位。主存中的数据只会在cache line被替换或者显示的clean操作时更新。因此,主存中的数据可能是未修改的数据,而修改的数据躺在cache中。cache和主存的数据可能不一致。
Cache组织方式
VIVT
VIVT(Virtually Indexed Virtually Tagged):通过VA虚拟地址中部分位域作为Index找对应的Cache Set,通过VA虚拟地址中部分位域作为Tag判断cache是否命中。
VIVT产生问题
1)歧义
指不同的数据在cache中有相同的tag和index。
例如:
A进程虚拟地址0x4000映射物理地址0x2000
B进程虚拟地址0x4000映射物理地址0x3000
当A进程切换到B进程后,B进程访问0x4000,cache命中,此时访问的是A进程的数据
如何避免歧义?
当切换进程时flush所有的cache。使得cache dirty数据写回到主存,并invalid cache使得切换后不会命中上一个进程的缓存数据。
因此,切换后的进程刚开始执行的时候,将会由于大量的cache miss导致性能损失。
所以,VIVT高速缓存明显的缺点之一就是经常需要flush cache以保证歧义不会发生,最终导致性能的损失。
2)别名
当不同的虚拟地址映射相同的物理地址,而这些虚拟地址的index不同,此时就发生了别名现象(多个虚拟地址被称为别名)。
例如:
0x2000 VA映射PA 0x8000
0x4000 VA映射PA 0x8000
cache使用写回机制。假如cache index bit:15~4
0x8000存储数据0xABCD
这时进程A访问0x2000,那么0xABCD加载到cache Index 0x200中
然后进程B访问0x4000,那么0xABCD加载到cache Index 0x400中
如果进程A修改了0xABCD为0xEFFE,那此时进程B读到的还是旧值0xABCD,就导致不一致问题。
此时如何避免?
方法一:使用nocache映射
方法二:不同进程共享数据时,进程切换时主动flush cache
若同一个进程共享数据?
PIPT
PIPT(Physically Indexed Physically Tagged)物理地址部分位域作为Index和Tag的缓存。
因为是使用的是物理地址,相对应的Tag是唯一的,针对同一个物理地址,index也是唯一的。
所以不存在歧义和别名的问题。
PIPT都是硬件层面实现管理cache的,软件层面无需任何的管理。
VIPT
VIPT(Virtually Indexed Physically Tagged)先提取虚拟地址部分位域作为Index查找cache,同时将虚拟地址发给MMU。MMU转换物理地址完成时,对应Index查找cache也同时完成,然后对比cache Tag和物理地址位域Tag,以此判断是否命中。
使得VIPT不存在歧义:当一Way路cache大小>=Page size的时候,VIPT的tag取决于物理页大小的剩余位数。否则的话就是除去index和offset后剩余的位数。
使得VIPT不存在别名:如果是直接映射高速缓存的话,在建立共享映射的时候,返回的虚拟地址都是按照cache大小对齐的地址,这样就没问题了。如果是多路组相连高速缓存的话,返回的虚拟地址必须是满足一Way路cache大小对齐。在Linux的实现中,就是通过这种方法解决别名问题。
Cache操作有哪些
1、invalid整个缓存或某个缓存行,缓存上的数据会被丢弃
2、clean清除整个缓存或某个缓存行,相应dirty的缓存行被刷新到下一级缓存中或内存中
3、zero清零操作。对高速缓存进行清零操作起到预取和加速效果。可参考内核memset.S中使用
Cache操作范围
1、整块高速缓存
2、某个虚拟地址
3、特定的高速缓存行(Cache Line)或者组(Set)和路(Way)
参考资料:
1、ARM64体系结构与编程之cache必修课(上)
2、ARM64体系结构与编程之cache必修课(中)
3、ARM64体系结构与编程之cache必修课(下)
4、Cache的基本原理
5、Cache组织方式