CSAPP Cache Lab(缓存模拟器)

前言

在这里插入图片描述

理解高速缓存对 C 程序性能的影响,通过两部分实验达成:编写高速缓存模拟器;优化矩阵转置函数以减少高速缓存未命中次数。Part A一开始根本不知道要做什么,慢慢看官方文档,以及一些博客,和B站视频,终于知道是干嘛的了,看完别人的解题方法后,就能自己写出来了。按照我给出的一些链接,完全能搞懂Cache Simulator。Part B给大家推荐了两篇文章。

参考资料:

Lab下载链接,CacheLab官方文档,CacheLab官方课件(强烈推荐阅读),大佬笔记

新发现的宝藏网站

Part A: Writing a Cache Simulator

下面这些描述是我用豆包对官方PDF生成的总结

  • 输入输出接受 Valgrind 内存跟踪文件作为输入,模拟高速缓存的命中 / 未命中行为,输出命中、未命中和驱逐(替换)的总数。
  • 参考模拟器提供csim - ref作为参考模拟器,使用 LRU(最近最少使用)替换策略,命令行参数为Usage:./csim - ref [-hv] - s <s> - E <E> - b <b> - t <tracefile>,其中-h为帮助标志,-v为详细输出标志,-s指定组索引位数,-E指定每行关联度,-b指定块大小位数,-t指定 Valgrind 跟踪文件路径。
  • 编程规则编译无警告;为任意 S、E、b 值正确工作,需用malloc分配存储空间;忽略指令缓存访问(以 “I” 开头的行);在main函数结束时调用printSummary函数输出结果;假设内存访问已正确对齐,忽略 Valgrind 跟踪文件中的请求大小。
  • 提示先在小跟踪文件(如traces/dave.trace)上调试。参考模拟器的-v选项可显示详细的命中、未命中和驱逐信息,建议在csim.c中实现此功能辅助调试。推荐使用getopt函数解析命令行参数,需包含<getopt.h><stdlib.h><unistd.h>头文件。数据加载(L)或存储(S)操作最多导致一次缓存未命中,数据修改(M)操作视为一次加载和一次存储,可能产生两次命中、一次未命中加一次命中或一次未命中加一次命中加一次驱逐。

下面是高速缓存(S, E, B, m)的通用组织。高速缓存是一个高速缓存的数组。每个组包含一个或多个行,每个行包含一个有效位,一些标记位,以及一个数据块。高速缓存的结构将m个地址位划分成了t个标记位,s个索引位和b个块偏移位。详见CSAPP6.4强烈推荐B站视频,看完之后就知道这个实验要做什么了,理解计算机Cache(一):从块到缓存结构,以及逐步推出映射策略和理解计算机Cache(二):缓存与内存的交互。

在这里插入图片描述

下面是看完别人的解法后,又自己写的代码

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

typedef struct cache_line 
{
    int valid_bit; // 有效位
    unsigned tag;  // 标记位
    int stamp;     // 时间戳用于LRU
}cache_line;

// S(2^s)块大小, s组索引.
// E缓存块(2^b)行数, b块偏移.
int S, s, B, b, E;
// 命中,未命中,替换
int hit, miss, eviction;
char *filepath;
cache_line **cache;

void init()
{
    // malloc cache[S][E]
    cache = (cache_line**)malloc(sizeof(cache_line*) * S);
    for (int i = 0; i < S; i++)
        cache[i] = (cache_line*)malloc(sizeof(cache_line) * E);
    for (int i = 0; i < S; i++)
    {
        for (int j = 0; j < E; j++)
        {
            cache[i][j].valid_bit = 0;
            cache[i][j].tag = cache[i][j].stamp = -1; 
        }
    }
}

void destroy()
{
    for (int i = 0; i < S; i++)
        free(cache[i]);
    free(cache);
}

void update(unsigned addr)
{
    int s_addr = (addr >> b) & ((-1U) >> (32 - s));
    int t_addr = (addr >> (s + b));
    // 缓存命中
    for (int i = 0; i < E; i++)
    {
        if (cache[s_addr][i].tag == t_addr)
        {
            cache[s_addr][i].stamp = 0;
            hit++;
            return;
        }
    }
    // 缓存未命中,还有空块
    for (int i = 0; i < E; i++)
    {
        if (cache[s_addr][i].valid_bit == 0)
        {
            miss++;
            cache[s_addr][i].valid_bit = 1;
            cache[s_addr][i].tag = t_addr;
            cache[s_addr][i].stamp = 0;
            return;
        }
    }
    // 没有空组,产生替换
    miss++;
    eviction++; 
    int max_stamp = 0, max_i = 0;
    for (int i = 0; i < E; i++)
    {
        if (cache[s_addr][i].stamp > max_stamp)
        {
            max_stamp = cache[s_addr][i].stamp;
            max_i = i;
        }
    }
    cache[s_addr][max_i].tag = t_addr; 
    cache[s_addr][max_i].stamp = 0;
    return;
}

