这个实验主要是将高速缓存命中的一点东西,意在告诉我们平常多注意这方面的东西。

不懂java的,所以只管C的部分。

You will do this several times, making small modifications to see what differences they make—how the choice of language affects performance and how effective the compiler can be at optimizing your code when you:

  • interchange the order of the i and j loops
  • uncomment the commented line
  • change the size of the array being copied from 2048 x 2048 to 4096 x 4096
#include <stdio.h>

int src[2048][2048];
int dst[2048][2048]; /* Copies the contents of one 2048-by-2048 array (src) into another (dst). */
int main(int argc, char* argv[])
{
// declare all variables before the code (conform to an older C standard...)
int rep;
int i, j; for ( rep = 0; rep < 10; rep++ )
{
for ( i= 0; i < 2048;i++ )
{
for ( j= 0; j< 2048; j++ )
{
//src[i][j] = i * rep;
dst[i][j] = src[i][j];
}
}
} return 0;
}

要做的就是测试三种不同情况下的程序运行时间:

不优化 O2优化
原始程序 0.163 0.167
调换i,j顺序 1.332 1.305
加上src数组赋值 1.814 1.815
改变数组大小为4096 8.424 8.487

上诉结果都是在保持上一个改变的基础上得出的结果,也就是加上src数组赋值这一步骤时,i和j的顺序还是调换的。

  1. What are the source code differences among the two Java implementations?

由于不懂java,所以只能编译一下C的程序,对java的就暂时不管了。

2.Pick a single pair of results that most surprised you. What is it about the results that surprised
you? (That is, from the 32 pairs of measurement results, pick one pair whose relationship is least
like what you would have guessed.)

最大的震惊就是gcc的-O2优化什么用也没有啊,有时候甚至是反而比不优化的都要来的慢啊。真是……(看看当i,j调换的时候-o2和-o1的区别)

3.[Optional extra credit] None
of these programs appear to actually do anything, so one is tempted to optimize them by simply eliminating all code (resulting in an empty main()).
Is that a correct optimization? Related to that, try compiling this C program, with and without optimization, and then time running it:

#include <stdio.h>

#define SIZE 1000000

int main() {
int i, j, k;
int sum = 1; for (i = 0; i < SIZE; i++) {
for (j = 0; j < SIZE; j++) {
for (k = 0; k < SIZE; k++) {
sum = -sum;
}
}
} printf("hello, world\n"); return 0;
}

这个问题说main函数的参数会对程序产生速度上的影响,这个就一个栈的问题,会有什么影响?个人认为没有什么影响吧。

还有  这个程序确定个人PC跑的完?出这个题的耍人的吧。估计是要让计算机冬天煮鸡蛋,多散散热的……

Part II: Inferring Mystery Cache Geometries

Your job is to fill in the function stubs in cache-test-skel.c which,
when linked with one of these cache object files, will determine and then output the cache size, associativity, and block size. Some of the provided object files are named with this information (e.g. cache_64c_2a_16b.o is
a 64 KB capacity, 2-way set-associative cache with 16B blocks)

程序如下:

#ifndef __MYSTERY_CACHE_H
#define __MYSTERY_CACHE_H typedef unsigned long long addr_t;
typedef unsigned char bool_t;
#define TRUE 1
#define FALSE 0 /** Initializes the cache. This function must be called so that the
cache can initialize its data structures, though the mystery
caches will ignore the provided arguments (as their parameters are
hard-coded). */
void cache_init(int size, int block_size); /** Lookup an address in the cache. Returns TRUE if the access hits,
FALSE if it misses. */
bool_t access_cache(addr_t address); /** Clears all words in the cache (and the victim buffer, if
present). Useful for helping you reason about the cache
transitions, by starting from a known state. */
void flush_cache(void); #endif
#include <stdlib.h>
#include <stdio.h> #include "mystery-cache.h" Returns the size (in B) of each block in the cache.
*/
int get_block_size(void) {
<span style="white-space:pre"> </span>int count=0;
<span style="white-space:pre"> </span>flush_cache();
<span style="white-space:pre"> </span>access_cache(0);
<span style="white-space:pre"> </span>while(access_cache(count))
<span style="white-space:pre"> </span>count++;
<span style="white-space:pre"> </span>return count;
} /*
Returns the size (in B) of the cache.
*/
int get_cache_size(int block_size) {
unsigned long long count=0;
unsigned int i=0;
while(1)
{
count=count+block_size;
flush_cache();
for(i=0;i<count;i=i+block_size)
{
access_cache(i);
}
if(!access_cache(0))
return count-block_size;
}
} /*
Returns the associativity of the cache.
*/
int get_cache_assoc(int cache_size) {
/* YOUR CODE GOES HERE */
int assoc=0;
int i;
while(1)
{
assoc++;
for(i=0;i<=assoc;i++)
access_cache(i*cache_size);
if(!access_cache(0))
return assoc;
}
} int main(void) {
int size;
int assoc;
int block_size; cache_init(0,0); block_size=get_block_size();
size=get_cache_size(block_size);
assoc=get_cache_assoc(size);
printf("Cache block size: %d bytes\n", block_size);
printf("Cache size: %d bytes\n", size);
printf("Cache associativity: %d\n", assoc); return EXIT_SUCCESS;
}

这道题主要让你用mystery-cache.h头文件里面的三个函数,来对4个高速缓存的的模拟文件进行分析,得到高速缓存的块大小,缓存总容量和高速缓存行的大小。

这里主要注意这个函数:

/** Lookup an address in the cache. Returns TRUE if the access hits,
FALSE if it misses. */
bool_t access_cache(addr_t address);

这个函数是有两个作用,1.把address放入高速缓存。2.检查高速缓存中有没有address这个地址。

这个函数比较坑,主要是它会把在高速缓存中的地址也压入高速缓存。

解释下,就是当高速缓存的块是4的时候,地址0,1,2,3四个地址是一起的,是在一个高速缓存行里面的。假设高速换存一组有4行,当对一个空的高速缓存进行操作时(执行flush_cache()函数),执行access_cache(0),access_cache(1),access_cache(2),access_cache(3)时,此时高速缓存第0组的缓存行是:0,1,2,3

理论上来说,应该进行了那个操作之后,缓存行应该只有0,因为1,2,3三个数据都可以在0这个缓存行中访问到,他们是在一个块里面的。这感觉是这个高速缓存模拟文件的一个不好的地方。对后面那三个函数编写,很麻烦啊。

求解缓存块大小:

思路:假设块的大小为N,首先先把0放入缓存区中,则执行access_cache(0)~access_cache(N-1)的过程中,这些地址全都会缓存在在第0组中,由于有先把0放入了缓存区,所以在查询asscess_cache(add)的过程中(add>0&&add<N),会一直返回1.而N由于和前面的数字不是在一个块里面的,N会被缓存在第1组,而第一组本来是空的,读取N会有冷不命中,所以查询时会返回0,由此可以得出块的大小N。

int get_block_size(void) {
int count=0;
flush_cache();
access_cache(0);
while(access_cache(count))
count++;
return count;
}

求解缓存区的总容量:

思路很简单,就是往缓存区里面一直存入地址,根据缓存区相关知识,当缓存区存满时,会删除一个缓存区中的地址,以放入新的地址。所以程序的编写按照这个思路,一直往缓存区中存入数据的过程中,一直查询0是否在缓存区中,如果0不在,则缓存区因为缓存区容量已满,把0删除。但是因为asscess_cache(add)函数的特性,所以每次asscess_cache(0)的时候会把0写入,所以要用一个比较麻烦的方法。就是每次查询完0之后,要清空缓存区,并且重新写入地址。

int get_cache_size(int block_size) {
unsigned long long count=0;
unsigned int i=0;
while(1)
{
count=count+block_size;
flush_cache();
for(i=0;i<count;i=i+block_size)
{
access_cache(i);
}
if(!access_cache(0))
return count-block_size;
}
}

求解缓存区高速缓存行的大小:

求解思路:由于已经求接触缓存区的总容量cache_size,所以可以知道地址cache_size,2*cache_size,3*cache_size……n*cache_size和0总是在同一个缓存组里面的。利用这个性质,可以比较容易的得到assoc的值。

首先,存入0的地址,然后依次存入cache_size,2*cache_size,3*cache_size……,在存入的过程中,查询0是否在缓存区中,如果0不在缓存区中,则第0组空间已满,这是最后的n*cache_size中的n,就是assoc的大小。这里需要注意的就是access_cache()函数的特性。和上面一个函数的过程一样,查询过了,就要清空缓存区,重新写入,重新查询。

