CSAPP fall2015 深入理解计算机系统 Cache lab详解

news2024/11/24 0:43:31

Cache Lab

cache lab 缓存实验

代码下载

从CSAPP上面下载对应的lab代码

http://csapp.cs.cmu.edu/3e/labs.html

环境准备

需要安装 valgrind。可以参考文章Valgrind centos。

安装好以后执行valgrind --version可以看到版本号。

Cache simulator

  • cache simulator not a cache。我们不是实现一个真正的缓存,只是实现一个模拟器。
  • 不存储内容
  • 不使用block offset
  • 只计算命中数,不命中数和驱逐数(hit count, miss count,eviction count)
  • 缓存模拟器需要在不同的s,b,E下运行。
  • 使用LRU替换策略

Hints

  • 使用二维数组 struct cache_line cache[S][E];
  • S = 2^s
  • cache_line //上面说了不需要block offset,所以可以忽略block的内容
    • Valid bit
    • Tag
    • LRU counter
  • 通过getopt获取命令行输入
    • 返回-1表示没有输入了
    • 通常在循环里面接收参数
    • 需要包含#include <unistd.h>,#include <getopt.h>
    • 通常使用switch来处理不同的输入
    • 考虑如何处理无效输入
    • 更多信息 man 3 getopt
  • fscanf可以指定要读的流(scanf只能读标准输入流),用来读取trace file
    • 参数
      • 一个流的指针
      • 如何解析文件的信息的格式化字符串
      • 其余部分是指向存储解析数据的变量的指针
    • 通常在循环里使用
    • 当命中EOF或者没有匹配到格式化字符串的时候返回-1
    • 更多信息 man fscanf
  • Malloc/free
    • malloc分配数据到heap
    • 记得 free 掉malloc的数据
    • 不要 free 你没有分配的内存

在这里插入图片描述

在这里插入图片描述

要求我们实现csim.c文件,给了一个示例csim-ref文件。

输入./csim-ref -h可以看到我们要实现的东西。

在这里插入图片描述

首先需要接受参数,参数有

  • -h 输出帮助信息
  • -v 可选详细标志,根据示例程序来,就是输出 L 10,1 miss这些信息
  • -s [num] set index bit 数
  • -E [num] 每个set的行数
  • -b [num] block offset bit数
  • -t [file] Trace file文件路径

根据上面的提示可以知道,通过getopt函数来接收参数,并通过switch来处理。读取文件则通过fscanf函数,来读取-t传的文件。

下面是./traces/yi.trace文件的内容

 L 10,1
 M 20,1
 L 22,1
 S 18,1
 L 110,1
 L 210,1
 M 12,1
  • L 代表数据载入
  • S 代表数据存储
  • M 代表数据修改,需要一次载入 + 一次存储
  • 后面的10,20,22这些代表地址
  • 最后的1代表操作内存访问的字节数

完整代码

#include "cachelab.h"
#include <unistd.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>

typedef struct{
        int valid;
        int tag;
        int time_stamp;
} cache_line;

int timestamp = 0;

// 开始匹配到合适的set 找到命中的cache,如果命中返回1,如果没有命中返回0
int find_hit_cache(cache_line *cache_line,int E,int tag, int*hits) {
    int isHit = 0;
    // 循环set中的cache_line 找到是否有匹配tag && valid
    for(int i = 0; i < E; i++) {
        if (cache_line[i].valid == 1 && cache_line[i].tag == tag ) {
            //hit
            printf("hit \n");
            *hits = *hits + 1;
            isHit = 1;
            //刷新时间
            cache_line[i].time_stamp = timestamp;
            return isHit;
        }
    }
    return isHit;
}

// 找到一个空的cache line放进去,找到了就返回1,没有找到就返回0
int find_empty_cache(cache_line *cache_line,int E,int tag) {
    int have_empty_cache = 0;
    for (int i = 0; i< E; i++) {
        if (cache_line[i].valid == 0) {
            // 空的
            // 把当前内存放入cache
            cache_line[i].valid = 1;
            cache_line[i].tag = tag;
            cache_line[i].time_stamp = timestamp;
            // 找到了就不需要替换了
            have_empty_cache = 1;
            return have_empty_cache;
        }
    }
    return have_empty_cache;
}

// 获取要替换的索引
int get_eviction_index(cache_line *cache_line, int E) {
    int max_time_stamp = timestamp;
    int eviction_index = -1;
    for (int i = 0; i< E; i++) {
        if (cache_line[i].time_stamp < max_time_stamp) {
            //找到time_stamp最小的那个
            max_time_stamp = cache_line[i].time_stamp;
            eviction_index = i;
        }
    }
    return eviction_index;
}

