欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2024-03-04 10:20:47
...

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++;}
}

 

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

                                                   图1 程序的内存分布

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

                                                   图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不命中....嗯,需要尝试一下其他的映射方式了

memory 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遍历一遍了,不太好。嗯,再考虑另外一种映射方案吧

memory 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里面,并且查找也要快速。

相关标签: default