前言
本次实验的主要目的是熟悉cache的原理。加深对cache的映像规则、替换方法、cache命中与缺失的理解。通过实验对比分析映像规则对cache性能的影响。
实验内容一:熟悉模拟程序
阅读给出的cache模拟程序(cachesimulator.cpp),理解其中的主要参数与功能。修改代码,随机生成N个访存地址,运行程序观察并分析结果(例如,可分析其中命中次数,不命中次数,替换次数)。熟悉cache系统的执行过程(可举例详细分析一次命中/不命中/替换过程)。
首先我们先实现一个函数生成一个随机访问序列并写入文件**“project.txt”**以供后续的使用
void generateRandomMemorySequence(int sequenceLength, const char* fileName,int cache) {
FILE* fp;
int i;
srand(time(NULL));
fp = fopen(fileName, "w");
if (fp == NULL) {
printf("无法打开文件。\n");
return;
}
for (i = 0; i < sequenceLength; i++) {
int randomNumber = rand() % cache;
fprintf(fp, "%d\n", randomNumber);
}
fclose(fp);
}
当生成一个随机序列如红框中所示
我们将访问序列对应的字地址,块号,已经地址对应的index位和tag位打印到终端
当采用全相联的映射方式,每个cache的大小为64字节,每个块的大小位1个字长,并使用上述生成的内存随机访问序列时,它的命中率和缺失率如下图所示
由于我们采用的是全相联方式,并且我们生成的随机访问序列的个数是小于cache能存放的条目数的,所以最后所有的随机访问序列都会被保存到cache中,所以我们不必考虑置换的问题,接下来我们选中命中次数进行分析
命中次数分析:
由打印到终端的随机访问序列和对应的index位和tag位我们可以发现,命中的情况发生发生在随机访问的第四次,第六次,第九次
第四次命中是由于在第三次访存的时候,我们访问的是同一个内存地址,在第三次进行访存的时候,我们已经将该内存地址存放的数据以及该地址对应的tag值放入cache中,并将有效位置1,所以第四次访存可以命中。
第六次命中是由于我们在第一次访存的时候访存的地址是38,而我们在第六次访存的时候我们访存的地址是36,这两个地址同属于一个块,所以在第一次没命中的情况时,我们将其对应的数据块放入了cache,所以第六次才能命中。
第九次命中与第六次命中情况相同。
**cache命中过程介绍:**当我们访问一个内存地址时,我们可以使用这个地址算出对应的index位和tag位,比如我们使用的是全相联,我们就使用tag位与cache中的每一个条目进行比较,如果tag位相同并且有效位为1,那我们就命中了cache不用再去访问主存。
实验内容二:利用该模拟程序仿真课后习题4.1,并得出结果。
习题4.1:The following C program is run (with no optimizations) on a machine with a cache that has four-word (16-byte) blocks and holds 256 bytes of data:
int i, j, c, stride, array[256];
for (i=0;i<10000;i++)
for (j=0;j<256;j=j+stride)
c = array[j]+5;
If we consider only the cache activity generated by references to the array and we assume that integers are words.
(1)What is the expected miss rate when the cache is direct-mapped and stride=132? How about if stride=131?
当stride是132:
由于stride为132,所以每次的内部循环我们都要访问的数据为arrar[0]和array[132],又由于我们采用的是直接映射的方式并且每一个整数的大小为一个字长,所以array[0]所对应的内存块为0/4=0,而cache中的块的数量为16,0%16=0,所以array[0]对应的cache中的缓冲行的为0,同理可算出array[132]对应的条目存放的缓冲行为1。因此可以预测,一共会产生两次未命中的情况,是在第一次循环时访问array[0]和array[132]时,可算得缺失率为2/(2*10000)=0.01%。
当我们使用程序模拟的运行结果如下图所示:
当stride为131时:
当stride时同理我们要访问的数组元素为array[0]和array[131],可以计算出这两个元素所对应的缓冲行都为第0个,所以每次访问的时候都会发生缺失现象,缺失率为100%
当我们使用程序模拟的运行结果如下图所示:
(2)Would either of these changes if the cache were two-way set associative?
当stride为132时:
由于stride为132,使用的是两路组相联,与上一问不一样的地方在于当我们算出在内存中的块号后,我们需要将块号%(cache中的组数)
,每一组中可以放两个块,通过计算array[0]对应的是第0组cache块,而array[132]对应的是第1组cache块,所以预测结果仍与上一问中相同为0.01%
当stride为131时:
array[0]和array[131]都对应cache中的第0行,但由于我们采用的是组相联的方式,所以每一个缓冲行中能存放两个块,所以只会造成两次不命中的情况,缺失率为0.01%
(理论分析该试题,得出上述两问的结果。利用cache模拟程序仿真该程序的cache执行过程,核实实验结果是否与理论分析计算结果一致。)
(3)对于每个miss,标注是哪种miss(compulsory,conflict,capacity)。
在采用直接映射方式的时候
- 当stride为132时,由于两次未命中都是由于第一访问数组所在数据块,所以会导致两次强制失效
- 当stride为131时,由于第一次访问数组所在数据块,所以会导致两次强制失效,并且由于arrary[0]和array[131]两个数组元素所在数据块竞争同一个缓冲行,所以会导致19998次冲突失效
在采用二路组相联的方式时
- 无论stride为131还是132都会产生两次强制失效