// LRU替换
void LRU(cache_line *cache_line, int E,int tag) {
    // 获取要替换的索引
    int eviction_index = get_eviction_index(cache_line, E);
    
    // 替换
    cache_line[eviction_index].valid = 1;
    cache_line[eviction_index].tag = tag;
    cache_line[eviction_index].time_stamp = timestamp; 
}

// L和S操作,M就调用两次这个
int load_and_store(unsigned address,int b,int s,int u_max,int E,cache_line **cache, int *hits,int *misses,int *evications) {
    // 获取set index block offset tag
    int set_index,tag;
    set_index = (address >> b) & u_max;
    tag = (address >> b) >> s;

    // 开始匹配到合适的set 找到命中的cache,如果命中返回1,如果没有命中返回0
    int isHit = find_hit_cache(cache[set_index], E, tag, hits);
    if (isHit == 0) {
        // miss
        printf("miss \n");
        *misses = *misses + 1;
        // 找到一个空的cache line放进去,找到了就返回1,没有找到就返回0
        int have_empty_cache = find_empty_cache(cache[set_index], E, tag);
        // 如果没有找到空的cache,就需要LRU替换
        if (have_empty_cache == 0) {
            printf("evictions \n");
            *evications = *evications + 1;
            //LRU替换
            LRU(cache[set_index], E, tag);
        }
    }
    // 更新全局时间戳
    timestamp++;
    return 0;
}

