Cache技术实战分析

本文详细介绍了Cache技术,从高速缓冲存储器的组成、工作原理到多核环境下的Cache一致性问题,以及如何进行Cache优化。强调了理解和优化Cache对于提升程序性能的重要性,并通过实例分析了Cache访问延迟的测试方法,揭示了编程时应注意的Cache相关问题。
摘要由CSDN通过智能技术生成

Cache技术实战分析
在计算机存储系统的层次结构中,介于中央处理器和主存储器之间的高速小容量存储器。与主存储器一起构成一级的存储器。高速缓冲存储器和主存储器之间信息的调度和传送是由硬件自动进行的。
  某些机器甚至有二级三级缓存,每级缓存比前一级缓存速度慢且容量大。
在这里插入图片描述

组成结构
  高速缓冲存储器是存在于主存与CPU之间的一级存储器, 由静态存储芯片(SRAM)组成,容量比较小但速度比主存高得多, 接近于CPU的速度。
  主要由三大部分组成:
  Cache存储体:存放由主存调入的指令与数据块。
  地址转换部件:建立目录表以实现主存地址到缓存地址的转换。
替换部件:在缓存已满时按一定策略进行数据块替换,并修改地址转换部件。
参考文献链接
https://mp.weixin.qq.com/s/PddkCP_tE-TwOyXMGM2jvA
https://mp.weixin.qq.com/s/z_rQnSD8DFGIMaj2H0–gg
https://product.pconline.com.cn/itbk/diy/cpu/1107/2474321.html
cache写好代码
CACHE基础
对cache的掌握,对于Linux工程师(其他的非Linux工程师也一样)写出高效能代码,以及优化Linux系统的性能是至关重要的。简单来说,cache快,内存慢,硬盘更慢。在一个典型的现代CPU中比较接近改进的哈佛结构,cache的排布大概是这样的:
在这里插入图片描述

L1速度> L2速度> L3速度> RAM
L1容量< L2容量< L3容量< RAM
现代CPU,通常L1 cache的指令和数据是分离的。这样可以实现2条高速公路并行访问,CPU可以同时load指令和数据。当然,cache也不一定是一个core独享,现代很多CPU的典型分布是这样的,比如多个core共享一个L3。比如这台的Linux里面运行lstopo命令:
在这里插入图片描述

人们也常常称呼L2cache为MLC(MiddleLevel Cache),L3cache为LLC(Last LevelCache)。这些Cache究竟有多块呢?看看Intel的数据,具体配置:Intel i7-4770 (Haswell), 3.4 GHz (Turbo Boostoff), 22 nm. RAM: 32 GB (PC3-12800 cl11 cr2)
访问延迟:
在这里插入图片描述

数据来源:https://www.7-cpu.com/cpu/Haswell.html
应该尽可能追求cache的命中率高,以避免延迟,最好是低级cache的命中率越高越好。
CACHE的组织
现代的cache基本按照这个模式来组织:SET、WAY、TAG、INDEX,这几个概念是理解Cache的关键。随便打开一个数据手册,就可以看到这样的字眼:
在这里插入图片描述

翻译成中文就是4路(way)组(set)相联,VIPT表现为(behave as)PIPT --cacheline的长度是64字节。
想象一个16KB大小的cache,假设是4路组相联,cacheline的长度是64字节。Cacheline的概念比较简单,cache的整个替换是以行为单位的,一行64个字节里面读了任何一个字节,其实整个64字节就进入了cache。
比如下面两段程序,前者的计算量是后者的8倍:
在这里插入图片描述

但是执行时间,远远不到后者的8倍:
在这里插入图片描述

16KB的cache是4way的话,每个set包括4*64B,则整个cache分为16KB/64B/4 = 64set,也即2的6次方。当CPU从cache里面读数据的时候,用地址位的BIT6-BIT11来寻址set,BIT0-BIT5是cacheline内的offset。
在这里插入图片描述