void time()
{
    for (int i = 0; i < S; i++)
    {
        for (int j = 0; j < E; j++)
        {
            if (cache[i][j].valid_bit == 1) // 被使用了
                cache[i][j].stamp++;
        }
    }
}

int main(int argc, char* argv[])
{
    int opt;
    while (-1 != (opt = getopt(argc, argv, "s:E:b:t:")))
    {
        switch (opt)
        {
        case 's':
            s = atoi(optarg); // optarg是getopt函数设置的指向当前选项参数的指针
            S = 1 << s;
            break;
        case 'E':
            E = atoi(optarg);
            break;
        case 'b':
            b = atoi(optarg);
            B = 1 << b;
            break;
        case 't':
            filepath = optarg;
            break;
        }
    }
    init();
    FILE* pf = fopen(filepath, "r");
    if (pf == NULL)
    {
        printf("fopen fail\n");
        exit(-1);
    }
    char op;
    unsigned addr;
    int size;
    while (fscanf(pf, "%c %x,%d", &op, &addr, &size) > 0)
    {
        switch (op)
        {
        case 'L':
            update(addr);
            break;
        case 'M':   // 执行两次
            update(addr);
        case 'S':
            update(addr);
            break;
        }
        time();
    }
    destroy();
    fclose(pf);
    printSummary(hit, miss, eviction);
    return 0;
}

在这里插入图片描述

Part B: Optimizing Matrix Transpose

  • 函数功能trans.c中编写transpose_submit函数,计算矩阵的转置并存储结果,尽量减少高速缓存未命中次数。
  • 编程规则编译无警告;每个转置函数最多定义 12 个int类型的局部变量,不能使用long类型变量或位技巧规避此规则;函数不能使用递归;使用辅助函数时,辅助函数和顶级转置函数在栈上的局部变量总数不能超过 12 个;不能修改数组 A,可随意处理数组 B;不能定义数组或使用malloc
  • 提示转置函数在直接映射缓存上评估,冲突未命中是潜在问题,需考虑代码中尤其是对角线上的冲突未命中,设计降低冲突未命中的访问模式。分块是减少缓存未命中的有用技术,可参考利用分块提高时间局部性PDF 获取更多信息。测试程序test - trans会保存函数的跟踪文件(如trace.f0等),可通过参考模拟器的-v选项运行跟踪文件辅助调试。

给大家推荐两个写的好的文章,我做不出来…

myk的Cache Lab和马天猫的Cache Lab笔记。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

⽂件操作详解

⽬录 一 文件操作的引入 1 为什么使⽤⽂件&#xff1f; 2 什么是⽂件&#xff1f; 3 文件分类&#xff08;1 从⽂件功能的⻆度来分类&#xff1a;程序⽂件/数据⽂件 2根据数据的组织形式&#xff1a;为⽂本⽂件/⼆进制⽂件&#xff09; 二 ⽂件的打开和关闭 1 …

如何构建一个可扩展、全球可访问的 GenAI 架构?

你有没有尝试过使用人工智能生成图像&#xff1f; 如果你尝试过&#xff0c;你就会知道&#xff0c;一张好的图像的关键在于一个详细具体的提示。 我不擅长这种详细的视觉提示&#xff0c;所以我依赖大型语言模型来生成详细的提示&#xff0c;然后使用这些提示来生成出色的图像…

Python知识点精汇:列表篇精汇!

目录 一、列表是什么 二、列表长什么样 三、列表的基本操作 &#xff08;1&#xff09;访问元素 &#xff08;2&#xff09;列表删除 &#xff08;3&#xff09;增加元素 &#xff08;4&#xff09;修改元素 四、结合一些函数的用法 &#xff08;1&#xff09;最大值、…

基于WEB的房屋出租管理系统设计

摘 要 在当今社会的蓬勃发展的现状下&#xff0c;网络与我们的生活息息相关。工作、生活、休闲我们都利用着网络带给我们 的便捷&#xff0c;网络的发展提供了很多工作机会&#xff0c;众多的人们在不同的城市寻找着合适的工作机会&#xff0c;在此的第一步就是寻 找一个合适自…

【算法day4】链表:应用拓展与快慢指针

题目引用 两两交换链表节点删除链表的倒数第n个节点链表相交环形链表 1.两两交换链表节点 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&am…

电商项目高级篇06-缓存

电商项目高级篇06-缓存 1、docker下启动redis2、项目整合redis3、redis改造三级分类业务 缓存 流程图&#xff1a; data cache.load(id);//从缓存加载数据 If(data null){ data db.load(id);//从数据库加载数据 cache.put(id,data);//保存到 cache 中 } return data;在我们…

osg、osgearth源码编译(二)

如果比较懒&#xff0c;也可以不看这篇文章&#xff0c;网上应该有很多编译好的库。也可以找我要。 本人还是建议学会编译&#xff0c;因为其他人电脑上编译好的&#xff0c;可能在你的电脑环境上&#xff0c;出现这样那样奇怪的问题&#xff0c;所以&#xff0c;最好还是自己能…

Kubernetes 01

