免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 948 | 回复: 0
打印 上一主题 下一主题

cpu cache 学习 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-07-14 11:51 |只看该作者 |倒序浏览

计算机中cache的概念无处不在,buffer大多是指软件缓存,而cache多指硬件缓存,我把buffer和cache理解为同一个概念。
经过几天的学习,对cpu cache有点了解,把学习过程记录下来。

cache位于cpu和存储器之间
CPU -fast-> CACHE -slow-> MEMORY
每当cpu执行的指令需要访问存储器时,给出物理地址在地址总线上,cache控制器会根据这个地址判断是否访问的地址中的内容已经在cache中(方式如下),如果存在那么直接把内容传递给cpu,否则从memory中读取CACHE_LINE_SIZE字节大小的数据,这个读取比较慢,具体读写可以优化,选择一个cache中的line放置读取的内容,具体替换的算法不说了。写存储器原理是一样的。

那么怎么根据地址判断是否在cache中呢?以我的机器为例子,奔腾3.0G,memory为512M,也就是0x20000000(2^29),cache的大小为1M(/proc/cpuinfo),CACHE_LINE_SIZE为128字节(1
所以cache line的个数为2^20/2^7 == 2^13 == 8096。
而memory又有多少个cacheline大小的块呢?2^29/2^7 == 2^22

很显然,并不是所有的内容都能放到cache中,1/512 的内容在cache中。 好了,可以说说为怎么判断是否在cache中了(cache命中)举例说明:
当访问256M+1K处的地址时,物理地址值为0x100,00400,看看低20位(由1Mcache计算出来的,所以是20不是21或18)为0000,0000,0100,0000,0000,这下好了,cache控制器知道,如果它在,那么只能在cache中的哪一块呢,01000(低7位不影响,只是偏移),所以硬件电路直接访问那一块,那么如果这个cache块有效,它是对应,0x100,00400(256M+1K),还是0x10,00400(16M+1K),还是其它的呢?对了,这下缓冲管理有个目录,里面,记录了一个称为tag的12bit的值,对于上述例子,如果这个值为0x100那么就表明这个块缓冲着256M+1K的内容了。否则(比如0x010)不是(cache缺失)。
显然,缺失了就要把这个块用真正的内容替换掉,如果必要把内容写回到memory 16M+1K,再读进256M+1K的 128字节到这个块中。接下来的传输到cpu和命中是一样的。这样如果接下来又要访问16M+1K的内容呢,再替换呗,再256M+1K呢,再换,再16M+1K,再换,这就是颠簸啦,可是谁会访问的地址高位(20以上)会变化如此的频繁呢,是的不会,这就是局部性原理,和颠簸是相反的概念。只要前面12位不变(在同一个M内),那么就不会颠簸了。
但是也有可能会有地址变动很大的可能,比如把一块数据从16M copy 到256M,偶尔还是很有可能的把,所以就有了N-WAY,就是说中间13为相同并不一定只是映射到同一个cache line中,可以映射到N个块中,比如N == 2,那么当映射完16M+1K时要映射256M+1K,那么会发现,还有个槽可以映射,那么就不会颠簸了,同理,增大N可以减小更多的颠簸,比如需要检查16M+1k和15M+1K(同样的中间13位),是否相等,再决定是否要copy到256M+1K中。 这下N == 2,还是会颠簸。但是N=4一般就足够了,偶尔不够的可能性就非常小了,不是吗,局部性原理。当然对于1M的cache,N>1之后,2*13次方个函数值就会减少到1/2^(N-1)了。不过,还是因为局部性原理,有什么关系呢。
上述并不一定正确,而且很多细节没有说到,但是网上很多说cache的文章(中文的不多),找个再看看,这里主要描述的主要是我对cache的地址怎么映射的理解,也没有说多级映射,我没太了解。看看下面的例子吧,跑一跑,我自己想出来的,^^,可以根据自己的处理器快慢设置times,时间差大概为50-100倍,因为fine==0时一直在颠簸。通过下面的例子,我相信应该能写出来一个程序,在处理器主频差不多但是cache不一样的机器上跑快慢相差50倍,为什么呢,让程序在小cache的机器上颠簸而大的不颠簸。比如操作的数据总和介于大小cache之间


#include stdlib.h>
#define TIMES 50
char buf1[128][40960];
char buf2[128][40960];
int main(int argc,char *argv[])
{
    int i,j;
    int times = 0;
    int fine = 1;
    if (argc == 2)
        fine = atoi(argv[1]);
    if(fine) {
        while(times++  TIMES)
            for(i=0;isizeof(buf1)/sizeof(buf1[0]);++i)
                for(j=0;jsizeof(buf1[0]);++j) {
                    buf1[j] = buf2[j];
                }
    } else {
        while(times++  TIMES)
            for(j=0;jsizeof(buf1[0]);++j)
                for(i=0;isizeof(buf1)/sizeof(buf1[0]);++i) {
                    buf1[j] = buf2[j];
                }
    }
    return 0;
}


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/43233/showart_339984.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP