深入理解计算机系统_3e 第六章家庭作业 CS:APP3e chapter 6 homework
**6.22**
假设磁道沿半径均匀分布,即总磁道数和(1-x)r成正比,设磁道数为(1-x)rk;
由题单个磁道的位数和周长成正比,即和半径xr成正比,设单个磁道的位数为xrz;
其中r、k、z均为常数。
所以C = (1-x)rk * xrz = (-x^2 + x) * r^2 * kz,即需要-x^2 + x最大,得到x = 0.5。
6.23
seek time : 4 ms
average rotational latency : 0.5 * 60 / 15000 * 1000 = 2 ms
transfer time : 60 / 15000 / 800 * 1000= 0.005 ms
4 + 2 + 0.005 = 6.005 ms
6.24
A.
2MB = 512 bytes * 4096,即需要读取4096个扇区。
定位时间为:4 + 0.5*60/15000*1000 = 6 ms
最理想的情况下,这4096个扇区都在一个柱面上(一个磁道读完后继续读下一个,磁头不用移动),也就是4096/1000 = 5个磁道。
即transfer time = 4096 / 1000 * 60 / 15000 * 1000 = 16.384 ms
所以理想时间为:6 + 16.384 = 22.384 ms
B.
2MB = 512 bytes * 4096,即需要读取4096个扇区。
定位时间为:4 + 0.5*60/15000*1000 = 6 ms
在完全随机的情况下,这4096个扇区分布在不同的磁道上,每一个扇区读完以后磁头都要再次去定位。
所以总的时间为:6 * 4096 + transfer time = 24592.384 ms (这里书上有一个类似的题目,但是没有加上transfer time ,我觉得还是要加上)
6.25
S t s b
1. 64 24 6 2
2. 1 30 0 2
3. 128 22 7 3
4. 1 29 0 3
5. 32 22 5 5
6. 8 24 3 5
6.26
m C B E S t s b
1. 2048 256
2. 4 4
3. 25 6
4. 32 5
6.27
A.
0x08A4 0x08A5 0x08A6 0x08A7
0x0704 0x0705 0x0706 0x0707
B.
0x1238 0x1239 0x123A 0x123B
6.28
A.
None
B.
0x18F0 0x18F1 0x18F2 0x18F3
0x00B0 0x00B1 0x00B2 0x00B3
C.
0x0E34 0x0E35 0x0E36 0x0E37
D.
0x1BDC 0x1BDD 0x1BDE 0x1BDF
6.29
A.
CTCTCTCTCTCTCTCT, CICI, COCO
B.
Hit? Read value(or unknown)
N -
Y unknown
Y 0xC0
6.30
A.
C = S * E * B = 128 Bytes
B.
CTCTCTCTCTCTCTCT, CICICI, COCO
6.31
A.
00111000, 110, 10
B.
CO 0x2
CI 0x6
CT 0x38
Cache hit? Y
Cache byte returned 0xEB
6.32
A.
10110111, 010, 00
B.
CO 0x0
CI 0x2
CT 0xB7
Cache hit? N
Cache byte returned -
6.33
0x1788 0x1789 0x178A 0x178B
0x16C8 0x16C9 0x16CA 0x16CB
6.34
cache共有两个block,分别位于两个set中,设他们为b1和b2。每个block可以放下4个int类型的变量,也就是数组中的一行。在这一题中,源数组和目的数组是相邻排列的。所以内存和cache的映射情况是这样的:
b1 : src[0][] src[2][] dst[0][] dst[2][]
b2 : src[1][] src[3][] dst[1][] dst[3][]
dst array src array
Col.0 Col.1 Col.2 Col.3 Col.0 Col.1 Col.2 Col.3
Row0 m m h m m m m m
Row1 m h m h m m m m
Row2 m m h m m m m m
Row3 m h m h m m m m
6.35
cache共有八个block,分别位于八个set中,设他们为b1、b2、b3、b4、b5、b6、b7、b8。每个block可以放下4个int类型的变量,也就是数组中的一行。在这一题中,源数组和目的数组是相邻排列的。所以内存和cache的映射情况是这样的:(这时不会有冲突)
b1 : src[0][]
b2 : src[1][]
b3 : src[2][]
b4 : src[3][]
b5 : dst[0][]
b6 : dst[1][]
b7 : dst[2][]
b8 : dst[3][]
dst array src array
Col.0 Col.1 Col.2 Col.3 Col.0 Col.1 Col.2 Col.3
Row0 m h h h m h h h
Row1 m h h h m h h h
Row2 m h h h m h h h
Row3 m h h h m h h h
6.36
A.
cache共有32个block,分别位于32个set中,每个block可以放下4个int类型的变量,所以所有的block可以放下x数组中的一行。由映射关系,x[0][i]和x[1][i]对应的set是一样的。所以每一次的运算都会发生miss的情况,所以miss rate = 100%。
B.
cache共有64个block,分别位于64个set中,每个block可以放下4个int类型的变量,所以所有的block可以放下x数组中的两行,即全部放入。每四次读取中的第一次会发生miss,所以miss rate = 25%。
C.
cache共有32个block,分别位于16个set中,每个block可以放下4个int类型的变量,每个set可以放下8个int类型的变量,所有的block可以放下x数组中的一行。由映射关系,x[0][i]和x[1][i]对应的set是一样的,x[y][i]和x[y][i+64]对应的set也是一样的。
对于x[0][0] * x[1][0] ~ x[0][63] * x[1][63] ,每四次运算会有第一次miss。
对于x[0][64] * x[1][64] ~ x[0][127] * x[1][127] ,每四次运算会有第一次miss(擦去前面warm up的cache)。
综上,miss rate = 25%。
D.
不会,因为此时block大小是限制因素(每四次读取第一次miss)。
E.
会,更大的block会降低miss rate,因为miss只发生在第一次读入block的时候,所以更大的block会使得miss占总读取的比例降低。
6.37
cache共有256个block,分别位于256个set中,每个block可以放下4个int类型的变量,所有的block可以放下1024个int类型的变量。
当N = 64:
映射关系:a[0][0] ~ a[15][63]、a[16][0] ~ a[31][63]、a[32][0] ~ a[47][63]、a[48][0] ~ a[63][63] 互相重叠。
sumA按照行来读取,所以每四次读取第一次都会miss,即miss rate = 25%。
sumB按照列来读取,所以每一次读取都会发生miss(读取后的block又会被覆盖),即miss rate = 100%。
sumC按照列来读取,但是每次读取后都会按照行再读取一次,所以每四次读取会有两次miss,即miss rate = 50%。
当N = 60
映射关系:a[0][0] ~ a[17][3]、a[17][4] ~ a[34][7]、a[34][8] ~ a[51][11]、a[51][12] ~ a[59][59]互相重叠,其中最后的a[51][12] ~ a[59][59]没有到达cache的尾部。
sumA按照行来读取,所以每四次读取第一次都会miss,即miss rate = 25%。
sumB按照列来读取,这里的情况有些复杂,我写了一个程序来分析:
#include <stdio.h>
#define SIZEOFCACHE 256
#define SIZEOFBLOCK 4
#define N 60
int main()
{
int cache[SIZEOFCACHE];
for (int k = 0; k < SIZEOFCACHE; ++k)
{
cache[k] = -1;
}
int read = 0;
int miss = 0;
for (int j = 0; j < N; ++j)
{
for (int i = 0; i < N; ++i)
{
//read a[i][j]
++read;
int position = i * N + j;
int need_start = position/SIZEOFBLOCK;
if (cache[need_start%SIZEOFCACHE] != need_start)
{
++miss;
cache[need_start%SIZEOFCACHE] = need_start;
}
}
}
printf("%g\n", miss/(double)read);
return 0;
}
输出结果为25%。
C.
将上面程序的循环部分更改为:
for (int j = 0; j < N; j+=2)
{
for (int i = 0; i < N; i+=2)
{
//read a[i][j] a[i+1][j] a[i][j+1] a[i+1][j+1]
++read;
int position = i * N + j;
int need_start = position/SIZEOFBLOCK;
if (cache[need_start%SIZEOFCACHE] != need_start)
{
++miss;
cache[need_start%SIZEOFCACHE] = need_start;
}
++read;
position = (i+1) * N + j;
need_start = position/SIZEOFBLOCK;
if (cache[need_start%SIZEOFCACHE] != need_start)
{
++miss;
cache[need_start%SIZEOFCACHE] = need_start;
}
++read;
position = i * N + j + 1;
need_start = position/SIZEOFBLOCK;
if (cache[need_start%SIZEOFCACHE] != need_start)
{
++miss;
cache[need_start%SIZEOFCACHE] = need_start;
}
++read;
position = (i+1) * N + j + 1;
need_start = position/SIZEOFBLOCK;
if (cache[need_start%SIZEOFCACHE] != need_start)
{
++miss;
cache[need_start%SIZEOFCACHE] = need_start;
}
}
}
输出结果为25%。
6.38
这个cache有64个block,每个block可以放4个int类型的变量,也就是一个point_color
的结构体,即cache总共可以放置64个结构体。
映射关系为:square[0][0] ~ square[3][15]、square[4][0] ~ square[7][15]、square[8][0] ~ square[11][15]、square[12][0] ~ square[15][15] 互相重叠。
A.
16 * 16 * 4 = 1024
B.
这个程序是按照行来写的,所以每四次写入只有第一次miss,即miss的次数为1024 / 4 = 256
C.
25%
6.39
这个cache有64个block,每个block可以放4个int类型的变量,也就是一个point_color
的结构体,即cache总共可以放置64个结构体。
映射关系为:square[0][0] ~ square[3][15]、square[4][0] ~ square[7][15]、square[8][0] ~ square[11][15]、square[12][0] ~ square[15][15] 互相重叠。
A.
16 * 16 * 4 = 1024
B.
这个程序是按照列来写的,每四次写入只有第一次miss(每次都完整利用了一个block,没有读入block的浪费,此时miss rate只取决于block的大小),即miss的次数为1024 / 4 = 256
C.
25%
6.40
这个cache有64个block,每个block可以放4个int类型的变量,也就是一个point_color
的结构体,即cache总共可以放置64个结构体。
映射关系为:square[0][0] ~ square[3][15]、square[4][0] ~ square[7][15]、square[8][0] ~ square[11][15]、square[12][0] ~ square[15][15] 互相重叠。
A.
16 * 16 + 3 * 16 * 16 = 1024
B.
对于第一个循环,每一次写入都会发生miss的情况,最后cache中保存的是square[12][0] ~ square[15][15],而第二个循环又从头开始写入,所以每三次写入的第一次都会发生miss。总的miss次数就是16 * 16 * 2 = 512。
C.
50%
6.41
这个cache有16K个block,每个block可以放4个char类型的变量,也就是一个pixel
的结构体,即cache总共可以放置16K个结构体。buffer
里面一共有480 * 640 = 300K个结构体,所以映射时会有18个完全重叠的,最后一次重叠3/4.
这个程序按照列来写,每四次写入只有第一次miss(每次都完整利用了一个block,没有读入block的浪费,此时miss rate只取决于block的大小),所以miss rate = 25%。
6.42
这个cache有16K个block,每个block可以放4个char类型的变量,也就是一个pixel
的结构体,即cache总共可以放置16K个结构体。buffer
里面一共有480 * 640 = 300K个结构体,所以映射时会有18个完全重叠的,最后一次重叠3/4.
这个程序实际上就是按照行来写的指针版本,每四次写入只有第一次miss,miss rate = 25%。
6.43
这个cache有16K个block,每个block可以放4个char类型的变量,也就是一个pixel
的结构体,即cache总共可以放置16K个结构体。buffer
里面一共有480 * 640 = 300K个结构体,所以映射时会有18个完全重叠的,最后一次重叠3/4.
这个程序实际上还是按照行来写的指针版本,但是只写了buffer数组的1/4。每四次写入只有第一次miss,miss rate = 25%。
6.44
为了辨识缓存的大小,选取中间的列(例如S8)来判断——避免CPU的prefetching带来干扰。可以看出,在32K和512K以及8M的地方有明显的落差,所以判断L1:32k、L2:512k、L3:8M。
用lscpu
验证分析正确:
6.45
这个题要求我们利用第5章和第6章中学到的优化知识。对于第5章,就是减少循环的数据依赖,从而利用流水线并行执行;对于第6章,则是从两个方面(temporary、spatial)利用数据的“本地性”。
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] /* ! */
}
}
}
以上的关键语句中的乘法和加法已经实现了循环之间独立,src也是按照行读入的,但是dst却是按照列读入的,这样没有充分利用每一次读入的block。于是我们想到可不可以每一次读入dst[j*dim + i]
所在的block之后继续写入例如dst[j*dim + i + 1]
dst[j*dim + i + 2]
这样的变量,但是这样有需要src的部分变为src[(i+1)*dim +j]
等等,所以我们现在不仅要“横向”扩展dst,还要“纵向”扩展src,其实这是一种叫做blocking的技术,即每次读入一块数据,对此块数据完全利用后抛弃,然后读取下一个块。可以参考csapp网上给的注解:MEM:BLOCKING — Using blocking to increase temporal locality
设我们的数据块的宽度是B,由于我们要对两个数组进行读写操作,所以2B^2 < C(其中C是cache的容量),在此限制下B尽可能取大。
#define B chunkdatas_length_of_side
void faster_transpose(int *dst, int *src, int dim)
{
long limit = dim * dim;
for (int i = 0; i < dim; i += B)
{
for (int j = 0; j < dim; j += B)
{
/* Using blocking to improve temporal locality */
for (int k = i; k < i+B; ++k)
{
for (int l = j; l < j+B; ++l)
{
/* independent calculations */
int d = l*dim + k;
int s = k*dim + l;
if (s < limit && d < limit)
{
dst[d] = src[s]
}
}
}
}
}
}
6.46
这个题仅仅是6.45的一个实践版。但这个题有一个小技巧,就是G[d] || G[s]
这个运算对于G[d]和G[s]都是一样的,所以只用计算一次,从而我们只用计算对角线的上半部分的内容,也就是第二外层循环的j不用从0而是从最外层循环的i开始。
#define B chunkdatas_length_of_side
void faster_col_convert(int *G, int dim)
{
long limit = dim * dim;
for (int i = 0; i < dim; i += B)
{
for (int j = i; j < dim; j += B)
{
/* Using blocking to improve temporal locality */
for (int k = i; k < i+B; ++k)
{
for (int l = j; l < j+B; ++l)
{
/* independent calculations */
int d = l*dim + k;
int s = k*dim + l;
if (s < limit && d < limit)
{
_Bool temp = G[d] || G[s];
G[d] = temp;
G[s] = temp;
}
}
}
}
}
}
深入理解计算机系统_3e 第六章家庭作业 CS:APP3e chapter 6 homework的更多相关文章
- 深入理解计算机系统_3e 第十一章家庭作业 CS:APP3e chapter 11 homework
注:tiny.c csapp.c csapp.h等示例代码均可在Code Examples获取 11.6 A. 书上写的示例代码已经完成了大部分工作:doit函数中的printf("%s&q ...
- 深入理解计算机系统_3e 第七章家庭作业 CS:APP3e chapter 7 homework
7.6 +-----------------------------------------------------------------------+ |Symbol entry? Symbol ...
- 深入理解计算机系统_3e 第五章家庭作业 CS:APP3e chapter 5 homework
5.13 A. B. 由浮点数加法的延迟,CPE的下界应该是3. C. 由整数加法的延迟,CPE的下界应该是1. D. 由A中的数据流图,虽然浮点数乘法需要5个周期,但是它没有"数据依赖&q ...
- 深入理解计算机系统_3e 第三章家庭作业 CS:APP3e chapter 3 homework
3.58 long decode2(long x, long y, long z) { int result = x * (y - z); if((y - z) & 1) result = ~ ...
- 深入理解计算机系统_3e 第九章家庭作业 CS:APP3e chapter 9 homework
9.11 A. 00001001 111100 B. +----------------------------+ | Parameter Value | +--------------------- ...
- 深入理解计算机系统_3e 第二章家庭作业 CS:APP3e chapter 2 homework
初始完成日期:2017.9.26 许可:除2.55对应代码外(如需使用请联系 randy.bryant@cs.cmu.edu),任何人可以自由的使用,修改,分发本文档的代码. 本机环境: (有一些需要 ...
- 深入理解计算机系统_3e 第四章家庭作业(部分) CS:APP3e chapter 4 homework
4.52以后的题目中的代码大多是书上的,如需使用请联系 randy.bryant@cs.cmu.edu 更新:关于编译Y86-64中遇到的问题,可以参考一下CS:APP3e 深入理解计算机系统_3e ...
- 深入理解计算机系统_3e 第八章家庭作业 CS:APP3e chapter 8 homework
8.9 关于并行的定义我之前写过一篇文章,参考: 并发与并行的区别 The differences between Concurrency and Parallel +---------------- ...
- 深入理解计算机系统_3e 第十章家庭作业 CS:APP3e chapter 10 homework
10.6 1.若成功打开"foo.txt": -->1.1若成功打开"baz.txt": 输出"4\n" -->1.2若未能成功 ...
随机推荐
- SQL命令语句小技巧
1.[ ]的使用 当我们所要查的表是系统关键字或者表名中含有空格时,需要用[]括起来,例如新建了两个表,分别为user,user info,那么select * from user和select * ...
- TextView SpannableString 使用之实现可点击超链接效果
TextView SpannableString 使用之实现可点击超链接效果 如果看到这里说明你对 TextView 已经有了一定的了解,至少已经使用过该控件显示文字过.现在来实现一些复杂一点的效果. ...
- 对于php-fpm和cgi,还有并发响应的理解
参考链接: - https://www.zhihu.com/question/64414628 php fpm 进程数和并发数是什么关系? - https://segmentfault.com/q ...
- Python PycURL 网络编程
http://blog.chinaunix.net/uid-20544356-id-290882.html 在使用urllib的时候经常会死掉,以前debug过,是没有设置 timing out 所以 ...
- MySQL Flush Data
http://dimitrik.free.fr/db_STRESS_MySQL_540_Purge_Lag_and_Ahead_Flushing_Jun2009.html http://dimitri ...
- YII2 models非常好用的控制输出数据【重写Fields】
models里重写Fields真的很好用,用于分类.评论功能 列子:评论表models/Comment.php 1.关联商品表 2.获取父级(即管理员)评论 public function Field ...
- Go环境搭建
Linux系统golang环境搭建 1.下载安装包go1.8.linux-amd64.tar golang安装包下载地址:https://golang.org/dl/ ( 有可能被FQ) 2.解 ...
- android studio 的自动更新问题
地址背墙了 没办法... 只有另寻他法了: 在Android Studio安装目录/bin/studio(对应版本, x86, x64).vmoptions文件中追加以下几行 -Djava.net.p ...
- win10下Anaconda 2 和 3 共存安装,并切换jupyter notebook和Pycharm中的对应版本
win10下Anaconda 2 和 3 共存安装,并切换jupyter notebook和Pycharm中的对应版本 zoerywzhou@163.com http://www.cnblogs.co ...
- Anaconda 安装 Python 库(MySQLdb)的方法
[已解决]Anaconda 安装 Python 库(MySQLdb)的方法 zoerywzhou@163.com http://www.cnblogs.com/swje/ 作者:Zhouwan 201 ...