memory cache 直接映射、全相联映射和组相联映射

cpu的执行速度很快,cpu从memory读取数据速度很慢,导致cpu需要等memory,为了提高cpu的效率,根据程序的局部性原理(现在访问的数据很有可能以后还会访问),引入了读写比较快的memory cache,cache用来存放刚刚访问的memory的数据,这样下次再需要从memory读写数据时,可以直接从cache里面读,速度快了很多,提高了cpu的效率。

cache比memory速度快,但是也比memory价钱贵,所以cache一般比较小,比如memory可能有4G、但cache只有64k。既然cache不能存放所有的memory数据,那memory中的数据应该存放在cache的什么位置呢?希望达成的效果是最近经常访问的数据都在cache里面,并且查找也要快速。

考虑下面一个程序,假设这个程序在memory中的存放如下图1,这个时候在运行程序的时候肯定是希望code和data都被cache。为了达到这个目标,有3种方案可以选择,图2直接映射,图3全相联映射,图4组相联映射。

int a = 0;

int main()
{
    while(a < 100) {a++;}
}

                                                   图1 程序的内存分布

                                                   图2 直接映射

假设cache有4个cache line,memory比较多,另外各图的方框表示的空间大小相同,即一个memory的方框和一个cache的方框(cache line)大小相同。

直接映射,就是把memory按照cache line的数量分组,有4个cache line,那么memory每4个一组,每一组直接对应cache的相应line。memory第一组的0-3分别映射到cache的line 0-3。第二组的4-7分别映射到cache的line 0-3。

通过直接映射,code被放到了cache line 0和1,data也被映射到了cache line 0。这个时候的问题是,执行代码的时候命中cache,读写数据的时候不命中,然后更新cache,把cache的内容换为data。再执行的代码的时候发现code被从cache中移除了,导致cache不命中,然后又更新cache,换成code。读写数据的时候就又会cache不命中,更新cache;然后又代码cache不命中....嗯,需要尝试一下其他的映射方式了

                                                   图3 全相联映射

全相联映射,不规定memory在cache中的位置了,随意放。比如memory 0可以放在任意的cache line。其他memory也是,所有的cache line都可以放。

通过全相联映射,可能的结果是1)code放在了cache line 0 & 1,data放在了cache line 2,也可能2)code 0放在cache line 3,code 1放在cache line 2,data放在cache line 0。至少都在cache里面了。存在的问题是,当cpu拿着内存地址来找是否在cache中时,就会比较费力了。只拿着一个内存地址来找cache的话,只能把cache遍历一遍了,不太好。嗯,再考虑另外一种映射方案吧

                                                   图4 组相联映射(每组2个为例)

组相联映射,希望可以把程序都放在cache,同时希望查找要方便。回想直接映射的时候,因为memory 0和memory 4都映射到了cache line 0,所以导致频繁的cache不命中/更新。如果cache line 0可以同时把memory 0和memory 4都保存了,就会一直cache命中了……

但是一个cache line只能存放一个memory方框的内容(因为一个cache line的大小等于一个memory方框的大小),怎么办呢?考虑把cache line 0和cache line 1当成一个大的cache line吧,也就是把两个相邻的cache line当作一组、组成一个大的cache line,然后采用直接映射。

这样,之前的4个cache line变成了2个大的cache line,按照直接映射的规则,把memory按照cache line的数量分组,有2个大的cache line,那么memory每2个一组,每一组直接对应cache的相应line。这样memory第一组的0-1分别映射到大cache line 0-1(组0和组1),第二组的2-3分别映射到大cache line 0-1,第三组的4-5分别映射到大cache line 0-1。

映射到大的cache line之后需要决定具体放到哪个小的cache line,这个时候是随意的,哪个都可以。比如memory 0映射到组0(大的cache line 0)后,放在cache line 1;memory 1映射到组1(大的cache line 1)后,放在cache line 2;memory 4映射到组0(大的cache line 0)后,放在cache line 0。

这种映射可以把相关的代码数据都放在cache,同时查找也方便点,因为一个组里面的cache line数量比较少。这种方式也算是可以达成最初的期望:最近经常访问的数据都在cache里面,并且查找也要快速。

发布了34 篇原创文章 · 获赞 0 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/hfyinsdu/article/details/104729360