Cachelab 高速缓冲器模拟
实验报告
实 验(六)
题 目 Cachelab
高速缓冲器模拟
专 业 计算机科学与技术
csim.c和trans.c代码见文章末尾
目 录
第1章 实验基本信息... - 3 -
1.1 实验目的... - 3 -
1.2 实验环境与工具... - 3 -
1.2.1 硬件环境... - 3 -
1.2.2 软件环境... - 3 -
1.2.3 开发工具... - 3 -
1.3 实验预习... - 3 -
第2章 实验预习... - 5 -
2.1 画出存储器层级结构,标识容量价格速度等指标变化(5分)... - 5 -
2.2用CPUZ等查看你的计算机Cache各参数,写出各级Cache的C S E B s e b(5分)... - 6 -
2.3写出各类Cache的读策略与写策略(5分)... - 6 -
2.4 写出用gprof进行性能分析的方法(5分)... - 7 -
2.5写出用Valgrind进行性能分析的方法((5分)... - 7 -
第3章 Cache模拟与测试... - 9 -
3.1 Cache模拟器设计... - 9 -
3.2 矩阵转置设计... - 12 -
第4章 总结... - 20 -
4.1 请总结本次实验的收获... - 20 -
4.2 请给出对本次实验内容的建议... - 20 -
参考文献... - 21 -
第1章 实验基本信息
1.1 实验目的
理解现代计算机系统存储器层级结构
掌握Cache的功能结构与访问控制策略
培养Linux下的性能测试方法与技巧
深入理解Cache组成结构对C程序性能的影响
1.2 实验环境与工具
1.2.1 硬件环境
X64 CPU;2GHz;2G RAM;256GHD Disk 以上
1.2.2 软件环境
Windows7 64位以上;VirtualBox/Vmware 11以上;Ubuntu 16.04 LTS 64位/优麒麟 64位;
1.2.3 开发工具
Visual Studio 2010 64位以上;TestStudio;Gprof;Valgrind等
1.3 实验预习
了解实验的目的、实验环境与软硬件工具、实验操作步骤,复习与实验有关的理论知识。
用CPUZ等查看你的计算机Cache各参数,写出C S E B s e b
第2章 实验预习
2.1 画出存储器层级结构,标识容量价格速度等指标变化(5分)
从上到下分别为L0 L1 L2 L3 L4 L5 L6 L6
2.2用CPUZ等查看你的计算机Cache各参数,写出各级Cache的C S E B s e b(5分)
2.3写出各类Cache的读策略与写策略(5分)
1:缓存命中,则从cache中读相应数据到CPU或上一级cache中。
2:缓存不命中,则从主存或下一级cache中读取数据,并替换出一行数据。
当CPU写Cache命中时,只修改Cache的内容,而不是立即写入主存;只有当此块被换出时才写回主存。
立即将一个已经缓存了的字w的高速缓存块写回到紧接着的第一层中。。
2.4 写出用gprof进行性能分析的方法(5分)
2.5写出用Valgrind进行性能分析的方法((5分)
--version 显示valgrind内核的版本,每个工具
--tool= [default: memcheck] 最常用的选项。运行valgrind中名为
--db-attach= [default: no] 绑定到调试器上,便于调试错误。
第3章 Cache模拟与测试
3.1 Cache模拟器设计
还有s , E , hit_count , lru_counter等全局变量就不再多说。
initCache()函数 - 分配内存,写0表示有效和标记和LRU,为它们初始化
cache.sets = (cache_set_t*)malloc(S*sizeof(cache_set_t));
cache.sets = (cache_set_t*)malloc(S*sizeof(cache_set_t));//为组申请空间
cache.sets[i].lines = (cache_line_t*)malloc(E*sizeof(cache_line_t));//为行申请空间
freeCache()函数:为释放空间,根据申请空间的倒序来释放即可。
set_index_mask =(addr>>b)&((1<<s)-1); //组索引
在函数中实现时,hit发生的情况:组索引找到的某一组,存在一行有效位为1,并且标记匹配。
再看是否驱逐,驱逐发生的情况为:组索引找到的某一组,有效位全部为1,此时发生evictions++ ,并且找到lru最小的那一行,驱逐。
另外,每次发生hit 或者只miss或者miss加上eviction ,都需要更新那一行的lru数值,具体的就是该行的lru取到最大,其他所有行的lru减一即可
注:每个用例的每一指标5分(最后一个用例10)——与参考csim-ref模拟器输出指标相同则判为正确
3.2 矩阵转置设计
通过对组索引和标记的查看,可以得出:A矩阵和B矩阵相同的下标映射到相同的组中,但是标记不同。这条结论是后面矩阵转置优化的前提。
第二步 64*64 。对于64*64的矩阵而言,每一行元素会占8个组,因此4行元素即可占满cache。
又因为4*4的分块方式无法充分利用每次加载后的块,故也将其否定。
首先将红色块移至目的地,再将黄色块移至红色块左边“暂存”一下。此时移动是伴随着转置的。
再实现图中的移动即可,将黄色块移到红色块的下面,在将绿色快移到之前“暂存”黄色块的地方,最后将灰色块移动到目的地即可。
根据反复调整分块的大小,发现分成17*17的块时miss数最小,代码如下:
/*csim.c 源代码*/
#include <getopt.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <assert.h>
#include <math.h>
#include <limits.h>
#include <string.h>
#include <errno.h>
#include "cachelab.h"//#define DEBUG_ON
#define ADDRESS_LENGTH 64/* Type: Memory address */
typedef unsigned long long int mem_addr_t;/* Type: Cache lineLRU is a counter used to implement LRU replacement policy */
typedef struct cache_line {char valid; //有效位mem_addr_t tag; //标识位int lru; //最后的访问时间距离现在最远的块
} cache_line_t;typedef struct
{cache_line_t *lines;
}cache_set_t; //储存每一组包含的行
typedef struct
{cache_set_t *sets; //cache的空间,模拟cache
}cache_t;/* Globals set by command line args */
int verbosity = 0; /* print trace if set */
int s = 0; /* set index bits */
int b = 0; /* block offset bits */
int E = 0; /* associativity */
char* trace_file = NULL;/* Derived from command line args */
int S; /* number of sets */
int B; /* block size (bytes) *//* Counters used to record cache statistics */
int miss_count = 0;
int hit_count = 0;
int eviction_count = 0;
unsigned long long int lru_counter = 1;/* The cache we are simulating */
cache_t cache;
mem_addr_t set_index_mask; //组索引掩码
mem_addr_t tag_mask; //地址标记
/** initCache - Allocate memory, write 0's for valid and tag and LRU* also computes the set_index_maskinitCache - 分配内存,写0表示有效和标记和LRU ,计算set_index_mask*/
void initCache()
{int i,j;if(s<0){printf("set number error!\n");exit(0);}cache.sets = (cache_set_t*)malloc(S*sizeof(cache_set_t));//为组申请空间if(!cache.sets){printf("No set memory!\n");exit(0);}for(i=0;i<S;i++){cache.sets[i].lines = (cache_line_t*)malloc(E*sizeof(cache_line_t));//为行申请空间if(!cache.sets){printf("No line memory!\n");exit(0);}for(j=0;j<E;j++){cache.sets[i].lines[j].lru=0;cache.sets[i].lines[j].tag=0;cache.sets[i].lines[j].valid=0;}}
}/** freeCache - free allocated memory
*/
void freeCache()
{int i;for(i=0;i<S;i++){free(cache.sets[i].lines);}free(cache.sets);
}/** accessData - Access data at memory address addr.* If it is already in cache, increast hit_count* If it is not in cache, bring it in cache, increase miss count.* Also increase eviction_count if a line is evicted.accessData - 访问内存地址addr的数据。*如果它已经在缓存中,则增加hit_count*如果它不在缓存中,请将其放入缓存中,增加错过次数。*如果一条线被驱逐,也会增加eviction_count*/
void accessData(mem_addr_t addr)
{int i, isfull, j ,k , flag , minlru;isfull=1;for(i=0;i<E;i++){if(cache.sets[set_index_mask].lines[i].valid==1\&&cache.sets[set_index_mask].lines[i].tag==tag_mask){hit_count++;cache.sets[set_index_mask].lines[i].lru=lru_counter;for(k=0;k<E;k++){if(k!=i)cache.sets[set_index_mask].lines[k].lru--;}return;}}miss_count++;for(i=0;i<E;i++){if(cache.sets[set_index_mask].lines[i].valid==0){isfull=0;break;}}if(isfull==0) //未满{cache.sets[set_index_mask].lines[i].valid=1;cache.sets[set_index_mask].lines[i].tag=tag_mask;cache.sets[set_index_mask].lines[i].lru=lru_counter;for(k=0;k<E;k++){if(k!=i)cache.sets[set_index_mask].lines[k].lru--;}}else{eviction_count++;flag = 0;minlru = cache.sets[set_index_mask].lines[0].lru;for(j=0;j<E;j++){if(minlru>cache.sets[set_index_mask].lines[j].lru){minlru = cache.sets[set_index_mask].lines[j].lru;flag = j;}}cache.sets[set_index_mask].lines[flag].valid=1;cache.sets[set_index_mask].lines[flag].tag = tag_mask;cache.sets[set_index_mask].lines[flag].lru=lru_counter;for(k=0;k<E;k++){if(k!=flag)cache.sets[set_index_mask].lines[k].lru--;}}
}/** replayTrace - replays the given trace file against the cachereplayTrace - 针对缓存重放给定的跟踪文件*/
void replayTrace(char* trace_fn)
{char buf[1000];mem_addr_t addr=0;tag_mask=0;unsigned int len=0;FILE* trace_fp = fopen(trace_fn, "r");if(!trace_fp){fprintf(stderr, "%s: %s\n", trace_fn, strerror(errno));exit(1);}while( fgets(buf, 1000, trace_fp) != NULL) {if(buf[1]=='S' || buf[1]=='L' || buf[1]=='M') {sscanf(buf+3, "%llx,%u", &addr, &len);set_index_mask =(addr>>b)&((1<<s)-1); //组索引tag_mask = (addr>>b)>>s; //标记if(verbosity) //赘言printf("%c %llx,%u ", buf[1], addr, len);accessData(addr);/* If the instruction is R/W then access again */if(buf[1]=='M')accessData(addr);if (verbosity) //赘言printf("\n");}}fclose(trace_fp);
}/** printUsage - Print usage info*/
void printUsage(char* argv[])
{printf("Usage: %s [-hv] -s <num> -E <num> -b <num> -t <file>\n", argv[0]);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("\nExamples:\n");printf(" linux> %s -s 4 -E 1 -b 4 -t traces/yi.trace\n", argv[0]);printf(" linux> %s -v -s 8 -E 2 -b 4 -t traces/yi.trace\n", argv[0]);exit(0);
}/** main - Main routine*/
int main(int argc, char* argv[])
{char c;while( (c=getopt(argc,argv,"s:E:b:t:vh")) != -1){switch(c){case 's':s = atoi(optarg);break;case 'E':E = atoi(optarg);break;case 'b':b = atoi(optarg);break;case 't':trace_file = optarg;break;case 'v':verbosity = 1;break;case 'h':printUsage(argv);exit(0);default:printUsage(argv);exit(1);}}/* Make sure that all required command line args were specified确保指定了所有必需的命令行参数 */if (s == 0 || E == 0 || b == 0 || trace_file == NULL) {printf("%s: Missing required command line argument\n", argv[0]);printUsage(argv);exit(1);}/* Compute S, E and B from command line args从命令行参数计算S,E和B. */S = 1<<s; //组数B = 1<<b; //块大小E = E;/* Initialize cache */initCache();replayTrace(trace_file);/* Free allocated memory */freeCache();/* Output the hit and miss statistics for the autograder */printSummary(hit_count, miss_count, eviction_count);return 0;
}
以下是矩阵转置trans.c
/** trans.c - Matrix transpose B = A^T** Each transpose function must have a prototype of the form:* void trans(int M, int N, int A[N][M], int B[M][N]);** A transpose function is evaluated by counting the number of misses* on a 1KB direct mapped cache with a block size of 32 bytes.转置函数是通过对块大小为32字节的1KB直接映射高速缓存上的未命中次数进行计数来评估的。*/
#include <stdio.h>
#include "cachelab.h"int is_transpose(int M, int N, int A[N][M], int B[M][N]);/** transpose_submit - This is the solution transpose function that you* will be graded on for Part B of the assignment. Do not change* the description string "Transpose submission", as the driver* searches for that string to identify the transpose function to* be graded.trans._submit——这是您将针对作业B部分进行评分的解决方案transpose函数不要更改描述字符串“Transpose submission”,因为驱动程序搜索该字符串以标识要分级的转置函数。*/
char transpose_submit_desc[] = "Transpose submission";
void transpose_submit(int M, int N, int A[N][M], int B[M][N])
{int i,j,k,p,temp1,temp2,temp3,temp4,temp5,temp6,temp7,temp8;if(M==32&&N==32){for(i=0;i<M;i=i+8){for(j=0;j<N;j++){temp1 = A[j][i];temp2 = A[j][i+1];temp3 = A[j][i+2];temp4 = A[j][i+3];temp5 = A[j][i+4];temp6 = A[j][i+5];temp7 = A[j][i+6];temp8 = A[j][i+7];B[i][j] = temp1;B[i+1][j] = temp2;B[i+2][j] = temp3;B[i+3][j] = temp4;B[i+4][j] = temp5;B[i+5][j] = temp6;B[i+6][j] = temp7;B[i+7][j] = temp8;}}}if(M==64&&N==64){for(i=0;i<N;i=i+8){for(j=0;j<M;j=j+8){for(k=i;k<i+4;k++){temp1=A[k][j];temp2=A[k][j+1];temp3=A[k][j+2];temp4=A[k][j+3];temp5=A[k][j+4];temp6=A[k][j+5];temp7=A[k][j+6];temp8=A[k][j+7];B[j][k]=temp1;B[j+1][k]=temp2;B[j+2][k]=temp3;B[j+3][k]=temp4;B[j][k+4]=temp5;B[j+1][k+4]=temp6;B[j+2][k+4]=temp7;B[j+3][k+4]=temp8;}for(p=j;p<j+4;p++){temp1=A[i+4][p];temp2=A[i+5][p];temp3=A[i+6][p];temp4=A[i+7][p];temp5=B[p][i+4];temp6=B[p][i+5];temp7=B[p][i+6];temp8=B[p][i+7];B[p][i+4]=temp1;B[p][i+5]=temp2;B[p][i+6]=temp3;B[p][i+7]=temp4;B[p+4][i]=temp5;B[p+4][i+1]=temp6;B[p+4][i+2]=temp7;B[p+4][i+3]=temp8;}for(k=i+4;k<i+8;k++){temp1=A[k][j+4];temp2=A[k][j+5];temp3=A[k][j+6];temp4=A[k][j+7];B[j+4][k]=temp1;B[j+5][k]=temp2;B[j+6][k]=temp3;B[j+7][k]=temp4;}}}}if(M==61&&N==67){for(i=0;i<N;i=i+17){for(j=0;j<M;j=j+17){for(k=i;k<i+17 && k<N;k++){for(p=j;p<j+17 && p<M;p++){temp1 = A[k][p];B[p][k] = temp1;}}}}}
}/** You can define additional transpose functions below. We've defined* a simple one below to help you get started.您可以在下面定义额外的转置函数。下面我们定义了一个简单的方法来帮助您入门。*//** trans - A simple baseline transpose function, not optimized for the cache.一个简单的基线转置函数,没有对缓存进行优化。*/
char trans_desc[] = "Simple row-wise scan transpose";
void trans(int M, int N, int A[N][M], int B[M][N])
{int i, j, tmp;for (i = 0; i < N; i++) {for (j = 0; j < M; j++) {tmp = A[i][j];B[j][i] = tmp;}}}/** registerFunctions - This function registers your transpose* functions with the driver. At runtime, the driver will* evaluate each of the registered functions and summarize their* performance. This is a handy way to experiment with different* transpose strategies.registerFunctions——这个函数向驱动程序注册转置函数。在运行时,驱动程序将评估每个注册函数并总结它们的性能。这是一个方便的实验方法,用不同的转置策略。*/
void registerFunctions()
{/* Register your solution function */registerTransFunction(transpose_submit, transpose_submit_desc);/* Register any additional transpose functions */registerTransFunction(trans, trans_desc);}/** is_transpose - This helper function checks if B is the transpose of* A. You can check the correctness of your transpose by calling* it before returning from the transpose function.IsTrpSPOS-这个辅助函数检查B是否是转置的
*您可以通过调用来检查转置的正确性。
*在从转置函数返回之前。*/
int is_transpose(int M, int N, int A[N][M], int B[M][N])
{int i, j;for (i = 0; i < N; i++) {for (j = 0; j < M; ++j) {if (A[i][j] != B[j][i]) {return 0;}}}return 1;
}
Cachelab 高速缓冲器模拟相关推荐
- 哈工大计算机系统实验六——高速缓冲器模拟
实验报告 实 验(六) 题 目 Cachelab 高速缓冲器模拟 专 业 xxxx 学 号 xxxx 班 级 xxxx 学 生 xxxx 指 导 教 师 x ...
- 高速缓冲器(cache)基本概念
高速缓冲器(cache)基本概念 1. 问题提出 一是由于i/o设备与cpu之间会争访内存,导致降低cpu的效率,则可以在cpu与主存之间加上一级缓存.二是,因为摩尔定律的原因cpu的速度远远高于主存 ...
- cache高速缓冲器
缓存(cache),原始意义是指访问速度比一般随机存取存储器(RAM)快的一种高速存储器,通常它不像系统主存那样使用DRAM技术,而使用昂贵但较快速的SRAM技术.缓存的设置是所有现 ...
- 4.2 linux文件系统-高速缓冲区
1:基本信息 代码:linux-0.11 2:高速缓冲区 高速缓冲区的管理要素 映射关系(内存和磁盘之间的映射关系) 应用程序与高速缓冲区的交互API 磁盘的交互API 高速缓冲区的管理机制(循环链表 ...
- 2020-12-5(操作系统---设备管理)
文章目录 I/O 系统 I/O 设备 设备与控制器之间的接口 设备控制器 I/O通道(I/O Channel) 总线系统 I/O 控制方式 程序I/O(Programmed I/O)方式 中断驱动(I ...
- Linux操作系统原理与应用02:内存寻址
目录 1. 内存寻址 1.1 X86寻址技术演变 1.1.1 8086引入段机制 1.1.2 80286引入保护模式 1.1.3 80386在段寄存器上构建保护模式 1.2 80x86寄存器简介 1. ...
- ======第五章设备管理======
目录 5.1 I/O系统 5.1.1 I/O设备 5.1.2 设备控制器 5.1.3 I/O通道 5.1.4 总线系统 5.2 I/O 控制方式 5.2.1 程序 I/O 方式 5.2.2 中断驱动 ...
- 7系列FPGA数据手册:概述------中文翻译版
7系列FPGA数据手册:概述------中文翻译版 总体介绍 7系列FPGA功能摘要 Spartan-7系列FPGA功能摘要 Artix-7系列FPGA功能摘要 Kintex-7系列FPGA功能摘要 ...
- 闭关六个月整理出来的微机原理知识点(特别适用河北专接本)
专接本交流群:1051749714 (有什么问题欢迎进群讨论) 笔者准备过程中的总结,是通过填空题,简答题等等总结出来的 如有不足,还望大佬们指教 A14运算器 和 控制器 又称为中央处理器(CPU) ...
最新文章
- 安装debian总结以及编译linux内核
- Quartz框架中的Scheduler
- tensorflow实现宝可梦数据集迁移学习
- rgss加密文件解包器_Unity AssetBundle高效加密案例分享
- P2386 放苹果 方法一
- Java Web-网页基础-HTML-CSS
- css 宋体_6.CSS字体属性
- Python全栈学习_day010作业
- 维纳滤波python 函数_图像维纳滤波实现(1)
- 期刊论文发表的格式详细介绍
- 认识CPU的工作原理
- OpenCV-RGB转HSV
- 针对唯一化实例对话框程序,及其命令行操作方法
- 游戏策划学习(二)---游戏策划与开发方法---常见的游戏类型
- 快速摆脱在线扩容难的噩梦?
- com.oracle:ojdbc6:12.1.0.1-atlassian-hosted‘ not found
- 夜神模拟器链接不上ADB问题
- 2021-9-30 背景噪声的研究
- Java获取当前年月日、时间
- 防ddos-shell