实验报告

验(六)

题     目 Cachelab

高速缓冲器模拟 

专       业 xxxx

学     号 xxxx

班     级 xxxx

学       生 xxxx     

指 导 教 师 xxxx    

实 验 地 点 G712     

实 验 日 期 2019.12.7   

计算机科学与技术学院

目  录

第1章 实验基本信息............................................................................................. - 3 -

1.1 实验目的......................................................................................................... - 3 -

1.2 实验环境与工具............................................................................................. - 3 -

1.2.1 硬件环境................................................................................................. - 3 -

1.2.2 软件环境................................................................................................. - 3 -

1.2.3 开发工具................................................................................................. - 3 -

1.3 实验预习......................................................................................................... - 3 -

第2章 实验预习..................................................................................................... - 4 -

2.1 画出存储器层级结构,标识容量价格速度等指标变化(5分).............. - 4 -

2.2用CPUZ等查看你的计算机Cache各参数,写出各级Cache的C S E B s e b(5分)........................................................................................................... - 4 -

2.3写出各类Cache的读策略与写策略(5分)............................................. - 4 -

2.4 写出用gprof进行性能分析的方法(5分).............................................. - 4 -

2.5写出用Valgrind进行性能分析的方法((5分)...................................... - 4 -

第3章 Cache模拟与测试................................................................................. - 5 -

3.1 Cache模拟器设计......................................................................................... - 5 -

3.2 矩阵转置设计................................................................................................. - 5 -

第4章 总结............................................................................................................. - 6 -

4.1 请总结本次实验的收获................................................................................. - 6 -

4.2 请给出对本次实验内容的建议..................................................................... - 6 -

参考文献................................................................................................................... - 7 -

第1章 实验基本信息

1.1 实验目的

理解现代计算机系统存储器层级结构

掌握Cache的功能结构与访问控制策略

培养Linux下的性能测试方法与技巧

深入理解Cache组成结构对C程序性能的影响

1.2 实验环境与工具

1.2.1 硬件环境

X64 CPU2GHz2G RAM256GHD Disk 以上

1.2.2 软件环境

Windows7 64位以上;VirtualBox/Vmware 11以上;Ubuntu 16.04 LTS 64/优麒麟 64位;

1.2.3 开发工具

Visual Studio 2010 64位以上;TestStudioGprof;Valgrind

1.3 实验预习

上实验课前,必须认真预习实验指导书(PPT或PDF)

了解实验的目的、实验环境与软硬件工具、实验操作步骤,复习与实验有关的理论知识。

画出存储器的层级结构,标识其容量价格速度等指标变化

用CPUZ等查看你的计算机Cache各参数,写出C S E B s e b

写出Cache的基本结构与参数

写出各类Cache的读策略与写策略

掌握Valgrind与Gprof的使用方法

第2章 实验预习

2.1 画出存储器层级结构,标识容量价格速度等指标变化(5分)

2.2用CPUZ等查看你的计算机Cache各参数,写出各级Cache的C S E B s e b(5分)

C        S     E      B       s       e

一级数据缓存:   32KB      8    64      8       3       6

一级指令缓存:   32KB      8    64      8       3       6

二级指令缓存:   256KB     4    64     128      2       6

三级指令缓存:    9MB     12    64    12288    log12    6

2.3写出各类Cache的读策略与写策略(5分)

Cache读策略

1:缓存命中,则从cache中读相应数据到CPU或上一级cache中。

2:缓存不命中,则从主存或下一级cache中读取数据,并替换出一行数据。

Cache写策略

1、写回

当CPU写Cache命中时,只修改Cache的内容,而不是立即写入主存;只有当此块被换出时才写回主存。

2、直写

立即将一个已经缓存了的字w的高速缓存块写回到紧接着的第一层中。。

3、写分配

加载相应的低一层的块到高速缓存中,然后更新这个高速缓存块。

4、非写分配

避开高速缓存,直接把这个字写到低一层中去。

2.4 写出用gprof进行性能分析的方法(5分)

gprof是GNU profile工具,可以运行于linux、AIX、Sun等操作系统进行C、C++、Pascal、Fortran程序的性能分析,用于程序的性能优化以及程序瓶颈问题的查找和解决。通过分析应用程序运行时产生的“flat profile”,可以得到每个函数的调用次数,每个函数消耗的处理器时间,也可以得到函数的“调用关系图”,包括函数调用的层次关系,每个函数调用花费了多少时间。使用步骤如下:

(1)用gcc、g++、xlC编译程序时,使用-pg参数,如:g++ -pg -o test.exe test.cpp编译器会自动在目标代码中插入用于性能测试的代码片断,这些代码在程序运行时采集并记录函数的调用关系和调用次数,并记录函数自身执行时间和被调用函数的执行时间。

(2)执行编译后的可执行程序,如:./test.exe。该步骤运行程序的时间会稍慢于正常编译的可执行程序的运行时间。程序运行结束后,会在程序所在路径下生成一个缺省文件名为gmon.out的文件,这个文件就是记录程序运行的性能、调用关系、调用次数等信息的数据文件。

(3)使用gprof命令来分析记录程序运行信息的gmon.out文件,如:gprof test.exe gmon.out则可以在显示器上看到函数调用相关的统计、分析信息。上述信息也可以采用gprof test.exe gmon.out> gprofresult.txt重定向到文本文件以便于后续分析.

2.5写出用Valgrind进行性能分析的方法(5分)

Valgrind是运行在Linux上一套基于仿真技术的程序调试和分析工具,它包含一个内核──一个软件合成的CPU,和一系列的小工具,每个工具都可以完成一项任务──调试,分析,或测试等。Valgrind可以检测内存泄漏和内存违例,还可以分析cache的使用等。Valgrind包含以下工具:Memcheck(用来检测程序中出现的内存问题,所有对内存的读写都会被检测到,一切对malloc()/free()/new/delete的调用都会被捕获)、Callgrind(收集程序运行时的一些数据,建立函数调用关系图,还可以有选择地进行cache模拟。在运行结束时,它会把分析数据写入一个文件,callgrind_annotate可以把这个文件的内容转化成可读的形式)、Cachegrind(模拟CPU中的一级缓存I1,Dl和二级缓存,能够精确地指出程序中cache的丢失和命中。如果需要,它还能够为我们提供cache丢失次数,内存引用次数,以及每行代码,每个函数,每个模块,整个程序产生的指令数)、Helgrind(用来检查多线程程序中出现的竞争问题)、Massif(堆栈分析器,能测量程序在堆栈中使用了多少内存,告诉我们堆块,堆管理块和栈的大小)。Valgrind的使用非常简单,valgrind命令的格式如下:valgrind [valgrind-options] your-prog [your-prog options] 。一些常用的选项如下:

选项                              作用

-h --help                                               显示帮助信息

--version                                 显示valgrind内核的版本,每个工具都有各自的                                           版本

-q --quiet                                安静地运行,只打印错误信息

-v --verbose                           打印更详细的信息。

--tool= [default: memcheck]             最常用的选项。运行valgrind中名为toolname                               的工具。如果省略工具名,默认运行memcheck。

--db-attach= [default: no]                       绑定到调试器上,便于调试错误。

第3章 Cache模拟与测试

3.1 Cache模拟器设计

提交csim.c(如下图所示)


/*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("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;}

程序设计思想:

1.分析一下实验的内容和需要做的事

通过ppt可知,我们需要编写一个cache模拟器,该模拟器可以模拟在一系列的数据访问中cache的命中、不命中与牺牲行的情况,其中,需要牺牲行时,用LRU替换策略进行替换。

cache模拟器需要能处理一系列如下的命令:

Usage: ./csim-ref [-hv] -s <s> -E <E> -b <b> -t <tracefile>

其中各参数意义如下:

①-h:输出帮助信息的选项;

②-v:输出详细运行过程信息的选项;

③-s:组索引的位数(意味着组数S=2^s);

④-E:每一组包含的行数;

⑤-b:偏移位的宽度(意味着块的大小为B=2^b);

⑥-t:输入数据文件的路径(测试数据从该文件里面读取)。

2.分析测试数据

traces文件夹里面包含五个文件:

这五个文件就是用于测试csim.c的输入文件,各个文件中包含了各种不同指令,用于测试hits、missses、evictons。

trace文件中的指令具有如下形式:

I 0400d7d4,8

M 0421c7f0,4

L 04f6b868,8

S 7ff0005c8,8

即每行代表一个或两个内存访问。每行的格式是

[空格]操作 地址,大小

操作字段表示存储器访问的类型,其中:

“I”表示指令加载,

“L”表示数据加载,

“S”表示数据存储,

“M”表示数据修改(即数据存储之后的数据加载)。

每个“I”前面都没有空格。每个“M”,“L”和“S”之前总是有空格。

地址字段指定一个32位的十六进制存储器地址。

大小字段指定操作访问的字节数;

通俗地解释一下各种操作:

①对于‘I’指定地操作,实验说明中提到,我们不需要考虑:

意思就是valgrind运行地时候第一个指令总是为操作‘I’。

②对于‘L’以及‘S’指定的操作,我们简单地可以认为这两个操作都是对某一个地址寄存器进行访问(读取或者存入数据);

③对于‘M’指定的操作,可以看作是对于同一地址连续进行‘L‘和’S‘操作。

以yi.trace中的数据为例:

其解释如下:

①对于地址0x10进行访问

0x10=0000...00010000,偏移值为最低四位,故S=1;

访问结果为mis;

②连续对地址0x20进行连续两次访问:

0x20=000...00100000,S=2;

结果为第一次mis,第二次hit;

③对地址0x22进行访问:

0x22=000...00100100,S=2;

由于操作②以将该块存入高速缓存,故结果为hit;

④对地址0x18进行访问:

0x18=000...00011000,S=1;

由于操作①以将该块存入高速缓存,故结果为hit;

⑤对地址0x110进行访问:

0x110=0...000100010000,S=1;

虽然操作①使得第一组(只有一行有效),但是这里的标志位的值Tag为1

故结果为先mis,后eviction;

⑥对地址0x210进行访问:

0x210=0...001000010000,S=1;

同操作⑤,但是这里的标志位的值为2,不匹配

故结果为先mis,后evicton;

⑦对地址0x12进行连续两次访问:

0x12=000...00000010010,S=1;

由于标志位不匹配,故第一次访问时mis,并evicton

第二次访问时当然就是hit。

上述分析也就是解释了实验说明中的示例:

3.分析一下csim.c的主要函数功能

(1)Cache结构体的声明:

(2)分析主要函数

在主函数中从命令行参数计算S,E和B. 如下:

S = 1<<s;   //组数

B = 1<<b;   //块大小

E = E;

  1. 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));//为行申请空间

  1. freeCache()函数:为释放空间,根据申请空间的倒序来释放即可。

(3)void replayTrace(char* trace_fn) :此函数基本已经全部给出,主要的就是从trace文件中读取数据,并且调用accessdata函数,操作类型若为 'L'或 'S',则调用一次accessdata,若为 'M' ,则多调用一次accessdata 。 另外在次函数中读取了地址addr之后,可以计算出组索引和标记:

set_index_mask =(addr>>b)&((1<<s)-1);  //组索引

tag_mask = (addr>>b)>>s;           //标记

(4)accessData - 访问内存地址addr的数据。

1)如果它已经在缓存中,则增加hit_count

2)如果它不在缓存中,请将其放入缓存中,增加错过次数。

3)如果一条线被驱逐,也会增加eviction_count

在函数中实现时,hit发生的情况:组索引找到的某一组,存在一行有效位为1,并且标记匹配。

若不hit ,则直接miss++。

再看是否驱逐,驱逐发生的情况为:组索引找到的某一组,有效位全部为1,此时发生evictions++ ,并且找到lru最小的那一行,驱逐。

另外,每次发生hit 或者只miss或者miss加上eviction ,都需要更新那一行的lru数值,具体的就是该行的lru取到最大,其他所有行的lru减一即可

4.程序的测试

测试用例1的输出截图(5分):

测试用例2的输出截图(5分):

测试用例3的输出截图(5分):

测试用例4的输出截图(5分):

测试用例5的输出截图(5分):

测试用例6的输出截图(5分):

测试用例7的输出截图(5分):

测试用例8的输出截图(10分):

注:每个用例的每一指标5分(最后一个用例10——与参考csim-ref模拟器输出指标相同则判为正确

3.2 矩阵转置设计

/* * 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.*/
#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. */
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,t0,t1,t2,t3,t4,t5,t6,t7,t8;if(M==32&&N==32){for(i=0;i<M;i=i+8){for(j=0;j<N;j++){t1 = A[j][i];t2 = A[j][i+1];t3 = A[j][i+2];t4 = A[j][i+3];t5 = A[j][i+4];t6 = A[j][i+5];t7 = A[j][i+6];t8 = A[j][i+7];B[i][j] = t1;B[i+1][j] = t2;B[i+2][j] = t3;B[i+3][j] = t4;B[i+4][j] = t5;B[i+5][j] = t6;B[i+6][j] = t7;B[i+7][j] = t8;}}}for(i=0;i<64;i+=8){for(j=0;j<64;j+=8){for(k=j;k<j+4;k++){t0=A[k][i];t1=A[k][i+1];t2=A[k][i+2];t3=A[k][i+3];t4=A[k][i+4];t5=A[k][i+5];t6=A[k][i+6];t7=A[k][i+7];B[i][k]=t0;B[i][k+4]=t4;B[i+1][k]=t1;B[i+1][k+4]=t5;B[i+2][k]=t2;B[i+2][k+4]=t6;B[i+3][k]=t3;B[i+3][k+4]=t7;}for(k=i;k<i+4;k++){t0=B[k][j+4];t1=B[k][j+5];t2=B[k][j+6];t3=B[k][j+7];t4=A[j+4][k];t5=A[j+5][k];t6=A[j+6][k];t7=A[j+7][k];B[k][j+4]=t4;B[k][j+5]=t5;B[k][j+6]=t6;B[k][j+7]=t7;B[k+4][j]=t0;B[k+4][j+1]=t1;B[k+4][j+2]=t2;B[k+4][j+3]=t3;    }for(k=i+4;k<i+8;k++){t0=A[j+4][k];t1=A[j+5][k];t2=A[j+6][k];t3=A[j+7][k];B[k][j+4]=t0;B[k][j+5]=t1;B[k][j+6]=t2;B[k][j+7]=t3;}}}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++){t1 = A[k][p];B[p][k] = t1;}}}}}}
/* * 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.*/
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.*/
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;
}

提交trans.c()

程序设计思想:

1.分析一下题干内容和要做的事情

①编写一个实现矩阵转置的函数。即对于给定的矩阵A[N][M],得到矩阵B[M][N],使得对于任意0<=i<N、0<=j<M,有B[j][i]=A[i][j],

并且使函数调用过程中对cache的不命中数miss尽可能少。

②在如下函数里面编写最终代码:

char transpose_submit_desc[] = "Transpose submission";

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

③测试用例:

用三种不同规模的数组进行测试,规模分别为:

• 32 × 32 (M = 32, N = 32)

• 64 × 64 (M = 64, N = 64)

• 61 × 67 (M = 61, N = 67)

2.开始实现三种不同规模的数组转置

(1)32*32

因为A矩阵和B矩阵中下标相同的元素会映射到一个块中,因此访问两个数组的过程中会发生很多的冲突不命中。因此要减少miss,必须减少冲突不命中。基于这个原因,可以想到,我们可以一次性访问一个块中的多个元素,访问完就不再访问这个块了。

因为cache一个block中可以存8个int数据,因此先考虑8*8将其分块,这样分块的一个更重要的原因是当我将8个int直接取出来,这样即使写入的时候替换了block也没关系,因为我们已经全部读入了。

测试一下

嗯呢,达到要求了,那试试64X64能不能这样做

(2)64*64

嗯实际是行不通的,对A数组的访问依然是第一个不命中。对B数组的访问,可以看到前4行和后四行所映射的块是相同的,于是访问完前四行的第一列后,访问后四行的第一列会冲突不命中,导致原来的块被驱逐,再访问前四行的第二列,由于之前的块已经被驱逐,因此又会miss且驱逐,如此反复下去,B数组中所有的元素皆会不命中。由以上否定了8*8的划分方式。

思路:每次处理一个块,也就是像32x32那样取出每行的8个元素,然后将 每行的0-3号元素正常的放到B[0-3][0]这些位置去(也就是正常的转置),剩下的四个元先放置B矩阵4x4块的最右边保存,注意这个时候我已经取出来了。然后再用一个循环去把这些值放到B正确的位置去,然后A[4]到A[7]也是上述的处理。对整个矩阵重复这个操作即可。简单的示意图如下:

(3)61x67

于之前的两个矩阵,由于它们的每一行元素恰好占整数个块,因此分块的时候也会利用这一特性。但是根据之前的处理,由于这个测试的miss数允许到2000,这个限度相对较大,因此我们可以尝试不同的分块来处理即可。因此相当于64*64需要反复优化,这个还是比较好处理的。

调整分块的大小,测试了四组,最终确定17是最好的。

