存储器层次结构(二)

存储器层次结构(二)

参考文献:

[1]Randal E.Bryant、David R. O’Hallaron.Computer Systems A Programmer’s Perspective Third Edition 北京:机械工业出版社,2017.4

[2]蒋本珊.计算机组成原理(第3版)[M].北京:清华大学出版社,2013;

目录:

1、存储器层次结构中的缓存:

2、高速缓存存储器:

3、直接映射高速缓存:

4、为什么用中间的位来做索引?

5、i7的高速缓存层次结构:

6、高速缓存行、组和块的区别:

7、高速缓存友好问题:

8、假设有一个如下属性的系统:

9、有关写的问题:

10、命中率与命中时间与不命中处罚:

 

1、存储器层次结构中的缓存:

(1)存储器层次结构的中心思想:

对于每个k,位于k层的更快更小的存储设备作为位于k+1层的更慢更大的存储设备的缓存。即层次结构中的每一层都缓存来自较低一层的数据对象。

(2)数据传送形式:

数据总是以块大小为传送单元(transfer unit)在第k层和第k+1层之间来回复制的。

(3)缓存覆盖:

覆盖一个现存的块的过程称为替换(replacing)或驱逐(evicting)这个块。被驱逐的这个块有时也称为牺牲块(victim block)。决定该替换哪个块是由这个缓存的替换策略(replacement polocy)来控制的。例如,LRU(最近最少被使用)替换策略。

(4)常见缓存:

存储器层次结构(二)_第1张图片


2、高速缓存存储器:

(1)高速缓存的结构:

高速缓存(S,E,B,m),S表示一个高速缓存的组数,E表示一个组中的行数,B表示一行由B个字节的数据块组成,m表示存储器物理地址位数为m位。

(2)m个地址位划分:

m个地址位划分为t个标记位、s个组索引位和b个块偏移位。

(3)高速缓存的容量:

C = S * E * B

(4)当要从某地址读某个字的副本时,当且仅当设置了有效位并且该行的标记位与要读的地址中的标记位相匹配时,组中的这一行才包含这个字。

(5)示例:下表给出了几个不同的高速缓存的参数。确定每个高速缓存的缓存组数(S)、标记位数(t)、组索引数(s)以及块偏移位数(b)。

存储器层次结构(二)_第2张图片

存储器层次结构(二)_第3张图片


3、直接映射高速缓存:

(1)定义:每个组只有一行(E = 1)的高速缓存。

(2)直接映射高速缓存确定一个请求是否命中:

如:当CPU执行一条读内存字w的指令时,它向L1高速缓存请求这个字。

①组选择

高速缓存从w的地址中间抽取出s个组索引位。

②行匹配

当且仅当设置了有效位,而且高速缓存行中的标记与w的地址中的标记相匹配时,这一行中包含w的一个副本。

③字抽取

块偏移位提供了所需要的字的第一个字节的偏移。

 

4、为什么用中间的位来做索引?

假想一个高速缓存,用地址的高s位做组索引,那么内存块连续的片(chunk)会被映射到同一个高速缓存组。

a)每个这样的连续的数组片中有多少个块?

b)考虑下面的代码,它运行在一个高速缓存形式为(S,E,B,m) = (512,1,32,32)的系统上:

int array[4096];

for(i = 0; i < 4096; i++){

sum +=array[i];

}

在任意时刻,存储在高速缓存中的数组块的最大数量为多少?

答:a)t = m - (b + s)个标记位是当前块的内存地址的位的一个子集,它们唯一地标识存储在这个高速缓存行中的块。

用高位做索引,每个连续的数据片由2^t个块组成,因此,数组头2^t个连续的块都会映射到组0,接下来的2^t个块会映射到组1,依次类推。

b)S = 512,E = 1,B = 32,C = 512 * 1 * 32,即高速缓存容量是512个32字节的块,s = log2(512) = 9,b = log2(32) = 5,t = m - b - s = 32 - 5 - 9 = 18,标记位为18,所以数组中头2^18个块会映射到组0,接下来2^18个块会映射到组1。数组的块为4096 * 4 / 32 = 2^9个,所以数组中所有的块都会映射到组0。

