【仅供参考】Csapp第六章课后习题答案(欢迎批评指正)

6.22

【答案】 x = 0.5

【解释】

假设磁道延半径均匀分布,则磁道数 = r - x*r = (1 - x) * r,而每个磁道位数 = k * 2πxr;

所以总位数 = k*2πrx * (1-x)*r = 2kπr²x(1-x),易知x = 0.5时取最大值。

6.23

【答案】

平均寻道时间:T_avg_seek​=4ms

平均旋转时间:T_avg_rotation​ = 0.5*1/15000 *60s/min *1000ms/s= 2ms

平均传送时间:T_avg_transfer =2* T_avg_rotation​ /800 = 0.005ms

总时间:T = 6.005ms

6.24

【答案】

A.最优时间为22ms

B.随机时间为24s

【解释】

A.最优情况,我们假设所有的文件快连续储存,并且在同一柱面。

平均寻道时间:T_avg_seek​=4ms

平均旋转时间:T_avg_rotation​ = 0.5*1/15000 *60s/min *1000ms/s= 2ms

首先计算块数 = 2MB/512字节 = 4000块,根据我们假设的情况只需要一次寻道,需要转4圈,

每一圈的时间T_max_rotation,四圈的总时间= T_max_rotation*4 = 4* 4 = 16ms

第一个块定位时间 = T_avg_seek​+T_avg_rotation = 6s

所以总时间 = 第一个块定位时间+四圈的时间 = 6+16 = 22ms

B.若随机映射,则每次读一个块都需要定位,所以总时间 = 4000*6 = 24s

6.25

【答案】

高速缓存 m C B E S t s b
1. 32 1024 4 4 64 24 6 2
2. 32 1024 4 256 1 30 0 2
3. 32 1024 8 1 128 22 7 3
4. 32 1024 8 128 1 29 0 3
5. 32 1024 32 1 32 22 5 5
6. 32 1024 32 4 8 24 3 5

【解释】

以第一行为例,b = log₂(B) =  log₂(4) = 2,s =  log₂(S) = 6,t = m-b-s = 32-2-6 = 24

6.26

【答案】

高速缓存 m C B E S t s b
1. 32 2048 8 1 256 21 8 3
2. 32 2048 4 4 128 23 7 2
3. 32 1024 2 8 64 25 6 1
4. 32 1024 32 2 16 23 4 5

【解释】参考上题

6.27

【答案】

A.命中行0组1地址范围:0x08A4~0x08A7
    命中行1组1地址范围:0x0704~0x0707

B.命中行0组6地址范围:0x1238~0x123B

【解释】

以命中行0组1字节0为例:本题中标记位有8位,索引位有3位,偏移位有2位

       标记位:0x45 二进制表示 :0100 0101

       索引位:0x1   二进制表示 :001

       偏移位:0x0   二进制表示 :00

对应地址为0100 0101 001 00 便于看我们改一下分隔0 1000 1010 0100

所以对应地址为0x08A4,其他的以此类推。

6.28

【答案】

A.没有

B.命中行0组4地址范围:0x18F0-0x18F3

   命中行1组4地址范围:0x00B0-0x00B3

C.命中行0组5地址范围:0x0E34-0x0E37

D.命中行1组7地址范围: 0x1BDC-0x1BDF

【解释】见上题

6.29

A.0 1 偏移位CO,2 3索引位为CI,其余为CT.

B.

操作 地址 命中 读出的值
0x834 不命中 ——
0x836 命中 未知
0xFFD 命中 0xC0

【解释】

A.B = 4, 则b(即CO) = 2,S=4,则s(即CI) = 2

B.地址0x834转换为二进制为1000 0011 0100,所以CO为00 = 0,CI为01 = 1,CT为1000 0011 = 83,所以对应到cache为组1,标记83,字节0,此时我们可以看到会发生不命中,接下来会从内存中加载4个字节进来,再读出对应的值,但是值我们未知。题目说内存访问顺序执行,则第二次进行写的时候因为从内存中加载进来4个字节,要写的内容在上一步要读的数据后面两个字节,所以被一同加载了进来,这样写就命中,最后的读命中,内容也易知。

6.30

【答案】

A.B*E*S = 4*4*8=128字节

B.0 1 偏移位CO,2 3 4索引位为CI,其余为CT.

6.31

【答案】

A.0 0111 0001 1010

B.

参数
高速缓存块偏移(CO) 0x2
高速缓存组索引(CI) 0x6
高速缓存标记(CT) 0x38
高速缓存命中? 命中
返回的高速缓存字节 0xEB

【解释】

B.对于组相联cache,因为要搜索每一行,找到一个有效行,首先在组6行0,我们找到标记38,但是其有效位为0,所以会继续搜寻,找到行3,标记38,有效位为1,对应偏移量2为0xEB.

6.32

【答案】

A.1 0110 1111 1000

B.略

6.33

【答案】

命中行0:0x1788-0x178B

命中行1:0x16C8-0x16CB

【解释】

注意只有行0与行1有效位为1.

6.34

【答案】