int get_cache_assoc(int cache_size) {
/* YOUR CODE GOES HERE */
int assoc=0;
int i;
while(1)
{
assoc++;
for(i=0;i<=assoc;i++)
access_cache(i*cache_size);
if(!access_cache(0))
return assoc;
}
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

lab4 Cache Geometries 深入理解计算机系统——高速缓存的更多相关文章

  1. 《深入理解计算机系统》(CSAPP)读书笔记 —— 第一章 计算机系统漫游

    本章通过跟踪hello程序的生命周期来开始对计算机系统进行学习.一个源程序从它被程序员创建开始,到在系统上运行,输出简单的消息,然后终止.我们将沿着这个程序的生命周期,简要地介绍一些逐步出现的关键概念 ...

  2. 深入理解计算机系统家庭作业汇总 20135301&&20135328

    深入理解计算机系统家庭作业 深入理解计算机系统第二章家庭作业 题目2.64 题目要求 判断二进制数偶数位是否有任意一位位为1,有的话返回1,否则返回0 解题过程 int any_even_one(un ...

  3. 《深入理解计算机系统》【PDF】下载

    <深入理解计算机系统>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230382303 内容提要 本书主要介绍了计算机系统的基本概念,包 ...

  4. 4.2《深入理解计算机系统》笔记(五)并发、多进程和多线程【Final】

    该书中第11章是写web服务器的搭建,无奈对web还比较陌生.还没有搞明白. 这些所谓的并发,其实都是操作系统做的事情,比如,多进程是操作系统fork函数实现的.I/O多路复用需要内核挂起进程.多线程 ...

  5. 深入理解计算机系统_3e 第九章家庭作业 CS:APP3e chapter 9 homework

    9.11 A. 00001001 111100 B. +----------------------------+ | Parameter Value | +--------------------- ...

  6. 《深入理解计算机系统V2》学习指导

    <深入理解计算机系统V2>学习指导 目录 图书简况 学习指导 第一章 计算机系统漫游 第二章 信息的表示和处理 第三章 程序的机器级表示 第四章 处理器体系结构 第五章 优化程序性能 第六 ...

  7. 深入理解计算机系统(4.1)---X86的孪生兄弟,Y86指令体系结构

    引言 各位猿友们好,计算机系统系列很久没更新了,实在是抱歉之极.新的一年,为了给计算机系统系列添加一些新的元素,LZ将其更改为书的原名<深入理解计算机系统>.这本书非常厚,而且难度较高,L ...

  8. 深入理解计算机系统(1.2)---hello world的程序是如何运行的

    在写本章的内容之前,LZ先做个小广告.其实也不算是什么广告,就是LZ为了和各位猿友交流方便,另外也确实有个别猿友留言或者在博客里发短消息给LZ要联系方式.因此LZ斗胆建立了一个有关<深入理解计算 ...

  9. 《深入理解计算机系统》 Chapter 7 读书笔记

    <深入理解计算机系统>Chapter 7 读书笔记 链接是将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载(货被拷贝)到存储器并执行. 链接的时机 编译时,也就是 ...

随机推荐

  1. jQuery插件

    1. Lightbox 2:    Lightbox 2 是一款很酷的图片显示插件,可以在一个平滑展开的新窗口中展现出图片,而同时页面的其余部分都变成黑色背景.使用这款插件,是为了当你的的图片过大必须 ...

  2. Android开发之自定义Spinner样式的效果实现(源代码实现)

    android系统自带的Spinner样式是远远满足不了我们实际开发过程中对Spinner UI风格的要求,因此我们肯定需要为了切合整个应用的风格,修改我们的Spinner样式.系统给我们提供了两种常 ...

  3. linux 搭建Tomcat

    这几天用虚拟机装了centos ,以前没有用过linux,先将搭建java web 环境记录如下: 一.卸载系统安装的jdk环境. 1.安装好的CentOS会自带OpenJdk,用命令 java -v ...

  4. 有关Repeater的事件

    Repeater放在Updatepanel中是可以通过右键->属性,双击事件来生成事件的,若能这样的话,那最后是用这种方法吧,最起码不会出错!

  5. html系列教程--base button canvas caption

    <base> 标签 <base> 标签为页面上的所有链接规定默认地址或默认. demo: <head> <base href="http://www ...

  6. graph使泳道图的label横向显示

    1.如果需要将label靠左边对齐,则必须重写底层源码 新增mxText的一个构造器,主要是增加了一个参数:x(代表当前的cell) function mxText(a, b, c, d, e, f, ...

  7. JavaScript的一点简介(注:本文诸多观点源于JavaScript高级程序设计,如有侵权,立即删除)

    JavaScript是一门最易让人误解的语言,该语言中精华与糟粕并存(可能比一般语言的这个比例要大一些):但“千淘万漉虽辛苦,吹尽黄沙始到金”,层层面纱下是易用灵活.优雅轻灵的内在.很久以前,Java ...

  8. Python核心编程读笔 2

    第三章 python基础 一.语句和语法 \n 标准的行分隔符 \ 继续上一行 ; 将两个语句连接在一行 : 分开代码块的头和体 代码块以缩进块的形式体现 python文件以模块的形式组织 二.变量赋 ...

  9. poj 2771 最大独立集

    这道题又无耻的抄袭了别人的代码. 刚开始以为是最大匹配,把条件不相符的人连一起,然后求最大匹配,感觉麻烦,然后看了别人的解题报告,是把相符的人连一起,然后减去,其实就是最大独立集. 最大独立集=|G| ...

  10. linux mail 简操作

    1. 如何查看linux的mailqueue 检查所传送的电子邮件是否送出,或滞留在邮件服务器中 语法:/usr/lib/sendmail -bp 2. 如何发送mail 1)将文件当做电子邮件的内容 ...