# 家庭作业
家庭作业 6.38(★)
3M 决定在白纸上印黄方格,做成 Post-It 小贴纸。在打印过程中,他们需要设置方格中每个点的 CMYK(蓝色,红色,黄色,黑色)值。3M 雇佣你判定下面算法在一个具有 2048 字节、直接映射、块大小为 32 字节的数据高速缓存上的效率。有如下定义:
struct point_color {
int c;
int m;
int y;
int k;
};
struct point_color square[16][16];
int i, j;
有如下假设:
sizeof(int)==4。square起始于内存地址 0。- 高速缓存初始为空。
- 唯一的内存访问是对于
square数组中的元素。变量i和j存放在寄存器中。
确定下列代码的高速缓存性能:
for (i = 0; i < 16; i++) {
for (j = 0; j < 16; j++) {
square[i][j].c = 0;
square[i][j].m = 0;
square[i][j].y = 1;
square[i][j].k = 0;
}
}
A. 写总数是多少?
B. 在高速缓存中不命中的写总数是多少?
C. 不命中率是多少?
家庭作业 6.39(★)
给定作业 6.38 中的假设,确定下列代码的高速缓存性能:
for (i = 0; i < 16; i++) {
for (j = 0; j < 16; j++) {
square[j][i].c = 0;
square[j][i].m = 0;
square[j][i].y = 1;
square[j][i].k = 0;
}
}
A. 写总数是多少?
B. 在高速缓存中不命中的写总数是多少?
C. 不命中率是多少?
家庭作业 6.40(★)
给定作业 6.38 中的假设,确定下列代码的高速缓存性能:
for (i = 0; i < 16; i++) {
for (j = 0; j < 16; j++) {
square[i][j].y = 1;
}
}
for (i = 0; i < 16; i++) {
for (j = 0; j < 16; j++) {
square[i][j].c = 0;
square[i][j].m = 0;
square[i][j].k = 0;
}
}
A. 写总数是多少?
B. 在高速缓存中不命中的写总数是多少?
C. 不命中率是多少?
家庭作业 6.41(★★)
你正在编写一个新的 3D 游戏,希望能名利双收。现在正在写一个函数,使得在画下一帧之前先清空屏幕缓冲区。工作的屏幕是 640×480 像素数组。工作的机器有一个 64 KB 直接映射高速缓存,每行 4 个字节。使用下面的 C 语言数据结构:
struct pixel {
char r;
char g;
char b;
char a;
};
struct pixel buffer[480][640];
int i, j;
char *cptr;
int *iptr;
有如下假设:
sizeof(char)==1和sizeof(int)==4。buffer起始于内存地址 0。- 高速缓存初始为空。
- 唯一的内存访问是对于
buffer数组中元素的访问。变量i、j、cptr和iptr存放在寄存器中。
下面代码中百分之多少的写会在高速缓存中不命中?
for (j = 0; j < 640; j++) {
for (i = 0; i < 480; i++) {
buffer[i][j].r = 0;
buffer[i][j].g = 0;
buffer[i][j].b = 0;
buffer[i][j].a = 0;
}
}
家庭作业 6.42(★★)
给定作业 6.41 中的假设,下面代码中百分之多少的写会在高速缓存中不命中?
char *cptr = (char *) buffer;
for (; cptr < (((char *) buffer) + 640 * 480 * 4); cptr++)
*cptr = 0;
家庭作业 6.43(★★)
给定作业 6.41 中的假设,下面代码中百分之多少的写会在高速缓存中不命中?
int *iptr = (int *) buffer;
for (; iptr < ((int *) buffer + 640 * 480); iptr++)
*iptr = 0;
家庭作业 6.44(★★★)
从 CS:APP 的网站上下载 mountain 程序,在你最喜欢的 PC/Linux 系统上运行它。根据结果估计你系统上的高速缓存的大小。
家庭作业 6.45(★★★)
在这项任务中,你会把在第 5 章和第 6 章中学习到的概念应用到一个内存使用频繁的代码的优化问题上。考虑一个复制并转置一个类型为 int 的 N×N 矩阵的过程。也就是,对于源矩阵 S 和目的矩阵 D,我们要将每个元素 si,j 复制到 dj,i。只用一个简单的循环就能实现这段代码:
void transpose(int *dst, int *src, int dim)
{
int i, j;
for (i = 0; i < dim; i++)
for (j = 0; j < dim; j++)
dst[j*dim + i] = src[i*dim + j];
}
这里,过程的参数是指向目的矩阵(dst)和源矩阵(src)的指针,以及矩阵的大小 N(dim)。你的工作是设计一个运行得尽可能快的转置函数。
家庭作业 6.46(★★★)
这是练习题 6.45 的一个有趣的变体。考虑将一个有向图 g 转换成它对应的无向图 g′。图 g′ 有一条从顶点 u 到顶点 v 的边,当且仅当原图 g 中有一条 u 到 v 或者 v 到 u 的边。图 g 是由如下的它的邻接矩阵(adjacency matrix)G 表示的。如果 N 是 g 中顶点的数量,那么 G 是一个 N×N 的矩阵,它的元素是全 0 或者全 1。假设 g 的顶点是这样命名的:v0,v1,…,vN−1。那么如果有一条从 vi 到 vj 的边,那么 G[i][j] 为 1,否则为 0。注意,邻接矩阵对角线上的元素总是 1,而无向图的邻接矩阵是对称的。只用一个简单的循环就能实现这段代码:
void col_convert(int *G, int dim) {
int i, j;
for (i = 0; i < dim; i++)
for (j = 0; j < dim; j++)
G[j*dim + i] = G[j*dim + i] || G[i*dim + j];
}
你的工作是设计一个运行得尽可能快的函数。同前面一样,要提出一个好的解答,你需要应用在第 5 章和第 6 章中所学到的概念。