17x17

32×32(10分):运行结果截图

64×64(10分):运行结果截图

61×67(20分):运行结果截图

第4章 总结

4.1 请总结本次实验的收获

理解了现代计算机系统存储器层级结构

掌握了Cache的功能结构与访问控制策略

培养了Linux下的性能测试方法与技巧

深入理解了Cache组成结构对C程序性能的影响

以后会充分考虑Cache的功能结构来书写程序,减少Cache不命中的次数。

4.2 请给出对本次实验内容的建议

建议老师多给点时间完成这个实验

注:本章为酌情加分项。

参考文献

为完成本次实验你翻阅的书籍与网站等

[1]  林来兴. 空间控制技术[M]. 北京:中国宇航出版社,1992:25-42.

[2]  辛希孟. 信息技术与信息服务国际研讨会论文集:A集[C]. 北京:中国科学出版社,1999.

[3]  赵耀东. 新时代的工业工程师[M/OL]. 台北:天下文化出版社,1998 [1998-09-26]. http://www.ie.nthu.edu.tw/info/ie.newie.htm(Big5).

[4]  谌颖. 空间交会控制理论与方法研究[D]. 哈尔滨:哈尔滨工业大学,1992:8-13.

[5]  KANAMORI H. Shaking Without Quaking[J]. Science,1998,279(5359):2063-2064.

