cache
为什么需要高速缓存
解决处理器访问速度与内存速度严重不匹配的问题;
高速缓存架构
- l1 cache:分为dcache,icache,存在于每个cpu内部;
- l2 cache:不区分dcache, icache,由一个cluster内的cpu共享;
- l3 cache:不区分dcache, icache,各个cluster共享
访问延时
系统存在两种内存体系结构:uma,numa
- uma:系统中只存在一个内存结点,所有cpu通过相同的总线去访问同一个内存结点;
- numa:每个cpu结点存在对应的内存结点,可以通过总线直接访问;也可以通过upi总线访问非本地的内存结点,速度更慢;****
- 访问延时:l1 < l2 < l3 < 远端l3 < 本地ddr < 远端ddr
- cache的访问延时都是可以以时钟周期进行度量,到ddr级需要60ns以上;
如何理解组和路
路:把一个cache分为平均分为几列就是几路;
组:然后想象放在一起平铺,有几行就是有多少组;
每组有多少cacheline,就是每组有多少列,就是多少路;(网上画的就是把这些路重叠了一下)
如图:有5列,就是5路;有3行,就是3组;
- 每组有5个cacheline;(5列)
- 每路有3个cacheline;(cacheline总数/路)
寻址:如何通过内存地址找到所在cache中的位置?
tag,index,offset
- offset: 全称是字节索引,cacheline内偏移;
- index:全称是行索引,定位到是哪个组;(哪行)
- tag:index定位到是哪一组之后,需要定位到是哪路(哪列);还有可能这个组中的每一路都没有对应地址的数据,需要tag去比较;
VIPT:virtual address 寻址具体cache的具体过程
- 虚拟地址同时传递给TLB和高速缓存
- 传递给tlb的目的是获取pfn
- 如果tlb命中,直接从tlb获取pfn;
- 如果tlb没有命中,则需要查询页表获取pfn;
- 根据虚拟地址的index域找到高速缓存行对应的组;
- 传递给tlb的目的是获取pfn
- 如果cache没有命中,则需要到主存获取进行数据获取;
映射方式
直接映射:
只有一路
全相连
只有一组
组相连
- 有多少行就是多少组
- 有多少列就是多少路
高速缓存策略
分配:cache miss的情况
- 读分配(read allocation) :当CPU读数据时,发生cache缺失,这种情况下都会分配一个cache line缓存从主存读取的数据。默认情况下,cache都支持读分配。
- 写分配(write allocation) :当CPU写数据发生cache缺失时,才会考虑写分配策略。
- 当我们不支持写分配的情况下,写指令只会更新主存数据,然后就结束了。
- 当支持写分配的时候,我们首先从主存中加载数据到cache line中(相当于先做个读分配动作),然后会更新cache line中的数据
更新: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和主存的数据可能不一致。
- (只有写的策略,没有读的策略)
共享属性
共享属性
- 内部共享的高速缓存:CPU内部继承的高速缓存;
- 外部共享的高速缓存:系统总线扩展的高速缓存;
共享域:
目的:指定可以访问内存的硬件单元实现一致性的范围;
分为以下四个域:
- 不可共享域:
- 内部共享域:通常是cpu之间
- 外部共享域:是cpu + 访问内存的ip(DMA、GPU)
- 系统共享域:
pou和poc
- poc:就是上面所描述的外部共享域;一致范围是CPU + 访问内存的IP
- pou:系统的内部;比如cpu之间;
高速缓存维护指令
操作:
- invalid:使整个高速缓存行失效
- clean:将标记为脏的整个高速缓存写入下一级高速缓存或内存中,然后清除脏位;
- zeor:主动写入零数据到cacheline;
指令:
- 数据缓存:DC
- 指令缓存:IC
在指令中会指定观察点,也就是POC,POU;
cache问题
颠簸、伪共享:都是cacheline的数据由于其他cpu对其的更新,导致本地的cacheline又得不停的更新,进而性能下降;
参考
https://cloud.tencent.com/developer/article/2206026
什么是歧义
不同的物理地址映射到同一个虚拟地址,如果是vivt,那么就会造成不同的地址映射到同一个cacheline;
vipt存在歧义吗?
歧义的前提同一个虚拟地址映射到不同的物理地址。虚拟地址相同,物理地址不相同,那么这两个物理地址一定有这么一个特征:以4k page为例,这两个物理地址的[11:0]必定是相同的;
- 虚拟地址相同,那么虚拟地址的[11:0]也一定相同,[11:0]是页内偏移,和物理地址完全能对上;所以一定有以上特征;
物理地址可以看成pfn + 页内偏移,现在这两个物理地址的页内偏移相同了,那么他们两的pfn一定是不相同的;
vipt会将是物理地址的pfn作为tag;他们pfn一定不相同,所以他们的tag也一定不相同; - 所以vipt,会因为index相同映射到同一个组中,但是他们的tag不同,任然会定位到不同的cacheline,所以不存在歧义问题;
存在别名问题吗?
同一个物理地址对应不同虚拟地址,pfn一定相同,也就是tag一定相同;
如果两个虚拟地址的index 与 offset 任一不相同就会映射到不同的cacheline,造成别名问题;
index 与 offset 的来自于虚拟地址,也就是虚拟地址的[index+offset, 0]完全一样,就不会出现同名问题;
怎么能保证完全一样呢?[index+offset, 0]在一个page中;因为他们对应的是同一个物理地址,页内偏移是完全一样的;[index+offset, 0]构成一路,也就是一路小于4k;
- 同一物理地址对应不同虚拟地址,这两个虚拟地址一定有[11: 0]完全相同的特性
总结
- 不同的物理地址正常应该映射到不同的cacheline。歧义,就是不同物理地址映射到了同一cacheline,想要不存在问题就得映射到不同的cacheline;
- 同一物理地址应该映射到同一cacheline。同名,就是同一物理地址映射到了不同cacheline,想要不存在问题就得映射到同一cacheline;
按照这两个分析就完事;
pivt
歧义
虚拟地址相同,所以vt一定相同;想要映射到不同的cacheline就得靠pi不同,虽然物理地址不同,但是pi不能保证一定不同。所以还是存在歧义问题
别名
虚拟地址不同,vt一定不同,所以一定存在同名问题;
解决
歧义
解决不同物理地址在同一cacheline问题;
- 为了防止数据丢失,进程切换时得进行cache flush;
- 为了不使用其他物理地址的cache数据,进程切换还要invalid
别名
- 直接映射 + 虚拟地址是cache大小对齐;
- 如果是多路组相连高速缓存的话,返回的虚拟地址必须是满足一路cache大小对齐。
这时候就算是vi不同,但由于循环存放,就能刚好存放在那个cacheline; 太巧妙了;
解决原理: - tag一定是相同的,保证index可以进行循环存放即可;也就是虚拟地址是cacheline对齐;
- 由于tag是相同的,就算是多路,也一定是在同一路的;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通