深入理解计算机系统(第二版) 家庭作业 第六章
2013-08-24 13:18
3019 查看
6.23
我们可以认为,磁道沿半径方向是均匀分布的。假设半径为r的磁盘总的磁道是K,那么除掉内部的x*r(磁道数为x*K),剩下的磁道数为 (1-x)*K。
那么总容量为 2*pi*x*r*(1-x)*K,其中pi,r和K都是常数,那么只剩下x*(1-x)。
这个函数在x = 0.5的时候取最大。
6.24
T_seek = 3 ms
T_maxrotate = 60*1000/12000 ms = 5 ms
T_avgrotate = 0.5*T_maxrotate = 2.5 ms
T_transfer = T_maxrotate/500 = 0.01 ms
T = T_seek + T_avgrotate + T_transfer = 5.51 ms
6.25
3MB文件,我们假设1MB = 1000KB,而1KB = 1024B(这个好算一些)。
那么3MB文件就有3000个逻辑块(扇区),需要读6个磁道。
T_maxrotate = 5 ms
T_transfer = 0.01 ms
A.最好情况是6个磁道都在一个柱面上,只需要寻一次道,而且文件是顺序存储。
T = T_seek + 0.5*T_maxrotate + 6*T_maxrotate = 35.5ms
B. 最差的情况 3000*(T_seek + 0.5*T_maxroate + T_transfer) = 16530ms
6.26
6.27
感觉最后一行答案有错误,C应该是4096,或者t是23,或者E为2。
6.28_6.29
Address_start = (tag<<5) | (set<<2);
Address_end = (tag<<5) | (set<<2) | 3;
6.30
b = 2, s = 2, t = 12 - b - s = 8;
A.
B.
6.31
A. C = E*B*S = 128 字节
B. b = 2, s = 3, t = 13-b-s = 8;
6.32
A.0x0718
B.
6.33
A.0x16EC
B.
6.34
0x1314-0x1317
0x1794-0x1797
6.35
对于写分配的高速缓存,每次写不命中时,需要读取数据到高速缓存中。
该高速缓存只有2个组,对于相同的i,j,src[i][j]和dst[i][j]对应相同的组。
src[0] src[2] 对应组0;
src[1] src[3] 对于组1。
dst同src。
6.36
缓存能完全容得下两个数组,所以只会出现冷不命中。
6.37
A.缓存为1024字节,数组大小为2*256*4=2048,所以x[0]和x[1]的每一个元素(x[0][i]和x[1][i])对应的高速缓存是同一个块。
因此,每次都在加载,驱逐。不命中率为100%。
B. 缓存足够大,只有冷不命中,不命中率为1/8 = 12.5%。
C. 这种情况相当于是只有冷不命中,不命中率为12.5%。
D. 不会降低,因为块大小不变时,冷不命中的概率不可能被减小。
E. 会降低,因为一个块的大小增加,冷不命中的频率就降低。
6.38
写了个程序进行测试的。
结果如下:
程序清单:
unsigned calc_address(unsigned head, int i, int j, int N)
{
return head + i*N*4 + j*4;
}
unsigned calc_line(unsigned add, int block_size, const int line)
{
return (add / block_size) % line;
}
int isHit(unsigned cache[], unsigned r, unsigned a, int block_size)
{
a = a / block_size * block_size;
unsigned tmp = cache[r];
cache[r] = a;
return tmp == a;
}
void testA(int block_size, const int line, unsigned add, const int N)
{
unsigned cache[line];
memset(cache, -1, sizeof(cache));
int hit = 0, miss = 0;
for(int i=0; i<N; ++i)
for(int j=0; j<N; ++j)
{
unsigned address = calc_address(add, i, j, N);
unsigned r = calc_line(address, block_size, line);
hit += isHit(cache, r, address, block_size);
}
miss = N*N - hit;
cout << "sumA " << hit << " " << miss << endl;
cout << (double)miss/(N*N) << endl;
}
void testB(int block_size, const int line, unsigned add, const int N)
{
unsigned cache[line];
memset(cache, -1, sizeof(cache));
int hit = 0, miss = 0;
for(int j=0; j<N; ++j)
for(int i=0; i<N; ++i)
{
unsigned address = calc_address(add, i, j, N);
unsigned r = calc_line(address, block_size, line);
hit += isHit(cache, r, address, block_size);
}
miss = N*N - hit;
cout << "sumB " << hit << " " << miss << endl;
cout << (double)miss/(N*N) << endl;
}
void testC(int block_size, const int line, unsigned add, const int N)
{
unsigned cache[line];
memset(cache, -1, sizeof(cache));
int hit = 0, miss = 0;
for(int j=0; j<N; j+=2)
for(int i=0; i<N; i+=2)
{
unsigned a, r;
a = calc_address(add, i, j, N);
r = calc_line(a, block_size, line);
hit += isHit(cache, r, a, block_size);
a = calc_address(add, i+1, j, N);
r = calc_line(a, block_size, line);
hit += isHit(cache, r, a, block_size);
a = calc_address(add, i, j+1, N);
r = calc_line(a, block_size, line);
hit += isHit(cache, r, a, block_size);
a = calc_address(add, i+1, j+1, N);
r = calc_line(a, block_size, line);
hit += isHit(cache, r, a, block_size);
}
miss = N*N - hit;
cout << "sumC " << hit << " " << miss << endl;
cout << (double)miss/(N*N) << endl;
}
void testHit()
{
const unsigned start_address = 0x08000000;
const int cache_size = 4*1024;
const int block_size = 16;
int line = cache_size / block_size;
int N = 64;
cout << N << endl;
testA(block_size, line, start_address, N);
testB(block_size, line, start_address, N);
testC(block_size, line, start_address, N);
cout << "-----" << endl;
N = 60;
cout << N << endl;
testA(block_size, line, start_address, N);
testB(block_size, line, start_address, N);
testC(block_size, line, start_address, N);
}
6.39
A. 写总数为 16*16*4 = 1024
B C. 这种情况只有冷不命中,一个block能存下16个int,不命中率为1/16。不命中总数为64。
6.40
A. 写总数为 16*16*4 = 1024
B C.
E = 1024/64 = 16,每4行才能容得下数组的一行,每次j在变化时,都会不断驱逐掉之前的缓存。所以,只有循环内是可以命中的。不命中率为1/4,不命中总数为256。
6.41
A. 写总数为 16*16*4 = 1024
B.
一行能保持4个square结构体的值,所以第一个双循环不命中率为1/4。
第二个双循环,不命中率为1/12。
总的不命中次数为 16*16/4 + 16*16*3/12 = 16*16/2 = 128。
C. 不命中率为 1/8。
前的缓存。所以,只有循环内是可以命中的。不命中率为1/4,不命中总数为256。
6.42
每行只有4个字节,那只可能是循环中后三个命中,第一个不命中,不命中率为0.25。
感觉这个题目设定应该不是每行4个字节,64个字节也好啊。
6.43
和上题一样,每次要写一个char,不命中率仍然为0.25。
6.44
每次写一个int,每次都不会命中。不命中率为100%。
6.45
固定stride,看吞吐量随着工作集大小改变的情况。
那个mountain的程序不会用,心想还是先看完书,所以也没花功夫看。
6.46 6.47暂时都没想到
可能的想法是,将两层循环都进行二展开,这样至少可以:
dst[j*dim+i] = src[i*dim+j];
dst[(j+1)*dim+i] = src[i*dim+j+1];
dst[j*dim+i+1] = src[(i+1)*dim+j];
dst[(j+1)*dim+i+1] = src[(i+1)*dim+j+1];
只要不是遇到缓存抖动,不命中率最多就是50%,还是会比较低的。
如果加入运算,就可以想办法同时更新 dst[i][j], dst[j][i]。
但是这样读不命中就可能高了。
等待高人回答吧!
我们可以认为,磁道沿半径方向是均匀分布的。假设半径为r的磁盘总的磁道是K,那么除掉内部的x*r(磁道数为x*K),剩下的磁道数为 (1-x)*K。
那么总容量为 2*pi*x*r*(1-x)*K,其中pi,r和K都是常数,那么只剩下x*(1-x)。
这个函数在x = 0.5的时候取最大。
6.24
T_seek = 3 ms
T_maxrotate = 60*1000/12000 ms = 5 ms
T_avgrotate = 0.5*T_maxrotate = 2.5 ms
T_transfer = T_maxrotate/500 = 0.01 ms
T = T_seek + T_avgrotate + T_transfer = 5.51 ms
6.25
3MB文件,我们假设1MB = 1000KB,而1KB = 1024B(这个好算一些)。
那么3MB文件就有3000个逻辑块(扇区),需要读6个磁道。
T_maxrotate = 5 ms
T_transfer = 0.01 ms
A.最好情况是6个磁道都在一个柱面上,只需要寻一次道,而且文件是顺序存储。
T = T_seek + 0.5*T_maxrotate + 6*T_maxrotate = 35.5ms
B. 最差的情况 3000*(T_seek + 0.5*T_maxroate + T_transfer) = 16530ms
6.26
高速 缓存 | m | C | B | E | S | t | s | b |
1 | 32 | 2048 | 4 | 4 | 128 | 23 | 7 | 2 |
2 | 32 | 2048 | 4 | 512 | 1 | 30 | 0 | 2 |
3 | 32 | 2048 | 8 | 1 | 256 | 21 | 8 | 3 |
4 | 32 | 2048 | 8 | 128 | 2 | 28 | 1 | 3 |
5 | 32 | 2048 | 32 | 1 | 64 | 21 | 6 | 5 |
6 | 32 | 2048 | 32 | 4 | 16 | 23 | 4 | 5 |
高速 缓存 | m | C | B | E | S | t | s | b |
1 | 32 | 8192 | 16 | 1 | 512 | 19 | 9 | 4 |
2 | 32 | 4096 | 4 | 4 | 256 | 22 | 8 | 2 |
3 | 32 | 4096 | 4 | 8 | 128 | 23 | 7 | 2 |
4 | 32 | 2048 | 32 | 4 | 16 | 22 | 4 | 5 |
6.28_6.29
Address_start = (tag<<5) | (set<<2);
Address_end = (tag<<5) | (set<<2) | 3;
| 行1 | 行2 |
组0 | 0x0120-0x0123 | - |
组1 | 0x08A4-0x08A7 | 0x0704-0x0707 |
组2 | - | - |
组3 | - | 0x064C-0x064F |
组4 | 0x18F0-0x18F3 | 0x00B0-0x00B3 |
组5 | 0x0E34-0x0E37 | - |
组6 | 0x1238-0x123B | - |
组7 | - | 0x1BDC-0x1BDF |
b = 2, s = 2, t = 12 - b - s = 8;
A.
11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
CT | CT | CT | CT | CT | CT | CT | CT | CI | CI | CO | CO |
操作 | 地址 | 命中? | 读出的值 |
读 | 0x409 | No | - |
写 | 0x40A | Yes | - |
读 | 0x833 | Yes | 0xD0 |
A. C = E*B*S = 128 字节
B. b = 2, s = 3, t = 13-b-s = 8;
12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
CT | CT | CT | CT | CT | CT | CT | CT | CI | CI | CI | CO | CO |
A.0x0718
12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 |
参数 | 值 |
块偏移CO | 0x00 |
索引CI | 0x6 |
标记CT | 0x38 |
命中? | Yes |
返回值 | 0xFA |
A.0x16EC
12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
1 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 0 | 0 |
参数 | 值 |
块偏移CO | 0x00 |
索引CI | 0x3 |
标记CT | 0xB7 |
命中? | No |
返回值 | - |
0x1314-0x1317
0x1794-0x1797
6.35
对于写分配的高速缓存,每次写不命中时,需要读取数据到高速缓存中。
该高速缓存只有2个组,对于相同的i,j,src[i][j]和dst[i][j]对应相同的组。
src[0] src[2] 对应组0;
src[1] src[3] 对于组1。
dst同src。
dst数组 | ||||
| 列0 | 列1 | 列2 | 列3 |
行0 | m | h | m | h |
行1 | m | m | h | m |
行2 | m | h | m | h |
行3 | m | m | h | m |
src数组 | ||||
| 列0 | 列1 | 列2 | 列3 |
行0 | m | m | m | m |
行1 | m | m | m | m |
行2 | m | m | m | m |
行3 | m | m | m | m |
缓存能完全容得下两个数组,所以只会出现冷不命中。
dst数组 | ||||
| 列0 | 列1 | 列2 | 列3 |
行0 | m | h | h | h |
行1 | m | h | h | h |
行2 | m | h | h | h |
行3 | m | h | h | h |
src数组 | ||||
| 列0 | 列1 | 列2 | 列3 |
行0 | m | h | h | h |
行1 | m | h | h | h |
行2 | m | h | h | h |
行3 | m | h | h | h |
A.缓存为1024字节,数组大小为2*256*4=2048,所以x[0]和x[1]的每一个元素(x[0][i]和x[1][i])对应的高速缓存是同一个块。
因此,每次都在加载,驱逐。不命中率为100%。
B. 缓存足够大,只有冷不命中,不命中率为1/8 = 12.5%。
C. 这种情况相当于是只有冷不命中,不命中率为12.5%。
D. 不会降低,因为块大小不变时,冷不命中的概率不可能被减小。
E. 会降低,因为一个块的大小增加,冷不命中的频率就降低。
6.38
写了个程序进行测试的。
结果如下:
函数 | N=64 | N=60 |
sumA | 0.25 | 0.25 |
sumB | 1 | 0.25 |
sumC | 0.5 | 0.25 |
unsigned calc_address(unsigned head, int i, int j, int N)
{
return head + i*N*4 + j*4;
}
unsigned calc_line(unsigned add, int block_size, const int line)
{
return (add / block_size) % line;
}
int isHit(unsigned cache[], unsigned r, unsigned a, int block_size)
{
a = a / block_size * block_size;
unsigned tmp = cache[r];
cache[r] = a;
return tmp == a;
}
void testA(int block_size, const int line, unsigned add, const int N)
{
unsigned cache[line];
memset(cache, -1, sizeof(cache));
int hit = 0, miss = 0;
for(int i=0; i<N; ++i)
for(int j=0; j<N; ++j)
{
unsigned address = calc_address(add, i, j, N);
unsigned r = calc_line(address, block_size, line);
hit += isHit(cache, r, address, block_size);
}
miss = N*N - hit;
cout << "sumA " << hit << " " << miss << endl;
cout << (double)miss/(N*N) << endl;
}
void testB(int block_size, const int line, unsigned add, const int N)
{
unsigned cache[line];
memset(cache, -1, sizeof(cache));
int hit = 0, miss = 0;
for(int j=0; j<N; ++j)
for(int i=0; i<N; ++i)
{
unsigned address = calc_address(add, i, j, N);
unsigned r = calc_line(address, block_size, line);
hit += isHit(cache, r, address, block_size);
}
miss = N*N - hit;
cout << "sumB " << hit << " " << miss << endl;
cout << (double)miss/(N*N) << endl;
}
void testC(int block_size, const int line, unsigned add, const int N)
{
unsigned cache[line];
memset(cache, -1, sizeof(cache));
int hit = 0, miss = 0;
for(int j=0; j<N; j+=2)
for(int i=0; i<N; i+=2)
{
unsigned a, r;
a = calc_address(add, i, j, N);
r = calc_line(a, block_size, line);
hit += isHit(cache, r, a, block_size);
a = calc_address(add, i+1, j, N);
r = calc_line(a, block_size, line);
hit += isHit(cache, r, a, block_size);
a = calc_address(add, i, j+1, N);
r = calc_line(a, block_size, line);
hit += isHit(cache, r, a, block_size);
a = calc_address(add, i+1, j+1, N);
r = calc_line(a, block_size, line);
hit += isHit(cache, r, a, block_size);
}
miss = N*N - hit;
cout << "sumC " << hit << " " << miss << endl;
cout << (double)miss/(N*N) << endl;
}
void testHit()
{
const unsigned start_address = 0x08000000;
const int cache_size = 4*1024;
const int block_size = 16;
int line = cache_size / block_size;
int N = 64;
cout << N << endl;
testA(block_size, line, start_address, N);
testB(block_size, line, start_address, N);
testC(block_size, line, start_address, N);
cout << "-----" << endl;
N = 60;
cout << N << endl;
testA(block_size, line, start_address, N);
testB(block_size, line, start_address, N);
testC(block_size, line, start_address, N);
}
6.39
A. 写总数为 16*16*4 = 1024
B C. 这种情况只有冷不命中,一个block能存下16个int,不命中率为1/16。不命中总数为64。
6.40
A. 写总数为 16*16*4 = 1024
B C.
E = 1024/64 = 16,每4行才能容得下数组的一行,每次j在变化时,都会不断驱逐掉之前的缓存。所以,只有循环内是可以命中的。不命中率为1/4,不命中总数为256。
6.41
A. 写总数为 16*16*4 = 1024
B.
一行能保持4个square结构体的值,所以第一个双循环不命中率为1/4。
第二个双循环,不命中率为1/12。
总的不命中次数为 16*16/4 + 16*16*3/12 = 16*16/2 = 128。
C. 不命中率为 1/8。
前的缓存。所以,只有循环内是可以命中的。不命中率为1/4,不命中总数为256。
6.42
每行只有4个字节,那只可能是循环中后三个命中,第一个不命中,不命中率为0.25。
感觉这个题目设定应该不是每行4个字节,64个字节也好啊。
6.43
和上题一样,每次要写一个char,不命中率仍然为0.25。
6.44
每次写一个int,每次都不会命中。不命中率为100%。
6.45
固定stride,看吞吐量随着工作集大小改变的情况。
那个mountain的程序不会用,心想还是先看完书,所以也没花功夫看。
6.46 6.47暂时都没想到
可能的想法是,将两层循环都进行二展开,这样至少可以:
dst[j*dim+i] = src[i*dim+j];
dst[(j+1)*dim+i] = src[i*dim+j+1];
dst[j*dim+i+1] = src[(i+1)*dim+j];
dst[(j+1)*dim+i+1] = src[(i+1)*dim+j+1];
只要不是遇到缓存抖动,不命中率最多就是50%,还是会比较低的。
如果加入运算,就可以想办法同时更新 dst[i][j], dst[j][i]。
但是这样读不命中就可能高了。
等待高人回答吧!
相关文章推荐
- CSAPP(深入理解计算机系统)第二版家庭作业答案-第二章
- 深入理解计算机系统(第二版) 家庭作业 第三章
- 深入理解计算机系统(第二版) 家庭作业 第四章
- 深入理解计算机系统第二版家庭作业2.66
- 深入理解计算机系统(第二版) 家庭作业 第十章
- 深入理解计算机系统(第二版) 家庭作业 第二章
- 深入理解计算机系统(第二版) 家庭作业 第十一章
- 深入理解计算机系统_3e 第六章家庭作业 CS:APP3e chapter 6 homework
- 深入理解计算机系统(第二版) 家庭作业 第五章
- 深入理解计算机系统(第二版) 家庭作业 第八章
- 深入理解计算机系统(第二版) 家庭作业 第七章
- 深入理解计算机系统(第二版)家庭作业解答
- 深入理解计算机系统家庭作业第六章
- CSAPP(深入理解计算机系统)第二版家庭作业答案-第三章
- 深入理解计算机系统_3e 第八章家庭作业 CS:APP3e chapter 8 homework
- 深入理解计算机系统第二版习题解答CSAPP 2.9
- 深入理解计算机系统(第二版)----之二:(一:程序的结构和执行)信息的表示和处理
- 深入理解计算机系统(第二版)----之1:(三:程序间的交互和通信)系统级 IO
- 深入理解计算机系统家庭作业第四章(4.43-4.54)
- 深入理解计算机系统_3e 第四章家庭作业(部分) CS:APP3e chapter 4 homework