dst数组 列0 列1 列2 列3
行0 m m m m
行1 m m m m
行2 m m m m
行3 m m m m
src数组 列0 列1 列2 列3
行0 m m h m
行1 m h m h
行2 m m h m
行3 m h m h

【解释】

首先我们要明确这个cache的基本参数:b = 4,s = 1,m = 7 (因为内存连续储存,从地址0到地址127,一共128个数,所以需要7位来表示),接下来我们需要明确映射关系,因为这个高速缓存只有32字节,所以当存到32的时候高速缓存就存满了,那么接下来就要回到开头重新存,同理每隔32字节就要从头开始存储(为了便于理解,我把地址列出来,src[0][0]的地址是0,对应二进制也就是00 0 0000(注意此处的间隔,分别是标记位,索引位,偏移位),因为是内存按行存储的所以,存到src[1][3],就满了,接下来是src[2][0],地址为32,对应的二进制为01 0 0000,我们观察组索引,和偏移量可以发现,src[0][0]和src[2][0],映射到同一块高速缓存,同理dst[0][0](地址为64对应的二进制为10 0 0000,dst[2][0]地址为11 0 0000,观察组索引和偏移量我们可以发现,这俩也映射到cache最头上),那么src[0][0],src[2][0],dst[0][0],dst[2][0]这四个都映射到cache最头上,那么类推就知道src[0][1],src[2][1],dst[0][1],dst[2][1]这四个都映射到cache第一行偏移1的位置,后面也一样类推。

好接下来就开始映射了,首先读src[0][0],最开始cache是空的,所以未命中,然后就要把src[0][0]加载进来,因为预存,所以后面三个也被加载进来到第一行,然后写dst[0][0],未命中,那么就要把dst[0][0]的地址加载进来,同样预存,那么src[0][0]以及后面三个就要被覆盖了,接下来读src[0][1],因为上一步的写dst[0][0]把原本预存的src[0][1]给覆盖了,所以还是未命中,后面就这样推,一样的道理。

6.36

【答案】

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

【解释】道理和上面一道题类似,但是这个高速缓存为128字节,能够装下两个数组,所以不会有不同的数组映射到同一块cache,所以每次只有开始的冷不命中,后买三个因为预存所以会命中。

6.36

【答案】

A.100%

B.25%

C.25%

D.不会,组相连的命中率是和你能预存进来的块的个数相关的,行替换是有空行用空行,行数的改变不会影响命中率,影响命中率的其实是块的大小。

E.会,更大的块则预存会会存进来更多的块,那么命中率就会提高。

【解释】

A.因为你一次最多只能加载满这个数组的一行,而在这个循环中是交替读这个数组的两行,所以没读完一次,就会被覆盖,那么每次都不命中。

B.1024字节正好装下所有数组,所以只会发生冷不命中。

C.读数组的第一行,会加载到一个组的第一行,读数组的第二行会加载到同一组的第二行(因为组相联是有空行首先用空行),所以只有每次的冷不命中。

6.37

【答案】

函数 N=64 N=60
sumA 25% 25%
sumB 100% 25%
sumC 50%

25%

【解释】

N = 64就是正常的情况,我们主要讨论N= 60的sumB,sumC

为了便于想,我们给256个块取号从0~255,对于sumB,我们以a[0][0]~a[60][0]的访问为例子,
它的访问顺序为0, 15, 30, 45, 60…255,14,29,44,59…254, 13, 28, 43, 58…254, 12, 27, 42, 57, 72, 87, 102, 117(sumB是按列读取的,因为a[1][0]的地址与a[0][0]相差60,所以在cache中相差15行,对应的块号就是15,后面以此类推,要注意最后读完a[16][0]高速缓存还剩一行,所以再一轮循环,首个要读的块就要减去1,那么就是14,后面以此类推)那么我们发现它并不会覆盖前面已经完成预存,所以只有冷不命中。C类推。

个人认为这是一种类似于修正“抖动”的方法,有点像课本P432的修正抖动的方法。

6.38

【答案】

A.16*16*4 = 1024

B.16*16*4*1/8 = 128

C.1/8

【解释】

只有冷不命中

6.39

【答案】

A.16*16*4 = 1024

B.16*16*4*1/4 = 256

C.1/4

【解释】

如果把结构体看作一个整体,则每次都是不命中,但对于每个结构体内会发生冷不命中。

6.40

【答案】

A.1024

B.16*16*1/2+16*16*1/6 = 256

C.1/4

【解释】

第一个循环有一半不命中,第二个循环六个中只有一个不命中

6.41

【答案】

25%

【解释】

因为高速缓存能够容下全部的数组,所以只会发生冷不命中

6.42

【答案】

25%

【解释】

本质上和上题一样,只是循环条件改成了地址的形式

6.43

【答案】

25%

6.44

6.45

【答案】我们考虑充分利用写数组,因为前面的写数组都是写一次后就将这部分抛弃掉,

我们假设数据块得到宽度为B,不仅要延展src,而且要对dst进行延展。

#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]
					}
				}
			}

		}
	}
}

你可能感兴趣的:(c语言)