一文讲透高速缓存原理
早期计算机系统的存储器层次只有三层: CPU寄存器、DRAM主存储器和磁盘存储器。
随着CPU和主存储器之间的性能差距越来越大,系统设计者在CPU和主存储器之间逐渐添加了L1、L2、L3高速缓存。下面我们来看看Cache的结构以及如何工作:
1.Cache基本结构
一个cahce的组织可以由下面的包含4个参数的参数组来标识(S,E,B,m),S是缓存组的数目(index),E是每个组的高速缓存行的数目(way),B是一个cache line中保存的数据块的字节数,m是物理地址的bit数据。
- 行(line):高速缓存行是cache中最小的访问单元,包含一小段主存储器中的数据,常见的高速缓存行大小是32Byte或64Byte等。每行不仅有数据区域,处理器需要通过行内偏移量来访问每行中的数据,所以还需要偏移量(Offset)来定位行内位置,需要标记域(Tag)来知道本行缓存的是哪个内存地址,还需要其他的一些位来知道此行是否有效(即已经缓存了数据)。
- 地址编码:就是处理器访问高速缓存行的地址编码。分3个部分,分别是偏移量(Offset)、索引域(Index)、标记域(Tag)。
- 偏移量(Offset):行内的偏移量,处理器可以按照字或者字节来寻址,比如一行32byte,偏移量就有5bit,可以定位到字节。
- 标记域(Tag):行内的标记域,用于判断高速缓存行存放的数据是否和处理器想要的一致。也就是这一行对于的内存地址是多少,比如32位的内存地址,标记域为32-5=27。
- 索引域(Index):用于索引某一高速缓存中的某一组。例如上图中可以索引4组缓存,Index就有2bit。
- 组(Set):相同索引域(Index)的高速缓存行组成一个组,也就是使用Index来定位组号。
- 路(Way):在组相联的cache中,cache被分成大小相同的几个块,每一块就是一路,每一组。
高速缓存的结构很像一个三维结构,可以用zyx坐标轴定位来表示高速缓存中的字节,x轴对于行内偏移量,y轴对于某一路中的索引,z轴对应路号。
举例:
问题:一个32KB的4路组相联缓存,其中高速缓存行为32字节,请问这个高速缓存有多少行,多少路,多少组,参数组是多少?
答:高速缓存行数 32*1024 / 32 = 1024行 高速缓存路数为 4路 高速缓存组数为 1024 / 4 = 256 组
由于是组相联缓存,所以访问地址编码中的偏移量是 5bit(2^5 = 32字节),索引域为8bit(2^8 =
256组),标记域为19(32-5-8),物理地址可以访问的就是13bit(5+8)。
所以这个缓存的参数组为 (S,E,B,m) = (256,4,32,13)
2.Cache的工作方式
处理器访问主存储器使用地址编码方式。cache也使用类似的地址编码方式,因此处理器使用这些编码地址可以访问各级cache。
以VIPT(virtual Index phg sical Tag)的cache组织方式 举例:
处理器在访问存储器时,会把地址同时传递给TLB(Translation Lookaside Buffer)和cache。TLB是一个用于存储虚拟地址到物理地址转换的小缓存,处理器先使用EPN (effective page number)在TLB中进行查找最终的RPN(Real Page Number)。如果这期间发生TLB miss,将会带来一系列严重的系统惩罚,处理器需要查询页表。假设这里TLB Hit,此时很快获得合适的页帧号RPN,并得到相应的物理地址(Physical Address, PA)。
同时,处理器通过cache编码地址的索引域(Index)可以很快找到相应的组(Set)。但是这里的cache block的数据不一定是处理器所需要的,因此有必要进行一些检查,将cache line中存放的地址和通过虚实地址转换得到的物理地址进行比较。如果相同并且状态位匹配,那么就会发生cache命中(Cache Hit),那么处理器经过字节选择和偏移(Byte Select and Align)部件,最终就可以获取所需要的数据。如果发生cache miss,处理器需要用物理地址进一步访问主存储器来获得最终数据,数据也会填充到相应的cache line中。
高速缓存目前是由硬件自动管理的,也就是当处理器访问存储器的时候, 会自动去高速缓存中尝试获取,如果高速缓存中不存在此数据,就会读取内存,并把此内容之后的一个高速缓存行大小的数据存入高速缓存。刚开机时,由于高速缓存为空,此时高速缓存会出现大量的miss,直到高速缓存满了,当高速缓存满了以后,如果出现miss,就会采用替换策略,将已存入的某行替换掉。
3.Cache的映射方式
第一节的例子中提到了组相联缓存,组相联就是Cache的映射方式。我们采用第一节讲到的参数组的方式来几种方式:
参数组(S,E,B,m),S是缓存组的数目(index),E是每组的高速缓存行的数目(way),B是一个cache
line中保存的数据块的字节数,m是物理地址的bit数据。
根据参数组中的E(每组的高速缓存行的数目),cache可以分成不同的类。
- 当每组只有一行cache line时,称为直接映射高速缓存;
- 当整个高速缓存只有一组高速缓存时,即E=C/B,则为全相联高速缓存,C为此高速缓存的总大小;
- 当每组的高速缓存行数E在这个范围内 1<E<C/B ,则为组相联高速缓存;
下面详细讲解这几种方式构造的缘由:
3.1 直接映射方式
当每个组只有一行cache line时,称为直接映射高速缓存。
举例:下面用一个简单小巧的cache来说明,这个cache只有4行cache line,每行有4个字(16byte),总大小是64byte。这个cache控制器可以使用两个比特位(bits[3:2])来选择高速缓存行中的字,以及使用另外两个比特位(bits[5:4])作为索引(Index),选择4个cache line中的一个,其余的比特位用于存储标记值(Tag)。
-
cache命中
当索引域和标记域的值和查询的地址相等,并且有效位显示这个cache line包含有效数据时,则发生cache命中,那么可以使用偏移域来寻址cache line中的数据。 -
cache替换
如果cache line包含有效数据,但是标记域是其他地址的值,