比如CPU访问地址
0 000000 XXXXXX
或者
1 000000 XXXXXX
或者
YYYY 000000 XXXXXX
由于红色的6位都相同,所以全部都会找到第0个set的cacheline。第0个set里面有4个way,之后硬件会用地址的高位如0,1,YYYY作为tag,去检索这4个way的tag是否与地址的高位相同,而且cacheline是否有效,如果tag匹配且cacheline有效,则cache命中。
所以地址YYYYYY000000XXXXXX全部都是找第0个set,YYYYYY000001XXXXXX全部都是找第1个set,YYYYYY111111XXXXXX全部都是找第63个set。每个set中的4个way,都有可能命中。
中间红色的位就是INDEX,前面YYYY这些位就是TAG。具体的实现可以是用虚拟地址或者物理地址的相应位做TAG或者INDEX。如果用虚拟地址做TAG,叫VT;如果用物理地址做TAG,叫PT;如果用虚拟地址做INDEX,叫VI;如果用物理地址做TAG,叫PT。工程中碰到的cache可能有这么些组合:
VIVT、VIPT、PIPT。
VIVT的硬件实现开销最低,但是软件维护成本高;PIPT的硬件实现开销最高,但是软件维护成本最低;VIPT介于二者之间,但是有些硬件是VIPT,但是behave as PIPT,这样对软件而言,维护成本与PIPT一样。
在VIVT的情况下,CPU发出的虚拟地址,不需要经过MMU的转化,直接就可以去查cache。
在这里插入图片描述

在VIPT和PIPT的场景下,都涉及到虚拟地址转换为物理地址后,再去比对cache的过程。VIPT如下:
在这里插入图片描述

PIPT如下:
在这里插入图片描述

从图上看起来,VIVT的硬件实现效率很高,不需要经过MMU就可以去查cache了。不过,对软件来说,这是个灾难。因为VIVT有严重的歧义和别名问题。
歧义:一个虚拟地址先后指向两个(或者多个)物理地址
别名:两个(或者多个)虚拟地址同时指向一个物理地址
这里重点看别名问题。比如2个虚拟地址对应同一个物理地址,基于VIVT的逻辑,无论是INDEX还是TAG,2个虚拟地址都是可能不一样的(尽管物理地址一样,但是物理地址在cache比对中完全不掺和),这样完全可能在2个cacheline同时命中。
在这里插入图片描述

由于2个虚拟地址指向1个物理地址,这样CPU写过第一个虚拟地址后,写入cacheline1。CPU读第2个虚拟地址,读到的是过时的cacheline2,这样就出现了不一致。所以,为了避免这种情况,软件必须写完虚拟地址1后,对虚拟地址1对应的cache执行clean,对虚拟地址2对应的cache执行invalidate。
而PIPT完全没有这样的问题,因为无论多少虚拟地址对应一个物理地址,由于物理地址一样,是基于物理地址去寻找和比对cache的,所以不可能出现这种别名问题。
在这里插入图片描述

那么VIPT有没有可能出现别名呢?答案是有可能,也有可能不能。如果VI恰好对于PI,就不可能,这个时候,VIPT对软件而言就是PIPT了:
VI=PI
PT=PT
那么什么时候VI会等于PI呢?这个时候来回忆下虚拟地址往物理地址的转换过程,以页为单位的。假设一页是4K,那么地址的低12位虚拟地址和物理地址是完全一样的。回忆前面的地址:
YYYYY000000XXXXXX
其中红色的000000是INDEX。在例子中,红色的6位和后面的XXXXXX(cache内部偏移)加起来正好12位,所以这个000000经过虚实转换后,其实还是000000的,这个时候VI=PI,VIPT没有别名问题。
原先假设的cache是:16KB大小的cache,假设是4路组相联,cacheline的长度是64字节,这样正好需要红色的6位来作为INDEX。但是如果把cache的大小增加为32KB,这样需要 32KB/4/64B=128=2^7,也即7位来做INDEX。
YYYY0000000XXXXXX
这样VI就可能不等于PI了,因为红色的最高位超过了2^12的范围,完全可能出现如下2个虚拟地址,指向同一个物理地址:
在这里插入图片描述

这样就出现了别名问题,在工程里,可能可以通过一些办法避免这种别名问题,比如软件在建立虚实转换的时候,把虚实转换往213而不是212对齐,让物理地址的低13位而不是低12位与物理地址相同,这样强行绕开别名问题,下图中,2个虚拟地址指向了同一个物理地址,但是INDEX是相同的,这样VI=PI,就绕开了别名问题。这通常是PAGE COLOURING技术中的一种技巧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值