zoukankan      html  css  js  c++  java
  • cache lab

    参考链接先挂上,再补

    读书中

    https://zhuanlan.zhihu.com/p/33846811

    PartA

    这相当于一个模拟题目,读入文件后分析是否hit,miss,是否需要eviction。

    开始需要进行分析参数,这里使用了getopt函数。 

      

     1 #include "cachelab.h"
     2 #include<getopt.h>
    3
    #include<stdlib.h> 4 #include<unistd.h> 5 #include<stdio.h> 6 #include<string.h> 7 #include<getopt.h> 8 int s,E,b,S,number_hits,number_miss,number_eviction; 9 char filename[1000]; 10 char buf[1000]; 11 12 typedef struct{ 13 int valid,tag;//有效位,标记 14 int time;//LRU时间标记 15 }cache_line; 16 cache_line **cache = NULL; 17 void update(unsigned address){ 18 int t_addr,s_addr,max_time = -1,max_time_id = 0; 19 s_addr = (address >> b) & ((0x1 << s) - 1);//取出中间s位 20 t_addr = address >> (s + b);//取出前面t位 21 //check if hit检查命中,命中更新时间标记,hits次数 22 for(int i = 0;i < E;i++){ 23 if(cache[s_addr][i].valid == 1 && 24 cache[s_addr][i].tag == t_addr){ 25 cache[s_addr][i].time = 0; 26 number_hits++; 27 return; 28 } 29 } 30 //check if empty检查是否有空行,有就放进去,到这里说明之前没hit,所以miss++ 31 for(int i = 0;i < E;i++){ 32 if(cache[s_addr][i].valid == 0){ 33 cache[s_addr][i].valid = 1; 34 cache[s_addr][i].time = 0; 35 cache[s_addr][i].tag = t_addr; 36 number_miss++; 37 return; 38 } 39 } 40 //no empty没有空行,需要选出淘汰掉 41 number_eviction++; 42 number_miss++; 43 //找出时间最长的行替换掉 44 for(int i = 0;i < E;i++){ 45 if(cache[s_addr][i].time > max_time){ 46 max_time = cache[s_addr][i].time; 47 max_time_id = i; 48 } 49 } 50 cache[s_addr][max_time_id].tag = t_addr; 51 cache[s_addr][max_time_id].time = 0; 52 return; 53 } 54 int main(int argc,char *argv[]) 55 { 56 int opt,temp; 57 number_hits = number_miss = number_eviction = 0; 58 while(((opt = getopt(argc,argv,"hvs:E:b:t:")) != -1)){ 59 switch(opt){ 60 case 'h':system("./cism -s 1 -E 1 -b 1 -t traces/yi2.trace");//具体要求在参考文档有 61 exit(0);break; 62 case 's':s = atoi(optarg);S = (1<<s);break; 63 case 'E':E = atoi(optarg);break; 64 case 'b':b = atoi(optarg);break; 65 case 't':strcpy(filename,optarg); 66 } 67 } 68 FILE* fp = fopen(filename,"r"); 69 if(fp == NULL){//文件打开失败 70 fprintf(stderr,"The file is wrong! "); 71 exit(-1); 72 } 73 //开辟cache
         //cache是二级指针,指向cache;对应一级指针指向每一个组,每组里有许多行 74 cache = (cache_line**)malloc(sizeof(cache_line*) * S); 75 for(int i = 0;i < S;i++){//开辟每个一级指针 76 cache[i] = (cache_line*)malloc(sizeof(cache_line) * E); 77 }//初始化每行 78 for(int i = 0;i < S;i++){ 79 for(int j = 0;j < E;j++){ 80 cache[i][j].valid = 0; 81 cache[i][j].tag = cache[i][j].time = -1; 82 } 83 } 84 unsigned addr; 85 char type; 86 while(fgets(buf,1000,fp)){ 87 sscanf(buf," %c %xu,%d",&type,&addr,&temp); 88 switch(type){ 89 case 'L':update(addr);break;//L操作访问一次cache 90 case 'M':update(addr);
    //L操作访问两次cache
     91             case 'S':update(addr);break;//访问一次cache
     92         }
     93         for(int i = 0;i < S;i++){
     94             for(int j = 0;j < E;j++){
     95                 if(cache[i][j].valid == 1)
     96                     cache[i][j].time++;//使用LRU算法,time作为标记
     97             }
     98         }
     99     }
    100     for(int i = 0 ;i < S;i++){
    101         free(cache[i]);
    102     }
    103     free(cache);
    104     fclose(fp);
    105     printSummary(number_hits, number_miss, number_eviction);
    106     return 0;
    107 }                                                                                                                                                                                                                            

     链接:https://zhuanlan.zhihu.com/p/28585726

    Part B

    没大看懂。。

    怎么估算的B的miss次数

    part B是优化矩阵转置算法,使用分块让Cache的miss次数尽量少。

    题目给的Cache大小只有 1024B,s=5,E=1,b=5。

    给的数据大小分别是32×32,64×64,61×67

    只能只用12个int变量。

    32×32

    第一题要求miss次数在300以下。

    Cache的一个块只有32B,也就是只能容纳8个int。即容纳这个matrix的前8行。

    分块的话,肯定是取8×8的比较合适。先读取A的一行,然后放入B的一列。

    对于在对角线上的块,A中每读一行,会有一次miss,也就是miss次数是读取操作的1/8,对于B数组的话,第一次读取这行会产生一次miss,之后对于第i行,只有A中读到第i行的时候,会被移除出Cache,然后存的时候会产生一次miss。可以粗略计算为miss次数是读取次数的1/4。

    对于不在对角线上的块,做转置的时候,A还是1/8的miss率,B的每行在Cache中和A的行不冲突 ,所以也是1/8的miss率。

    大概是 4	imes 64	imes(frac{1}{8}+frac{1}{4})+12	imes 64	imes2	imesfrac{1}{8}=288

    64×64

    1300次以下。

    Cache中只能放4行A中的行,如果再用8×8的块,前面4行可以填入,后面4行会在Cache中发生冲突,导致miss次数增加。

    如果只用4×4的块呢?那么每次Cache中放入8个int,却只用4个,浪费严重。

    引用:

    1.先考虑把A的上半部分存入到B,但是为了考虑Cache不冲突,所以把右上角的4×4的区域也存在B的右上角。对于在对角线上的块,A的miss率是1/8,B的左上角部分miss率是1/2。对于不在对角线上的块,A的miss率还是1/8,B左上角部分的miss率为1/4.

    2. 接下来这步是减少miss率的关键,把A左下角的一列4个数据读出,B右上角的一行4个数据读出,都用int变量暂存,然后把前四个填入B右上角行中,后四个填入B的左下角行中。

    因为从B右上角读取的时候,把块放入了Cache,然后从A往B中填的时候,就不会出现miss操作。

    来计算一下miss率,对于在对角线上的块,从A左下角读取miss率为1,B的右上角的操作miss率为1/4,B的左下角miss率为1/4。对于不在对角线的快,A的miss率为1/4,B右上角miss率为0,左下角miss率为1/4。

    3. 最后一步就是把A的右下角填入B的右下角,对于在对角线上的块,A的miss率为1/4,B的miss率为1/2.不在对角线上的块,A,B的miss率都为0.

    最后我们来计算下miss的次数吧,计算出来近似是1280次,实际我们代码跑出来是1219次 。

     

    61×67

    用16*16可以解决

    void transpose_submit(int M, int N, int A[N][M], int B[M][N])
    {   
        int a1,a2,a3,a4,a5,a6,a7,a8;
        int i,j,k,h;
        if(N==32){//第一种情况32*32
            for(i=0;i<4;i++){
                for(j=0;j<4;j++){
    //分块8*8
                    for(k=i*8;k<(i+1)*8;k++){
                        h=j*8;
                        a1=A[k][h];a2=A[k][h+1];a3=A[k][h+2];a4=A[k][h+3];
                        a5=A[k][h+4];a6=A[k][h+5];a7=A[k][h+6];a8=A[k][h+7];
    
                        B[h][k]=a1;B[h+1][k]=a2;B[h+2][k]=a3;B[h+3][k]=a4;
                        B[h+4][k]=a5;B[h+5][k]=a6;B[h+6][k]=a7;B[h+7][k]=a8;
                    }
                }
            }
        }
        else if(N==64){//第二种64*64
            for(i=0;i<64;i+=8){
                for(j=0;j<64;j+=8){//每个块是8*8
                    for(k=j;k<j+4;++k){//先处理A上半部分4*8
                        a1=A[k][i];a2=A[k][i+1];a3=A[k][i+2];a4=A[k][i+3];
                        a5=A[k][i+4];a6=A[k][i+5];a7=A[k][i+6];a8=A[k][i+7];
    
                        B[i][k]=a1;B[i][k+4]=a5;B[i+1][k]=a2;B[i+1][k+4]=a6;
                        B[i+2][k]=a3;B[i+2][k+4]=a7;B[i+3][k]=a4;B[i+3][k+4]=a8;                               
                    }
                    for(k=i;k<i+4;++k){//处理A左下角
                        a1=B[k][j+4];a2=B[k][j+5];a3=B[k][j+6];a4=B[k][j+7];
                        a5=A[j+4][k];a6=A[j+5][k];a7=A[j+6][k];a8=A[j+7][k];
    
                        B[k][j+4]=a5;B[k][j+5]=a6;B[k][j+6]=a7;B[k][j+7]=a8;
                        B[k+4][j]=a1;B[k+4][j+1]=a2;B[k+4][j+2]=a3;B[k+4][j+3]=a4;
                    }
                    for(k=i+4;k<i+8;++k){//处理A右下角
                        a1=A[j+4][k];a2=A[j+5][k];a3=A[j+6][k];a4=A[j+7][k];
    
                        B[k][j+4]=a1;B[k][j+5]=a2;B[k][j+6]=a3;B[k][j+7]=a4;
                    }
                }
            }
        }
        else{//最后一种 61*67
            for(i=0;i<N;i+=16){
                for(j=0;j<M;j+=16){
        //16*16分块
                    for(k=i;k<i+16&&k<N;k++){
                        for(h=j;h<j+16&&h<M;h++){
                            B[h][k]=A[k][h];
                        }
                    }
                }
            }
        }
    }
  • 相关阅读:
    兼容IE的滚动条自定义样式
    vue从入门到开发--4--处理http请求
    vue从入门到开发--3-基础语法
    Oracle 扩容表空间
    Oracle 整库备份还原
    Oracle 相关命令
    更改mysql数据库根目录
    关于文件系统
    挂载iscsi存储
    挂载nfs存储
  • 原文地址:https://www.cnblogs.com/gudygudy/p/10447379.html
Copyright © 2011-2022 走看看