CSAPP: cache lab

来源:互联网 发布:周恩来书法 知乎 编辑:程序博客网 时间:2024/06/04 21:03

CSAPP: cache lab

Part A

自制一个符合以下要求的 cache:

  1. sEb 为选项的参数来建立一个 2s 组,每组 E 行,每个块 2b 字节的 cache
  2. t 为选项的参数作为输入文件路径,逐条读入指令
  3. LRU 作为驱逐策略,模拟出 cache 命中、不命中与驱逐行为,并统计各种行为的总数
  4. v 选项的存在与否,决定每条指令的命中情况是否显示
  5. h 选项的存在与否,决定是否显示选项的用法信息

数据结构

链表

用链表来实现 cache 中,每一组的 LRU 驱逐策略

/* 节点结构定义 */typedef struct Node{    int data;    struct Node* next;} Node;/* 新建节点函数 */Node* newNode(int data);/* 链表定义 */typedef struct{    Node* head;    Node* tail;} LList;/* 链表初始化函数 */void initLList(LList* list);/* 尾部插入包含指定数据的节点 */void insertTail(LList* list, int d);/* 删除表头节点,并返回其数据元素 */int deleteFront(LList* list);/* 删除包含指定数据的节点 */void deleteData(LList* list, int d);

/* 行结构定义 */typedef struct{    int v;      // 有效位    int tag;    // 标志} Line;/* 行初始化函数 */void initLine(Line* ln){    ln -> v = 0;    ln -> tag = 0;}/* 行定位函数 */int locateLine(Line* ln,int tag){    if(!ln -> v) return 0;    if(ln -> tag == tag)        return 1;    else        return 0;}/* 加载块函数 */void loadBlock(Line* ln,int tag){    ln -> v = 1;    // 有效位置1    ln -> tag = tag;    // 覆盖标志}

用 LRUList 链表记录组内各行的 LRU 信息

每一次命中或是驱逐,就将相应的行索引号置于表尾

冷不命中,则将新的行索引号插入表尾

驱逐时,被驱逐行的索引号为表头的数据元素,然后调整该链表

/* 组结构定义 */typedef struct{    int E;      // 行数    Line* ln;   // 首行指针    bool isFull;        // 组是否已满    LList* LRUList;     // LRU表                        // 表头元素的值总是组内最近最少使用的行的索引号} Set;/* 组初始化函数 */void initSet(Set* st, int E){    Line* ln = (Line*)malloc(sizeof(Line) * E); // 一组E行    for(int i = 0;i < E;i++){   // 逐行初始化        initLine(ln + i);    }       // 用链表保存各行的最近访问时序    LList* list = (LList*)malloc(sizeof(LList));    initLList(list);    st -> isFull = false;    st -> ln = ln;    st -> E = E;    st -> LRUList = list;}/* 组内空行查找函数 */int findInvalidLine(Set* st){    int n = st -> E;    Line* ln = st -> ln;    for(int i = 0;i < n;i++)        if((ln + i) -> v == 0)            return i;    return -1;}/*  组定位函数     命中,返回1;    冷不命中,返回0    冲突不命中,返回-1;*/int locateSet(Set* st,int tag){    // 命中    int n = st -> E;    for(int i = 0;i < n;i++)        // 是否成功定位在某行        if(locateLine(st -> ln + i, tag)){            // 在LRU表中,删除数据元素i            deleteData(st -> LRUList, i);            // 将行索引号i插入LRU表的尾部            insertTail(st -> LRUList, i);            return 1;        }    // 冷不命中    if(!st -> isFull){        // 查找第一个无效行的索引        int idx = findInvalidLine(st);        // 向该行加载数据块        loadBlock(st -> ln + idx, tag);        // 将行索引号idx插入到LRU表的尾部        insertTail(st -> LRUList, idx);        if(idx == n - 1)    // 组满,更新isFull            st -> isFull = true;        return 0;    }    // 冲突不命中    // 删除LRU表的表头元素,并返回其值给idx    int idx = deleteFront(st -> LRUList);    // 向该驱逐行中,加载新的数据块    loadBlock(st -> ln + idx, tag);    // 将行索引号idx插入到LRU表的尾部    insertTail(st -> LRUList, idx);    return -1;}

Cache

主要被外部调用的函数是 locateCache

接受一个 Cache 的指针和一个 unsigned 地址,对指令中的字节数不做处理,即:默认每次单字节访问

命中,返回 1

冷不命中,返回 0

冲突不命中,返回 -1

/* Cache结构定义 */typedef struct{    int B;  // 块的字节数    int S;  // 组数    Set* st;    // 首组指针} Cache;/* Cache初始化函数 */void initCache(Cache* cache,int S,int E,int B){    Set* st = (Set*)malloc(sizeof(Set) * S);    // S组    for(int i = 0;i < S;i++)    // 初始化每组        initSet(st + i, E);    cache -> st = st;    cache -> S = S;    cache -> B = B;}/* Cache定位函数 */int locateCache(Cache* cache,unsigned addr){    unsigned indexOfBlocks = addr / cache -> B; // 块索引    int CI = indexOfBlocks % cache -> S;    // 组索引    int CT = indexOfBlocks / cache -> S;    // 标记    return locateSet(cache -> st + CI, CT);}

对于行、组、Cache,

每一个层次都定义了其结构和处理函数;

每一层的处理函数,只调用下一层的处理函数;

main函数

选项参数处理

isVisible 对应 -v 选项,为 true时 ,则后续读指令时,输出每一条指令的 cache 行为

hasOpt 为 false,表示不带选项运行,后续输出选项参数的用法,然后返回

S,E,B 对应 -s,-E,-b 选项,解释为 cache 的参数

pFile 对应 -t 选项,接收一个字符串,建立对特定文件的读管道

    bool isVisible = false; // 是否可追踪每条指令的命中情况    bool hasOpt = false;    // 是否有选项    int opt, S, E, B;    FILE* pFile;    while(-1 != (opt = getopt(argc, argv, "s:E:b:t:vh"))){          hasOpt = true;  // 附带选项运行        switch(opt) {             case 's':                S = 1 << atoi(optarg);                break;            case 'E':                E = atoi(optarg);   // 字符串转整数函数                break;            case 'b':                B = 1 << atoi(optarg);                break;            case 'v':                isVisible = true;                break;            case 't':                pFile = fopen(optarg,"r");                break;            case 'h':                printUsage();   // 输出选项用法                return 0;            default:                // 无效选项                printf("Missing required command line argument");                printUsage();   // 输出选项用法                return 0;        }    }    if(!hasOpt){ // 无选项情况        printf("./csim: Missing required command line argument\n");        printUsage();   // 输出选项用法        return 0;    }

读指令,模拟缓存行为

fscanf 将指令操作符、指令地址、操作字节数读入变量 ident,addr,size

t 根据操作符,确定访问 cache 的次数,即:locateCache函数的调用次数

根据 locateCache 的返回值,进行计数

    // 创建cache,并初始化    Cache *c = (Cache*)malloc(sizeof(Cache));    initCache(c,S,E,B);    hit_count = miss_count = eviction_count = 0;    while(fscanf(pFile," %c %x,%d",&ident, &addr, &size) > 0){        int t;  // locateCache函数调用次数                        if(ident == 'L' || ident == 'S')            t = 1;        else if(ident == 'M')            t = 2;        else            t = 0;        if(t == 0)            continue;        if(isVisible)            printf("%c %x,%d",ident, addr, size);        while(t--){            int msg = locateCache(c,addr);            if(msg == 1)                hit_count += 1;            else if(msg == 0)                miss_count += 1;            else{                miss_count += 1;                eviction_count += 1;            }            if(isVisible)                show(msg);        }         if(isVisible)            printf("\n");    }

csim_points

Part B

编写一个函数,进行矩阵转置

void transpose_submit(int M, int N, int A[N][M], int B[M][N]);

满足:

  1. 最多只能定义 12 个局部变量
  2. 不使用任何的数组,不调用任何类似于 malloc 的开辟内存的函数
  3. 测试矩阵的规模为 32 × 32,64 × 64,61 × 67
  4. 测试 cache 的组成:32 组, 每组一行,每个块 32 字节。对于编写的函数,miss 个数越少越好

Version 1

分块处理,尝试 32 × 32,16 × 16,8 × 8,4 × 4 地分块处理

效果最好的是 8×8,大于 8×8 的分块没有效果

其原因是:

测试 cache,每块字节数是 32,也就最多存储 8 个 int;

而低于 8×8 的,则没有有效利用 cache 的块容量大小 。

void transpose_submit_1(int M, int N, int A[N][M], int B[M][N]){    int i, j, ii, jj, tmp;    int n = N / 8 * 8;    int m = M / 8 * 8;    // 分块后可处理的部分:[0,0]~[n-1,m-1]    for (i = 0;i < n; i += 8) {        for (j = 0;j < m;j += 8)             for(ii = 0;ii < 8;ii++)                for(jj = 0;jj < 8;jj++){                    tmp = A[i+ii][j+jj];                    B[j+jj][i+ii] = tmp;                }    }    // 分块后,剩余部分的处理    for(i = n;i < N;i++)        for(j = m;j < M;j++){            tmp = A[i][j];            B[j][i] = tmp;        }    for(i = 0;i < N;i++)        for(j = m;j < M;j++){            tmp = A[i][j];            B[j][i] = tmp;        }    for(i = n;i < N;i++)        for(j = 0;j < M;j++){             tmp = A[i][j];            B[j][i] = tmp;        }}

这里写图片描述

Version 2

在 8 × 8 的基础上,对其平均四分

先处理左上角,再处理右上角,然后处理右下角,最后处理左下角

void transpose_submit_2(int M, int N, int A[N][M], int B[M][N]){    int i, j, ii, jj, tmp;    int n = N / 8 * 8;    int m = M / 8 * 8;    // 分块后可处理的部分:[0,0]~[n-1,m-1]    for (i = 0; i < n; i += 8) {        for (j = 0; j < m; j += 8) {            // 左上角            for(ii = 0;ii < 4;ii++){                for(jj = 0;jj < 4;jj++){                    tmp = A[i+ii][j+jj];                    B[j+jj][i+ii] = tmp;                }            }            // 右上角            for(ii = 0;ii < 4;ii++){                for(jj = 4;jj < 8;jj++){                    tmp = A[i+ii][j+jj];                    B[j+jj][i+ii] = tmp;                }            }            // 右下角            for(ii = 4;ii < 8;ii++){                for(jj = 4;jj < 8;jj++){                    tmp = A[i+ii][j+jj];                    B[j+jj][i+ii] = tmp;                }            }            // 左下角            for(ii = 4;ii < 8;ii++){                for(jj = 0;jj < 4;jj++){                    tmp = A[i+ii][j+jj];                    B[j+jj][i+ii] = tmp;                }            }        }    }      // 分块后,剩余部分的处理      for(i = n;i < N;i++)        for(j = m;j < M;j++){            tmp = A[i][j];            B[j][i] = tmp;        }    for(i = 0;i < N;i++)        for(j = m;j < M;j++){            tmp = A[i][j];            B[j][i] = tmp;        }    for(i = n;i < N;i++)        for(j = 0;j < M;j++){            tmp = A[i][j];            B[j][i] = tmp;        }}

tran_version_2

64 × 64 有了分数,但 32 × 32 和 61 × 67 规模的略有下降

Version 3

在 Version 2 的基础上,引入 4 个局部变量直接处理 A矩阵 4 × 4 规模中的一行

void transpose_submit_3(int M, int N, int A[N][M], int B[M][N]){    int i, j, ii, jj, tmp, tmp1, tmp2, tmp3;    int n = N / 8 * 8;    int m = M / 8 * 8;    // 分块后可处理的部分:[0,0]~[n-1,m-1]    for (i = 0; i < n; i += 8) {        for (j = 0; j < m; j += 8) {            // 左上角            jj = 0;            for(ii = 0;ii < 4;ii++){                tmp = A[i+ii][j+jj];                tmp1 = A[i+ii][j+jj+1];                tmp2 = A[i+ii][j+jj+2];                tmp3 = A[i+ii][j+jj+3];                B[j+jj][i+ii] = tmp;                B[j+jj+1][i+ii] = tmp1;                B[j+jj+2][i+ii] = tmp2;                B[j+jj+3][i+ii] = tmp3;            }            // 右上角            jj = 4;            for(ii = 0;ii < 4;ii++){                tmp = A[i+ii][j+jj];                tmp1 = A[i+ii][j+jj+1];                tmp2 = A[i+ii][j+jj+2];                tmp3 = A[i+ii][j+jj+3];                B[j+jj][i+ii] = tmp;                B[j+jj+1][i+ii] = tmp1;                B[j+jj+2][i+ii] = tmp2;                B[j+jj+3][i+ii] = tmp3;            }            // 右下角            for(ii = 4;ii < 8;ii++){                tmp = A[i+ii][j+jj];                tmp1 = A[i+ii][j+jj+1];                tmp2 = A[i+ii][j+jj+2];                tmp3 = A[i+ii][j+jj+3];                B[j+jj][i+ii] = tmp;                B[j+jj+1][i+ii] = tmp1;                B[j+jj+2][i+ii] = tmp2;                B[j+jj+3][i+ii] = tmp3;            }            // 左下角            jj = 0;            for(ii = 4;ii < 8;ii++){                tmp = A[i+ii][j+jj];                tmp1 = A[i+ii][j+jj+1];                tmp2 = A[i+ii][j+jj+2];                tmp3 = A[i+ii][j+jj+3];                B[j+jj][i+ii] = tmp;                B[j+jj+1][i+ii] = tmp1;                B[j+jj+2][i+ii] = tmp2;                B[j+jj+3][i+ii] = tmp3;            }        }    }        // 分块后,剩余部分的处理    for(i = n;i < N;i++)        for(j = m;j < M;j++){            tmp = A[i][j];            B[j][i] = tmp;        }    for(i = 0;i < N;i++)        for(j = m;j < M;j++){            tmp = A[i][j];            B[j][i] = tmp;        }    for(i = n;i < N;i++)        for(j = 0;j < M;j++){            tmp = A[i][j];            B[j][i] = tmp;        }}

tran_version_3

各个规模的分数均有提升,局部变量的引入效果不错

Version 4

既然引入更多的局部变量,收效不错。

那么改变分块结构,引入更多的局部变量,可能得到更好的效益

题目本身限制,只能引入 12 个局部变量

而 cache 一块最多只能存储 8 个 int,故用于暂存值的局部变量数最大为 8

void transpose_submit_4(int M, int N, int A[N][M], int B[M][N]){    int i, j, tmp, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;    int n = N / 8 * 8;    int m = M / 8 * 8;    // 分块后可处理的部分:[0,0]~[n-1,m-1]    for (j = 0; j < m; j += 8) {        for (i = 0; i < n; i++) {            tmp = A[i][j];            tmp1 = A[i][j+1];            tmp2 = A[i][j+2];            tmp3 = A[i][j+3];            tmp4 = A[i][j+4];            tmp5 = A[i][j+5];            tmp6 = A[i][j+6];            tmp7 = A[i][j+7];            B[j][i] = tmp;            B[j+1][i] = tmp1;            B[j+2][i] = tmp2;            B[j+3][i] = tmp3;            B[j+4][i] = tmp4;            B[j+5][i] = tmp5;            B[j+6][i] = tmp6;            B[j+7][i] = tmp7;        }       }     // 分块后,剩余部分的处理    for(i = n;i < N;i++)        for(j = m;j < M;j++){            tmp = A[i][j];            B[j][i] = tmp;        }    for(i = 0;i < N;i++)        for(j = m;j < M;j++){            tmp = A[i][j];            B[j][i] = tmp;        }    for(i = n;i < N;i++)        for(j = 0;j < M;j++){             tmp = A[i][j];            B[j][i] = tmp;        }}

tran_version_4

32 × 32,61 × 67 规模达到满分;而 64 × 64 则变成了诡异的 0 分

喜忧参半!!!

Version 5

考虑到 Version 3 处理 64 × 64 的效果很好

与 Version 4 综合,就得到了 Version 5,也是提交版本

因为局部变量使用数量的限制,那么牺牲一些可读性,用表达式代替一些中间变量的使用

void transpose_submit(int M, int N, int A[N][M], int B[M][N]){    int i, j, ii, jj, tmp, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;    if(N == 64 && M == 64){        // transpos_submit_3        for (i = 0; i < N / 8 * 8; i += 8) {            for (j = 0; j < M / 8 * 8; j += 8) {                // 左上角                jj = 0;                for(ii = 0;ii < 4;ii++){                    tmp = A[i+ii][j+jj];                    tmp1 = A[i+ii][j+jj+1];                    tmp2 = A[i+ii][j+jj+2];                    tmp3 = A[i+ii][j+jj+3];                    B[j+jj][i+ii] = tmp;                    B[j+jj+1][i+ii] = tmp1;                    B[j+jj+2][i+ii] = tmp2;                    B[j+jj+3][i+ii] = tmp3;                }                // 右上角                jj = 4;                for(ii = 0;ii < 4;ii++){                    tmp = A[i+ii][j+jj];                    tmp1 = A[i+ii][j+jj+1];                    tmp2 = A[i+ii][j+jj+2];                    tmp3 = A[i+ii][j+jj+3];                    B[j+jj][i+ii] = tmp;                    B[j+jj+1][i+ii] = tmp1;                    B[j+jj+2][i+ii] = tmp2;                    B[j+jj+3][i+ii] = tmp3;                }                // 右下角                for(ii = 4;ii < 8;ii++){                    tmp = A[i+ii][j+jj];                    tmp1 = A[i+ii][j+jj+1];                    tmp2 = A[i+ii][j+jj+2];                    tmp3 = A[i+ii][j+jj+3];                    B[j+jj][i+ii] = tmp;                    B[j+jj+1][i+ii] = tmp1;                    B[j+jj+2][i+ii] = tmp2;                    B[j+jj+3][i+ii] = tmp3;                }                // 左下角                jj = 0;                for(ii = 4;ii < 8;ii++){                    tmp = A[i+ii][j+jj];                    tmp1 = A[i+ii][j+jj+1];                    tmp2 = A[i+ii][j+jj+2];                    tmp3 = A[i+ii][j+jj+3];                    B[j+jj][i+ii] = tmp;                    B[j+jj+1][i+ii] = tmp1;                    B[j+jj+2][i+ii] = tmp2;                    B[j+jj+3][i+ii] = tmp3;                }            }        }       }else{        // transpos_submit_4        for (j = 0; j < M / 8 * 8; j += 8) {            for (i = 0; i < N / 8 * 8; i++) {                tmp = A[i][j];                tmp1 = A[i][j+1];                tmp2 = A[i][j+2];                tmp3 = A[i][j+3];                tmp4 = A[i][j+4];                tmp5 = A[i][j+5];                tmp6 = A[i][j+6];                tmp7 = A[i][j+7];                B[j][i] = tmp;                B[j+1][i] = tmp1;                B[j+2][i] = tmp2;                B[j+3][i] = tmp3;                B[j+4][i] = tmp4;                B[j+5][i] = tmp5;                B[j+6][i] = tmp6;                B[j+7][i] = tmp7;            }           }     }    // 分块后,剩余部分的处理    for(i = N / 8 * 8;i < N;i++)        for(j = M / 8 * 8;j < M;j++){            tmp = A[i][j];            B[j][i] = tmp;        }    for(i = 0;i < N;i++)        for(j = M / 8 * 8;j < M;j++){            tmp = A[i][j];            B[j][i] = tmp;        }    for(i = N / 8 * 8;i < N;i++)        for(j = 0;j < M;j++){            tmp = A[i][j];            B[j][i] = tmp;        }}

tran_version_5

目前得到的最好分数 ~_~

附录

### Part A

LList.h

// LList.h#include <stdlib.h>#include <stdio.h>#ifndef LLIST_H#define LLIST_H/* 节点结构定义 */typedef struct Node{    int data;    struct Node* next;} Node;/* 新建节点函数 */Node* newNode(int data){    Node* tmp = (Node*)malloc(sizeof(Node));    tmp -> data = data;    tmp -> next = 0;    return tmp;}/* 链表定义 */typedef struct{    Node* head;    Node* tail;} LList;/* 链表初始化函数 */void initLList(LList* list){    list -> head = list -> tail = newNode(0);}/* 尾部插入包含指定数据的节点 */void insertTail(LList* list, int d){    Node* tmp = newNode(d);    list -> tail -> next = tmp;    list -> tail = list -> tail -> next;}/* 删除表头节点,并返回其数据元素 */int deleteFront(LList* list){    Node* tmp = list -> head -> next;    if(!tmp) return -1;    list -> head -> next = tmp -> next;    int data = tmp -> data;    if(tmp == list -> tail)        list -> tail = list -> head;    free(tmp);    return data;}/* 删除包含指定数据的节点 */void deleteData(LList* list, int d){    Node* curr = list -> head;    Node* tail = list -> tail;    while(curr != tail){        if(curr -> next -> data == d)            break;        curr = curr -> next;    }    if(curr == list -> tail) return;    Node* tmp = curr -> next;    if(tmp == list -> tail)        list -> tail = curr;    curr -> next = tmp -> next;    free(tmp);}/* 输出链表所有节点内的数据 */void print(LList* list){    Node* curr = list -> head;    Node* tail = list -> tail;    printf("< ");    while(curr != tail){        printf("%d ", curr -> next -> data);        curr = curr -> next;    }    printf(">\n");}#endif

Cache.h

// Cache.h#include <stdlib.h>#include <stdbool.h>#include "LList.h"#ifndef CACHE_E#define CACHE_E/* 行结构定义 */typedef struct{    int v;      // 有效位    int tag;    // 标志} Line;/* 行初始化函数 */void initLine(Line* ln){    ln -> v = 0;    ln -> tag = 0;}/* 行定位函数 */int locateLine(Line* ln,int tag){    if(!ln -> v) return 0;    if(ln -> tag == tag)        return 1;    else        return 0;}/* 加载块函数 */void loadBlock(Line* ln,int tag){    ln -> v = 1;    // 有效位置1    ln -> tag = tag;    // 覆盖标志}/* 组结构定义 */typedef struct{    int E;      // 行数    Line* ln;   // 首行指针    bool isFull;        // 组是否已满    LList* LRUList;     // LRU表                        // 表头元素的值总是组内最近最少使用的行的索引号} Set;/* 组初始化函数 */void initSet(Set* st, int E){    Line* ln = (Line*)malloc(sizeof(Line) * E); // 一组E行    for(int i = 0;i < E;i++){   // 逐行初始化        initLine(ln + i);    }       // 用链表保存各行的最近访问时序    LList* list = (LList*)malloc(sizeof(LList));    initLList(list);    st -> isFull = false;    st -> ln = ln;    st -> E = E;    st -> LRUList = list;}/* 组内空行查找函数 */int findInvalidLine(Set* st){    int n = st -> E;    Line* ln = st -> ln;    for(int i = 0;i < n;i++)        if((ln + i) -> v == 0)            return i;    return -1;}/*  组定位函数     命中,返回1;    冷不命中,返回0    冲突不命中,返回-1;*/int locateSet(Set* st,int tag){    // 命中    int n = st -> E;    for(int i = 0;i < n;i++)        // 是否成功定位在某行        if(locateLine(st -> ln + i, tag)){            // 在LRU表中,删除数据元素i            deleteData(st -> LRUList, i);            // 将行索引号i插入LRU表的尾部            insertTail(st -> LRUList, i);            return 1;        }    // 冷不命中    if(!st -> isFull){        // 查找第一个无效行的索引        int idx = findInvalidLine(st);        // 向该行加载数据块        loadBlock(st -> ln + idx, tag);        // 将行索引号idx插入到LRU表的尾部        insertTail(st -> LRUList, idx);        if(idx == n - 1)    // 组满,更新isFull            st -> isFull = true;        return 0;    }    // 冲突不命中    // 删除LRU表的表头元素,并返回其值给idx    int idx = deleteFront(st -> LRUList);    // 向该驱逐行中,加载新的数据块    loadBlock(st -> ln + idx, tag);    // 将行索引号idx插入到LRU表的尾部    insertTail(st -> LRUList, idx);    return -1;}/* Cache结构定义 */typedef struct{    int B;  // 块的字节数    int S;  // 组数    Set* st;    // 首组指针} Cache;/* Cache初始化函数 */void initCache(Cache* cache,int S,int E,int B){    Set* st = (Set*)malloc(sizeof(Set) * S);    // S组    for(int i = 0;i < S;i++)    // 初始化每组        initSet(st + i, E);    cache -> st = st;    cache -> S = S;    cache -> B = B;}/* Cache定位函数 */int locateCache(Cache* cache,unsigned addr){    unsigned indexOfBlocks = addr / cache -> B; // 块索引    int CI = indexOfBlocks % cache -> S;    // 组索引    int CT = indexOfBlocks / cache -> S;    // 标记    return locateSet(cache -> st + CI, CT);}#endif

csim.c

#include <getopt.h>#include <stdio.h>#include <stdlib.h>#include <stdbool.h>#include <stdio.h>#include "cachelab.h"#include "cache.h"void show(int msg){    if(msg == 1)        printf(" hit");    else if(msg == 0)        printf(" miss");    else        printf(" miss eviction");}/* 选项用法打印函数 */void printUsage(){    printf("Usage: ./csim [-hv] -s <num> -E <num> -b <num> -t <file>\n");    printf("Options:\n");    printf("  -h         Print this help message.\n");    printf("  -v         Optional verbose flag.\n");    printf("  -s <num>   Number of set index bits.\n");    printf("  -E <num>   Number of lines per set.\n");    printf("  -b <num>   Number of block offset bits.\n");    printf("  -t <file>  Trace file.\n");    printf("\n");    printf("Examples:\n");    printf("  linux>  ./csim -s 4 -E 1 -b 4 -t traces/yi.trace\n");    printf("  linux>  ./csim -v -s 8 -E 2 -b 4 -t traces/yi.trace\n");}int main(int argc,char *argv[]){     // freopen("test/test.txt","w",stdout);      bool isVisible = false; // 是否可追踪每条指令的命中情况    bool hasOpt = false;    // 是否有选项    int opt, S, E, B;    FILE* pFile;    while(-1 != (opt = getopt(argc, argv, "s:E:b:t:vh"))){          hasOpt = true;  // 附带选项运行        switch(opt) {             case 's':                S = 1 << atoi(optarg);                break;            case 'E':                E = atoi(optarg);   // 字符串转整数函数                break;            case 'b':                B = 1 << atoi(optarg);                break;            case 'v':                isVisible = true;                break;            case 't':                pFile = fopen(optarg,"r");                break;            case 'h':                printUsage();   // 输出选项用法                return 0;            default:                // 无效选项                printf("Missing required command line argument");                printUsage();   // 输出选项用法                return 0;        }    }    if(!hasOpt){ // 无选项情况        printf("./csim: Missing required command line argument\n");        printUsage();   // 输出选项用法        return 0;    }    // 创建cache,并初始化    Cache *c = (Cache*)malloc(sizeof(Cache));    initCache(c,S,E,B);    char ident;    unsigned addr;    int size;    int hit_count, miss_count, eviction_count;    hit_count = miss_count = eviction_count = 0;    while(fscanf(pFile," %c %x,%d",&ident, &addr, &size) > 0){        int t;  // locateCache函数调用次数                        if(ident == 'L' || ident == 'S')            t = 1;        else if(ident == 'M')            t = 2;        else            t = 0;        if(t == 0)            continue;        if(isVisible)            printf("%c %x,%d",ident, addr, size);        while(t--){            int msg = locateCache(c,addr);            if(msg == 1)                hit_count += 1;            else if(msg == 0)                miss_count += 1;            else{                miss_count += 1;                eviction_count += 1;            }            if(isVisible)                show(msg);        }         if(isVisible)            printf("\n");    }    fclose(pFile);     printSummary(hit_count, miss_count, eviction_count);}
原创粉丝点击