MESOS&#xff1a;APACHE 分布式资源管理框架 2019-5 Twitter退出&#xff0c;转向使用Kubernetes Docker Swarm 与Docker绑定&#xff0c;只对Docker的资源管理框架&#xff0c;阿里云默认Kubernetes Kubernetes&#xff1a;Google 10年的容器化基础框架&#xff0c;borg…

中科院一区算法KO-K均值优化算法(K-means Optimizer)-附Matlab免费代码

首先&#xff0c;使用K-means算法在每次迭代中建立聚类区域的形心向量&#xff0c;然后KO提出两种移动策略&#xff0c;以在开发和探索能力之间建立平衡。每次迭代中探索或开发的移动策略的决定取决于一个参数&#xff0c;该参数将被设计为识别每个搜索代理是否在访问的区域中过…

算法复杂度

数据结构 数据结构(DataStructure)是计算机存储、组织数据的⽅式&#xff0c;指相互之间存在⼀种或多种特定关系的数据元素的集合。没有⼀种单⼀的数据结构对所有⽤途都有⽤&#xff0c;所以我们要学各式各样的数据结构&#xff0c;如&#xff1a;线性表、树、图、哈希等 算法…

用Python做数据分析环境搭建及工具使用(Jupyter)

目录 一、Anaconda下载、安装 二、Jupyter 打开 三、Jupyter 常用快捷键 3.1 创建控制台 3.2 命令行模式下的快捷键 3.3 运行模式下快捷键 3.4 代码模式和笔记模式 3.5 编写Python代码 一、Anaconda下载、安装 【最新最全】Anaconda安装python环境_anaconda配置python…

【R库包安装】R库包安装总结:conda、CRAN等

【R库包安装】R studio 安装rgdal库/BPST库 R studio 安装rgdal库解决方法 R studio 安装BPST库&#xff08;github&#xff09;解决方法方法1&#xff1a;使用devtools安装方法2&#xff1a;下载安装包直接在Rstudio中安装 参考 基础 R 库包的安装可参见另一博客-【R库包安装】…

前海湾地铁的腾通数码大厦背后的临时免费停车点探寻

临时免费停车点&#xff1a;前海湾地铁的腾通数码大厦背后的桂湾大街&#xff0c;目前看不仅整条桂湾大街停了​车&#xff0c;而且还有工地餐点。可能是这个区域还是半工地状态&#xff0c;故暂时还不会有​罚单的情况出现。 中建三局腾讯数码大厦项目部A栋 广东省深圳市南山…

Vue3在PC端接入萤石云监控

参考文档&#xff1a;文档概述 萤石开放平台API文档 1.安装依赖 npm i ezuikit-js 2.封装组件 src/components/PlayerVideo/index.vue <template><div id"video-container" style"width: 100%;"></div> </template> <scrip…

YOLO系列论文综述(从YOLOv1到YOLOv11)【第9篇:YOLOv7——跨尺度特征融合】

YOLOv7 1 摘要2 网络架构3 改进点4 和YOLOv4及YOLOR的对比 YOLO系列博文&#xff1a; 【第1篇&#xff1a;概述物体检测算法发展史、YOLO应用领域、评价指标和NMS】【第2篇&#xff1a;YOLO系列论文、代码和主要优缺点汇总】【第3篇&#xff1a;YOLOv1——YOLO的开山之作】【第…

Redis3——线程模型与数据结构

Redis3——线程模型与数据结构 本文讲述了redis的单线程模型和IO多线程工作原理&#xff0c;以及几个主要数据结构的实现。 1. Redis的单线程模型 redis6.0之前&#xff0c;一个redis进程只有一个io线程&#xff0c;通过reactor模式可以连接大量客户端&#xff1b;redis6.0为了…

【C++】STL容器中的比较函数对象

目录 set、map容器 priority_queue容器 在STL中涉及到以某种规则排序的容器都需要比较函数对象&#xff0c;比如&#xff1a;set、map、priority_queue这些容器内部都是依赖比较函数对象以某种规则存储数据的。STL容器中的比较函数对象可以是&#xff1a;函数指针、仿函数(函…

领养我的宠物:SpringBoot开发指南

第2章 开发环境与技术 本章节对开发宠物领养系统需要搭建的开发环境&#xff0c;还有宠物领养系统开发中使用的编程技术等进行阐述。 2.1 Java语言 Java语言是当今为止依然在编程语言行业具有生命力的常青树之一。Java语言最原始的诞生&#xff0c;不仅仅是创造者感觉C语言在编…

南京仁品耳鼻喉专科医院:12月启动公益义诊月

专业医疗资源送至“家门口”&#xff01;南京仁品耳鼻喉专科医院启动公益义诊月 随着2024年即将步入尾声&#xff0c;南京仁品耳鼻喉医院为回馈社会&#xff0c;提升公众健康福祉&#xff0c;将于12月隆重推出“三甲专家公益义诊月”活动。此次活动旨在通过汇聚众多耳鼻喉领域…

centos8:Could not resolve host: mirrorlist.centos.org

【1】错误消息&#xff1a; [rootcentos211 redis-7.0.15]# yum update CentOS Stream 8 - AppStream …