[6]  CHRISTINE M. Plant Physiology: Plant Biology in the Genome Era[J/OL]. Science,1998,281:331-332[1998-09-23]. http://www.sciencemag.org/cgi/ collection/anatmorp.

哈工大计算机系统实验六——高速缓冲器模拟相关推荐

  1. Cachelab 高速缓冲器模拟

    实验报告 实 验(六) 题     目 Cachelab 高速缓冲器模拟 专       业 计算机科学与技术 csim.c和trans.c代码见文章末尾 目  录 第1章 实验基本信息... - 3 ...

  2. 计算机系统实验六:程序的链接

    参考教材:计算机系统基础 第二版 袁春风 机械工业出版社 参考慕课:计算机系统基础(四):编程与调试实践 https://www.icourse163.org/learn/NJU-1449521162 ...

  3. 哈工大计算机系统实验二——DataLab数据表示

    计算机系统实验二特别难,和上一届的实验不一样,没有学长的火炬,当时做的时候特别崩溃.幸好有一帮志同道合的伙伴们,一起慢慢把实验解决了. 把火炬传下去! 实验报告 实 验(二) 题     目 Data ...

  4. 哈工大计算机系统实验一:计算机系统漫游

    计算机系统实验一:计算机系统漫游 寒假直接copy文档上传,有错误很正常(有对不上的地方请私聊我改正一下) 把火炬传下去把! 实验报告 实 验(一) 题     目 计算机系统漫游 专       业 ...

  5. 哈工大计算机系统实验七——微壳

    实验报告 实 验(七) 题     目 TinyShell 微壳 专       业 计算机类 学    号 xxxx 班    级 xxxx 学       生 xxxx 指 导 教 师 xxxx ...

  6. 哈工大计算机系统实验四——链接

    链接这一块呢,先看了李春凤老师的慕课,然后看一遍课本,然后来做实验,感觉真的懂了一样 把火炬传下去! 实验报告 实 验(四 题     目 LinkLab 链接 专       业 xxxx 学    ...

  7. S7-1200PLC—实验六 四节传送带控制模拟

    实验六 四节传送带控制模拟 一.实验目的 应用PLC的定时器.置位.复位等基本控制指令,根据控制要求,设计四节传送带控制系统. 二.PLC介绍 PLC (可编程逻辑控制器)是工业控制的核心部件,以控制 ...

  8. 操作系统课程设计---实验六 银行家算法的模拟与实现

    实验六 银行家算法的模拟与实现 完整课程设计源码及其报告查看:陈陈的操作系统课程设计 1.实验目的 (1) 进一步理解进程的并发执行. (2) 加强对进程死锁的理解,理解安全状态与不安全状态的概念. ...

  9. 【2022】哈工大计算机系统大作业——程序人生Hello’s P2P

    2022哈工大计算机系统大作业--程序人生Hello's P2P 摘要 第1章 概述 1.1 Hello简介 1.2 环境与工具 1.3 中间结果 1.4 本章小结 第2章 预处理 2.1 预处理的概 ...

最新文章

  1. 计算机应用基础 辅助教学系统,计算机应用基础课程辅助教学和智能测评系统使用手册——网络版.doc...
  2. Python删除文件及进行文件夹压缩
  3. HTML5中figure标签使用实例
  4. SQL SERVER 2005无法远程连接的问题
  5. struts2 mysql 分页代码_Struts2 + MySQL 实现分页
  6. 单片机里面的CPU使用率是什么鬼?
  7. Python之路 day1 基础1 变量 for while 用户输入
  8. openssh升级之后git账户免密登陆失效
  9. python爬虫的用途_python爬虫用代理ip有什么用途?
  10. 小学四年级计算机教案清华出版,清华版四年级下册信息技术电子备课教案
  11. matlab潮流计算ppt,matlab潮流计算.doc
  12. 进栈顺序为abcd则出栈顺序为_进栈顺序为ABCDEFG 有可能的出站顺序是什么
  13. 候选键的计算(数据库系统概论)
  14. 程序员工资真的很高么,月入几万的难道不是吹牛?
  15. 从2T-12.8T 一颗芯片全搞定
  16. BigDecimal舍入模式(Rounding Modes)
  17. 简单的封装知识 RDL,TSV, Bump,Wafer
  18. python pandas str列内置方法
  19. 计算机卸载一个程序正确操作,电脑这两个操作要学会,两种卸载软件的方法,保证电脑系统稳定...
  20. 收集前端优秀的网站、博客、书籍

热门文章

  1. ASO第一步-什么是ASO,与SEO的区别?
  2. Broadcom 802.11n网络适配器,网络连接没有有效的ip配置问题解决
  3. 日式键盘与美式键盘转换
  4. 如何修复Windows 10中的声音问题
  5. [总结]高效能人士的七个习惯
  6. 数学基础_设随机变量X1,X2,…Xn相互独立,且都服从(0,θ)上的均匀分布。求U=max{X1,X2,…Xn}数学期望
  7. 【无人驾驶系列五】GPS及惯性传感器在无人驾驶中的应用
  8. libusb系列-002-Windows下libusb源码编译
  9. wps中删除我的设备(已经不使用的)
  10. Java语言中 void和public void的区别,static和public static的区别。