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