int main(int argc, char** argv)
{
    // 接受参数 getopt
    int opt,v,s,E,b,S,B;
    // 文件
    FILE        *       pFile;
    while(-1 != (opt = getopt(argc, argv, "h?v?s:E:b:t:"))){
        // opt is h,v,s,E,b,t的ASCII码值
        // 通过switch对不同的参数进行不同的处理
        switch(opt) {
            case 'h':
                printf("./csim: Missing required command line argument \n Usage: ./csim-ref [-hv] -s <num> -E <num> -b <num> -t <file> \n Options: \n -h         Print this help message. \n -v         Optional verbose flag. \n -s <num>   Number of set index bits. \n -E <num>   Number of lines per set. \n -b <num>   Number of block offset bits. \n -t <file>  Trace file. \n\n Examples: \n ./csim -s 4 -E 1 -b 4 -t traces/yi.trace \n ./csim -v -s 8 -E 2 -b 4 -t traces/yi.trace \n");
                // h参数输出帮助内容
                break;
            case 'v':
                // v参数输出详细信息
                v = 1;
                printf("v:%d \n",v);
                break;
            case 's':
                // S is set 2^s 的数量
                // s is Number of set index bits
                s = atoi(optarg);
                S = 1 << s;
                printf("s:%d, S:%d \n",s,S);
                break;
            case 'E':
                // E is cache line 的数量
                // Number of lines per set
                E = atoi(optarg);
                printf("E:%d \n",E);
                break;
            case 'b':
                // B is block data 的字节
                // b is Number of block offset bits
                b = atoi(optarg);
                B = 1 << b;
                printf("b:%d, B:%d \n",b,B);
                break;
            case 't':
                // t is Trace file
                // 读取文件
                //t = atoi(optarg);
                pFile   =       fopen(optarg,"r");
                printf("t:%s, file:%p \n",optarg,pFile);
                break;
            default:
                printf("非法参数 \n");
            break;
        }
    }
    if(s == 0 || E == 0 || b == 0) {
        return 0;
    }
    // cache存储
    cache_line **cache = (cache_line **)malloc(S * sizeof(cache_line *));
    if (cache == NULL) {
        printf("内存分配失败 \n");
    }
    for(int i = 0; i < S; i++) {
        cache[i] = (cache_line *)malloc(E * sizeof(cache_line));
        if(cache[i] == NULL) {
                printf("内存分配失败,开始回滚 \n");
                // 在这里需要释放已分配的内存,然后退出
            for (int j = 0; j < i; ++j) {
                free(cache[j]);
            }
            free(cache);
        }
    }

    int u_max = 1; 
    for(int i = 0; i < s - 1; i++) {
        u_max = (u_max << 1) | 1;
    }

    // 读取文件
    char        identifier;
    unsigned    address;
    int         size;
    int hits,misses,evictions;
//      Reading lines   like    "       M       20,1"   or      "L      19,3"
    while(fscanf(pFile," %c %x,%d",&identifier,&address,&size)>0)
    {
        //      Do      stuff
        // 开始计算 hits,misses,evictions, hits:0 misses:0 evictions:0
        //printf("identifier %c, addr:%x, size:%d \n",identifier,address,size);
        
        //根据identifier来判断动作L load S store M = 一次L 一次S
        if (identifier == 'L' || identifier == 'S'){
        printf("identifier %c, addr:%x, size:%d \n",identifier,address,size);
            load_and_store(address,b,s,u_max,E,cache,&hits,&misses,&evictions);
        } else if (identifier == 'M') {
            // 一次L 一次S
        printf("identifier %c, addr:%x, size:%d \n",identifier,address,size);
            load_and_store(address,b,s,u_max,E,cache,&hits,&misses,&evictions);
            load_and_store(address,b,s,u_max,E,cache,&hits,&misses,&evictions);
        }
    }
    
    fclose(pFile);  //remember      to      close   file    when    done
    printSummary(hits, misses, evictions);

    // 释放数组内存
    for(int i = 0; i< S; i++) {
        free(cache[i]);
    }
    free(cache);
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1406047.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

API接口安全总结

接口分类 HTTP接口 RPC接口&#xff08;客户端和服务器端的连接 例如游戏登陆&#xff09;非web协议&#xff0c;PRC 远程过程调用 Remote Procedure Call&#xff0c;其就是一个节点请求另外一个节点提供的服务。当两个物理分离的子系统需要建立逻辑上的关联时&#xff0c;R…

第08章_面向对象编程(高级)(static,单例设计模式,理解mian方法,代码块,final,抽象类与抽象方法,接口,内部类,枚举类,注解,包装类)

文章目录 第08章_面向对象编程(高级)本章专题与脉络1. 关键字&#xff1a;static1.1 类属性、类方法的设计思想1.2 static关键字1.3 静态变量1.3.1 语法格式1.3.2 静态变量的特点1.3.3 举例1.3.4 内存解析 1.4 静态方法1.4.1 语法格式1.4.2 静态方法的特点1.4.3 举例 1.5 练习 …

小土堆pytorch学习笔记001

1、Pytorch环境的配置与安装。 &#xff08;1&#xff09;建议安装&#xff1a;Anaconda &#xff08;2&#xff09;检查显卡&#xff1a;GPU &#xff08;3&#xff09;管理环境&#xff08;不同版本的pytorch 版本不同&#xff09;&#xff1a; conda create -n pytorch…

【开源】基于JAVA+Vue+SpringBoot的农家乐订餐系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 用户2.2 管理员 三、系统展示四、核心代码4.1 查询菜品类型4.2 查询菜品4.3 加购菜品4.4 新增菜品收藏4.5 新增菜品留言 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的农家乐订餐系统&#xff0c…

防御保护----信息安全

网络安全概述 信息安全&#xff1a;防止任何对数据进行未授权访问的措施&#xff0c;或者防止造成信息有意无意泄露、破坏、丢失等问题的发生&#xff0c;让数据处于远离危险、免于威胁的状态和特性。 网络安全&#xff1a;计算机网络环境下的信息安全。 网络安全背景 网络空间…

STM32单片机学习5--STM32中断

文章目录 一、前言二、NVIC中断控制器2.1、NVIC结构体成员2.2、抢占优先级和响应优先级2.3、NVIC的优先级组 三、EXTI外部中断四、中断实战4.1、确定连线4.2、配置中断控制端口4.3、配置中断端口4.4、配置中断服务函数4.5、主函数调用 一、前言 单片机无系统执行逻辑&#xff…

央视:人工智能规模达5000亿元,企业超4400家,生成式AI发展进入快车道

2023年&#xff0c;对世界和中国来讲都是非常不平凡的一年。新一代信息技术&#xff0c;如5G、大数据和云计算&#xff0c;正在引领全球科技和产业变革的潮流。这些技术已经深深地融入了经济社会发展的各个领域&#xff0c;推动信息通信业实现了跨越式的发展。 1、AI助力产业发…

教你三个方法去除图片上的涂鸦快收藏起来吧

在数字时代&#xff0c;我们经常需要在图片上进行各种编辑和修改&#xff0c;以使其符合我们的需求。然而&#xff0c;有时候我们会遇到一些图片上的涂鸦&#xff0c;这些涂鸦不仅影响了图片的美观度&#xff0c;还破坏了图片的整体效果。那么图片上的涂鸦怎么去掉&#xff0c;…

Hive 行列转换

行列转换 列转行 使用 lateral view explode(array|map) 或 lateral view inline(array_struct) 可以将列转换为行。 单列转多行&#xff0c;降维&#xff08;单列数组或键值对&#xff09; 示例1&#xff1a;explode(array(…)) select ..., A from T lateral view exp…

RT-DETR 模型改进 | AKConv:具有任意采样形状和任意参数数量的卷积核

基于卷积操作的神经网络在深度学习领域取得了显著的成果,但标准卷积操作存在两个固有缺陷。一方面,卷积操作受限于局部窗口,无法捕捉其他位置的信息,而其采样形状是固定的。另一方面,卷积核的大小固定为kk,呈固定的正方形形状,而参数数量往往随大小呈平方增长。显然,不…

【Godot4自学手册】第三节设置主人公的动画

继续&#xff0c;今天是第三节&#xff0c;我们主要实现主人公的动画效果&#xff0c;共有两种方法实现动画效果 一、通过AnimationPlayer节点实现动画效果 我们首先在player场景下&#xff0c;player节点下添加AnimationPlayer节点&#xff0c;添加方法是&#xff0c;在play…

嵌入式学习-网络编程-Day6、7

嵌入式学习-网络编程-Day6 一、思维导图 二、作业 1.基于UDP的网络聊天室&#xff08;2024.1.21号前上交&#xff09; 项目需求&#xff1a; 1.如果有用户登录&#xff0c;其他用户可以收到这个人的登录信息 2.如果有人发送信息&#xff0c;其他用户可以收到这个人的群聊信息…

【论文代码】基于隐蔽带宽的汽车控制网路鲁棒认证-到达时间间隔通道的Java实现(二)

文章目录 五、TransmissionThread 抽象类5.1 IAT_thread类5.2 DLC_Thread 六、AttestationProtocol 接口6.1 HardCodedAttestation 七、FilterMash 类7.1 FilterValue 八、其他类8.1 CANAuthMessage8.2 USBtinException8.3 USBtinLibDemo8.4 CANMessage8.5 NoiseThread8.6 Filt…

Vulnhub靶机:FunBox 4

一、介绍 运行环境&#xff1a;Virtualbox 攻击机&#xff1a;kali&#xff08;10.0.2.15&#xff09; 靶机&#xff1a;FunBox 4&#xff08;10.0.2.29&#xff09; 目标&#xff1a;获取靶机root权限和flag 靶机下载地址&#xff1a;https://download.vulnhub.com/funbo…

11.什么档次的原型模式和我写的一样

在《生化危机》系列电影中&#xff0c;克隆人是个频频出现的话题。保护伞公司为了需求复制出另一个战力相当的战士Alice&#xff0c;不惜克隆成百上千个Alice&#xff0c;然而直到最后&#xff0c;非但没有真正克隆出另一个完美的Alice&#xff0c;就连Alice自己也被证实是保护…

华为OD机试之阿里巴巴找黄金宝箱(IV) C++

题目背景 贫如洗的椎夫阿里巴巴在去砍柴的路上&#xff0c;无意中发现了强盗集团的藏宝地&#xff0c;藏宝地有编号从0-N的箱子&#xff0c;每个箱子上面有一人数字&#xff0c;箱子排列成一个环&#xff0c;编号最大的箱子的下一个是编号为0的箱子。请输出每个箱了贴的数字之…

REVIT二次开发万能刷

将这两个参数赋予其他参数 步骤2 将来做个可以调控的版本 using System; using System.Collections.Generic; using System.Lin

常用界面设计组件 —— 数字输入和显示组件

2.3 数字输入和显示组件2.3.1 QSpinBox 与 QDoubleSpinBox2.3.2其它数值输入和显示组件 2.3 数字输入和显示组件 2.3.1 QSpinBox 与 QDoubleSpinBox QSpinBox用于整数的显示和输入&#xff0c;一般显示十进制 数&#xff0c;也可以显示二进制、十六进制数&#xff0c;而且可以…

基于SpringBoot的智慧社区居家养老健康管理系统

文章目录 项目介绍主要功能截图&#xff1a;部分代码展示设计总结项目获取方式 &#x1f345; 作者主页&#xff1a;超级无敌暴龙战士塔塔开 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、 简历模板、学习资料、面试题库【关注我&#xff0c;都给你】 &…

Shell脚本------变量

目录 一、shell脚本的变量 1、shell脚本的变量是什么&#xff1f; 2、变量的作用 3、变量作用范围 3.1、临时设置 3.2永久设置&#xff0c;需要在/etc/profile文件里添加 4、删除变量 5、变量基础 6、变量命名要求 7、特殊符号 8、整数运算 9、expr算术表达式 二、…