因此在任意时刻,高速缓存至多只能保存一个数组块。

 

5、i7的高速缓存层次结构:

(1)i-cache:只保存指令的高速缓存。

(2)d-cache:只保存程序数据的高速缓存。

(3)统一的高速缓存(unified cache):既保存指令又保存数据的高速缓存。

(4)Intel Core i7处理器的每个CPU芯片有四个核。每个核有自己私有的L1 i-cache、L1 d-cache和L2统一的高速缓存。所有的核共享片上L3统一的高速缓存。即所有的SRAM高速缓存存储器都在CPU芯片上。

 

6、高速缓存行、组和块的区别:

(1)块是一个固定大小的信息包,在高速缓存和主存(或下一层高速缓存)之间来回传送。

(2)行是高速缓存中的一个容器,存储块和其他信息(例如有效位和标志位)。

(3)组是一个或多个行的集合。直接映射高速缓存中的组只由一行组成。组相联和全相联高速缓存中的组是由多个行组成的。

 

7、高速缓存友好问题:

(1)对局部变量的反复引用是好的,因为编译器能够将它们缓存在寄存器文件中(时间局部性)。

(2)步长为1的引用模式是好的,因为存储器层次结构中所有层次上的缓存都是将数据存储为连续的块(空间局部性)。

(3)示例:

在一台具有大小为16字节(B = 16)、整个大小为1024字节的直接映射数据缓存的机器上测量它的高速缓存性能。有如下假设:

①sizeof(int) == 4

②grid从内存地址0开始。

③这个高速缓存开始时是空的。

④唯一的内存访问是对数组grid的元素的访问。变量i、j、total_x和total_y存放在寄存器中。

确定下列代码的高速缓存性能:

struct a{

int x;

int y;

};

struct a grid[16][16];

int total_x = 0, total_y = 0;

int i, j;

for(i = 0; i < 16; i++){

for(j = 0; j < 16; j++){

total_x += grid[i][j].x;

tota;_y += grid[i][j].y;

}

}

A)读总数是多少?

读总数 = 16 * 16 * 2 = 512

B)高速缓存的不命中的读总数是多少?

C = S * E * B,B = 16,E = 1,C = 1024,所以S = 64,高速缓存容量是64个16字节的块,数组大小16 * 16 * 8 = 2048字节,所以高速缓存只能保存数组的1 / 2。

每个16字节的高速缓存行包含着两个连续的a结构体,所以grid[0][0]、grid[0][1]放在组索引为0的组中,grid[0][2]、grid[0][3]放在组索引为1的组中,依次类推,grid[7][14]、grid[7][15]放在组索引为63的组中,到了grid[8][0]后,开始驱逐grid[0][0]的元素加载进来的那一行。

程序的循环过程是:

①total_x += grid[i][j].x; grid[0][0]、grid[0][1]进入高速缓存,冷不命中

total_x += grid[i][j].y;grid[0][0]命中

②total_x += grid[i][j].x; grid[0][1]命中

total_x += grid[i][j].y;grid[0][1]命中

重复上述过程,所以都是1次的冷不命中加3次命中。及不命中占总读数的1 / 4,所以不命中的读总数为128次。

C)不命中率是多少?

25%

D)如果高速缓存有两倍大,那么不命中率会是多少?

缓存扩大为两倍,即高速缓存可以保存一整个数组,但奇数次循环过程的冷缓存依旧,不命中率仍然为1 / 4。

示例二:

修改程序:

for(i = 0; i < 16; i++){

for(j = 0; j < 16; j++){

total_x += grid[j][i].x;

tota;_y += grid[j][i].y;

}

}

A)读总数是多少?

B)高速缓存的不命中的读总数是多少?

C)不命中率是多少?

D)如果高速缓存有两倍大,那么不命中率会是多少?

答:A)读总数为512

B)程序的循环过程是:

①total_x += grid[j][i].x; grid[0][0]、grid[0][1]进入高速缓存,冷不命中

total_x += grid[j][i].y;grid[0][0]命中

②total_x += grid[j][i].x; grid[1][0]、grid[1][1]进入高速缓存,冷不命中

total_x += grid[j][i]].y;grid[1][0]命中。

重复上述过程,直到跳回第一层循环:

③total_x += grid[j][i].x; grid[8][0]、grid[8][1]进入高速缓存,驱逐了grid[0][0]、grid[0][1]所在行,冷不命中

total_x += grid[j][i]].y;grid[8][0]命中。

因为驱逐了grid[0][0]、grid[0][1]所在行,所以当下一次循环i = 1的时候,grid[0][0]、grid[0][1]所在行的缓存已经不存在,需要重新进入,所以每次循环都会有一次的冷不命中以及一次的命中。

所以不命中的读总数为256.

C)50%

D)缓存扩大为两倍,即高速缓存可以保存一整个数组,所以循环的过程中不会对原来的缓存进行驱逐,所有的不命中都是最开始时的一次冷不命中,则不命中率为25%。

 

8、假设有一个如下属性的系统:

①内存是字节寻址的。

②内存访问是对1字节字的(而不是4字节字)。

③地址宽12位。

④高速缓存是两路组相联的(E= 2),块大小为4字节(B = 4),有4个组(S = 4)。

高速缓存的内容如下,所有的地址、标记和值都以十六进制表示:

存储器层次结构(二)_第4张图片

A)下面的图给出了一个地址的格式(每个小框表示一位)。指出用来确定下列信息的字段(在图中标号出来):

CO:高速缓存块偏移

CI:高速缓存组索引

CT:高速缓存标记


B)对于下面每个内存访问,当它们是按照列出来的顺序执行时,指出的是高速缓存命中还是不命中。如果可以从高速缓存中的信息推断出来,请也给出读出的值。

存储器层次结构(二)_第5张图片

答:A)B = 4,b = 2,S = 4,s = 2,m = 12,t = 12 - 2 - 2 = 8

所以CO为两位,CI为两位,CT为8位。

B)0x834 = 100000110100,CT = 10000011 = 83(16进制),CO = 0,CI = 1,

0x836 = 100000110110,CT = 10000011 = 83(16进制),CO = 2,CI = 1,

0xFFD = 111111111101,CT = 10000011 = FF(16进制),CO = 1,CI = 3,

存储器层次结构(二)_第6张图片


9、有关写的问题:

假设要写一个已经缓存了的字,在高速缓存中更新了它的副本之后,怎么更新w在层次结构中紧接着低一层的副本呢?

(1)直写(write-through):立即将w的高速缓存块写回紧接着的低一层中。

缺点:每次写都会引起总线流量。

(2)写回(write-back):尽可能地推迟更新,只有当替换算法要驱逐这个更新过的块时,才把它写到紧接着的低一层中。

缺点:增加复杂性,高速缓存必须为每个高速缓存行维护一个额外的修改位,表明这个高速缓存块是否被修改过。

(3)直写高速缓存比较容易实现,而且能够使用独立于高速缓存的写缓冲区,用来更新内存。

写回高速缓存引起的传送比较少,它允许更多的到内存的带宽用于执行DMA的I/O设备。

由于较长的传送时间,存储器层次结构中较低层的缓存更可能使用写回,而不是直写。

 

10、命中率与命中时间与不命中处罚:

(1)命中率(hit rate):命中的内存引用比率。

(2)命中时间(hit time):从高速缓存传送一个字到CPU所需的时间,包括组选择,行匹配和字抽取的时间。对于L1高速缓存来说,命中时间的数量级是几个时间周期。

(3)不命中处罚(miss penalty):由于不命中所需要的额外的时间。L1不命中需要从L2得到服务的处罚,通常是10个周期;从L3得到服务的处罚,50个周期;从主存得到服务的处罚,200个周期。


你可能感兴趣的:(系统结构)