csapp cachelab

下载完hand-out没有实验文档,之前的没实验文档看代码注释也知道大概是干嘛的,这次不行,cism.c里面可以说是啥都没有,完全不知道让干嘛,无奈看别人答案才知道原来在wite up里有详细说明,还有提示,受ctf的影响我一直以为那wite up是答案,所以从来没看过,今天下载来看看觉得长得很像课堂ppt,不清楚是不是,如果是的话,那做这个实验还是很有必要听听课的
在这里插入图片描述
看到开局的这一张图感觉好好笑啊,突然好想听听课

part A

这是让实现一个对cache的LRU算法的部分,然后有个测试,根据trace里的数据测试命中次数,然后cache块是二维数组,主要是一些开局的初始化需要看看提供的两个函数,getopt还有fscanf,write up里都有介绍,看一下就懂了,然后就是
1.第一步初始化,init()里初始化出一个二维数组然后还有命中次数,miss次数,数据个数等等的初始化
2对传入进来的参数做回应,这个参数就是运行程序时加入的argc和argv,argc是传入的参数个数,argv是传入的参数数组,对应argv[1],argv[2]…unix-linux编程实践那本书有讲,这种东西应该挺多教linux编程的都会讲,这里有这一步主要是给的样例有这个功能
3一个循环,读取trace中的数据,并根据参数做相应操作,这一步就不用说了,总之就是LRU算法,然后模拟cache操作数据命中或者miss都要基数就是了,最后结果通过原本就有个printSummary,给输出,这是拿到源码文件里面本身就带的,但是记住把里面的000换成对应的参数
4. free空间

代码贴上我觉得别人写的好的一个,我自己写的太烂了来自

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <getopt.h>
#include "cachelab.h"
#define MAX_CACHE_SET 32
#define MAX_CACHE_LINE 32
#define DEBUG 0
int hit_cnt;
int miss_cnt;
int eviction_cnt;
int cmd_cnt;
int s,E,b;
struct cache_line
{
    int valid_bit;        //这个位置是否有数据
    int tag_bit;          //标志位
    int last_time;        //LRU参考
}cache[MAX_CACHE_SET][MAX_CACHE_LINE];

void init();              //初始化
void args_parse(int argc, char *argv[]);    //分析输入参数
void cmd_parse(char *cmd,long long addr);   //分析要执行哪条命令,trace数据对应的命令
void exec_cmd(long long addr);              //执行命令
void addr_parse(long long addr,int *tag_bit,int *set_id);   //存入cache中的哪个位置
int main(int argc,char *argv[]);

void init(){
    hit_cnt=miss_cnt=eviction_cnt=cmd_cnt=0;
    memset(cache,0,sizeof(cache));
    return;
}
void args_parse(int argc, char *argv[]){
    char ch;
    while((ch=getopt(argc, argv,"s:E:b:t:"))!=-1){
        switch (ch)
        {
        case 's':
            s=atoi(optarg);
            break;
        case 'E':
            E=atoi(optarg);
            break;
        case 'b':
            b=atoi(optarg);
            break;
        case 't':
            freopen(optarg, "r", stdin);
        }
    }
    return;
}
void cmd_parse(char *cmd,long long addr){
    switch (cmd[0])
    {
    case 'I':
        break;
    case 'L':
        exec_cmd(addr);
        break;
    case 'S':
        exec_cmd(addr);
        break;
    case 'M':
        exec_cmd(addr);
        exec_cmd(addr);
        break;
    }
    return;
}
void addr_parse(long long addr,int *tag_bit,int *set_id){
    int tmp=0;
    for(int i=0;i<s;i++){               //对数据存放位置的计算,约定
        tmp=(tmp<<1)+1;
    }
    *set_id=((int)(addr>>b)&tmp)%(1<<s);
    *tag_bit=(int)(addr>>(b+s));
    return;
}
void exec_cmd(long long addr){
    int tag_bit,set_id;
    cmd_cnt++;
    addr_parse(addr,&tag_bit,&set_id);
    if(DEBUG) printf("%d %d ",set_id,tag_bit);
    for(int i=0;i<E;i++){
        if((cache[set_id][i].valid_bit)   //命中则return
        &&(cache[set_id][i].tag_bit)==tag_bit
        ){
            cache[set_id][i].last_time=cmd_cnt;
            hit_cnt++;
            if(DEBUG) printf("hit\n");
            return;
        }
    }
    miss_cnt++;
    for(int i=0;i<E;i++){
        if(!cache[set_id][i].valid_bit){    //未命中,且有空位
            cache[set_id][i].valid_bit=1;
            cache[set_id][i].tag_bit=tag_bit;
            cache[set_id][i].last_time=cmd_cnt;
            if(DEBUG) printf("miss\n");
            return;
        }
    }
    eviction_cnt++;                         //未命中且无空位
    int victim_id=0;
    for(int i=0;i<E;i++){
        if(cache[set_id][i].last_time<cache[set_id][victim_id].last_time){
            victim_id=i;                    //求出最早未使用
        }
    }
    cache[set_id][victim_id].tag_bit=tag_bit;   //将其替换
    cache[set_id][victim_id].last_time=cmd_cnt;
    if(DEBUG) printf("miss eviction\n");
    return;
}
int main(int argc,char *argv[])
{
    init();
    args_parse(argc,argv);
    char cmd[10];
    long long addr;
    int blocksize;
    while(~scanf("%s %llx,%d",cmd,&addr,&blocksize)){
        cmd_parse(cmd,addr);                  //对trace中数据格式的分析
    }
    printSummary(hit_cnt, miss_cnt, eviction_cnt);    //输出结果
    return 0;
}

part B

这部分我刚开始没看write up,我当时感觉,对于转置矩阵来说,需要互换位置,也就是两边都要取,即如果要顾着右边横着连续,则左边竖着就无法连续,我有想过分为两次操作,第一次是横着取,把下三角分到另一个同样大小的空间的数组的上三角去,然后再把这个数组中的上三角横着取,放下三角,这样能实现取数据都是在连续的空间取的,当然,存数据不是,但是我觉得存数据不符合局部性应该也还可以
以上是错误思路
看了write up里写了,只有一块cache,单看write up上的说明似乎是让在大数组里分成一块一块的小块来置换,但是具体操作看这没看懂,为了快点结束战斗我去借鉴别人的一下,大意是一次取出多个再一次放入多个,这样存和取都可以用到cache,大致代码就是,

if(N==32&&M==32){
		for(i=0;i<N;i+=8){
			for(j=0;j<M;j+=8){
				for(x=i;x<i+8;x++){
					for(y=j;y<j+8;y++){
						B[y][x]=A[x][y];
					}
				}
			}
		}
	}

不同数据规模照着这个套就了事,好的的优化我就不钻研了,对这块不感兴趣

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值