本节书摘来自华章出版社《深入浅出dpdk》一书中的第2章,第2.3节cache地址映射和变换,作者朱河清,梁存铭,胡雪焜,曹水 等,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
2.3 cache地址映射和变换
cache的容量一般都很小,即使是最大的三级cache(l3)也只有20mb~30mb。而当今内存的容量都是以gb作为单位,在一些服务器平台上,则都是以tb(1tb=1024gb)作为单位。在这种情况下,如何把内存中的内容存放到cache中去呢?这就需要一个映射算法和一个分块机制。
分块机制就是说,cache和内存以块为单位进行数据交换,块的大小通常以在内存的一个存储周期中能够访问到的数据长度为限。当今主流块的大小都是64字节,因此一个cache line就是指64个字节大小的数据块。
而映射算法是指把内存地址空间映射到cache地址空间。具体来说,就是把存放在内存中的内容按照某种规则装入到cache中,并建立内存地址与cache地址之间的对应关系。当内容已经装入到cache之后,在实际运行过程中,当处理器需要访问这个数据块内容时,则需要把内存地址转换成cache地址,从而在cache中找到该数据块,最终返回给处理器。
根据cache和内存之间的映射关系的不同,cache可以分为三类:第一类是全关联型cache(full associative cache),第二类是直接关联型cache(direct mapped cache),第三类是组关联型cache(n-ways associative cache)。
2.3.1 全关联型cache
全关联型cache是指主存中的任何一块内存都可以映射到cache中的任意一块位置上。在cache中,需要建立一个目录表,目录表的每个表项都有三部分组成:内存地址、cache块号和一个有效位。当处理器需要访问某个内存地址时,首先通过该目录表查询是否该内容缓存在cache中,具体过程如图2-5所示。

首先,用内存的块地址a在cache的目录表中进行查询,如果找到等值的内存块地址,检查有效位是否有效,只有有效的情况下,才能通过cache块号在cache中找到缓存的内存,并且加上块内地址b,找到相应数据,这时则称为cache命中,处理器拿到数据返回;否则称为不命中,处理器则需要在内存中读取相应的数据。
可以看出,使用全关联型cache,块的冲突最小(没有冲突),cache的利用率也高,但是需要一个访问速度很快的相联存储器。随着cache容量的增加,其电路设计变得十分复杂,因此只有容量很小的cache才会设计成全关联型的(如一些英特尔处理器中的tlb cache)。
2.3.2 直接关联型cache
直接关联型cache是指主存中的一块内存只能映射到cache的一个特定的块中。假设一个cache中总共存在n个cache line,那么内存被分成n等分,其中每一等分对应一个cache line。举个简单的例子,假设cache的大小是2k,而一个cache line的大小是64b,那么就一共有2k/64b=32个cache line,那么对应我们的内存,第1块(地址0~63),第33块(地址6432~6433-1),以及第(n32+1)块(地址64(n-1)~64n-1)都被映射到cache第一块中;同理,第2块,第34块,以及第(n32+2)块都被映射到cache第二块中;可以依次类推其他内存块。
直接关联型cache的目录表只有两部分组成:区号和有效位。其查找过程如图2-6所示。首先,内存地址被分成三部分:区号a、块号b和块内地址c。根据区号a在目录表中找到完全相等的区号,并且在有效位有效的情况下,说明该数据在cache中,然后通过内存地址的块号b获得在cache中的块地址,加上块内地址c,最终找到数据。如果在目录表中找不到相等的区号,或者有效位无效的情况下,则说明该内容不在cache中,需要到内存中读取。
可以看出,直接关联是一种很“死”的映射方法,当映射到同一个cache块的多个内存块同时需要缓存在cache中时,只有一个内存块能够缓存,其他块需要被“淘汰”掉。因此,直接关联型命中率是最低的,但是其实现方式最为简单,匹配速度也最快。
2.3.3 组关联型cache
组关联型cache是目前cache中用的比较广泛的一种方式,是前两种cache的折中形式。在这种方式下,内存被分为很多组,一个组的大小为多个cache line的大小,一个组映射到对应的多个连续的cache line,也就是一个cache组,并且该组内的任意一块可以映射到对应cache组的任意一个。可以看出,在组外,其采用直接关联型cache的映射方式,而在组内,则采用全关联型cache的映射方式。
假设有一个4路组关联型cache,其大小为1m,一个cache line的大小为64b,那么总共有16k个cache line,但是在4路组关联的情况下,我们并不是简简单单拥有16k个cache line,而是拥有了4k个组,每个组有4个cache line。一个内存单元可以缓存到它所对应的组中的任意一个cache line中去。
图2-7以4路组关联型cache为例介绍其在cache中的查找过程。目录表由三部分组成,分别是“区号+块号”、cache块号和有效位。当收到一个内存地址时,该地址被分成四部分:区号a、组号b、块号c和块内地址d。首先,根据组号b按地址查找到一组目录表项,在4路组关联中,则有四个表项,每个表项都有可能存放该内存块;然后,根据区号a和块号c在该组表项中进行关联查找(即并行查找,为了提高效率),如果匹配且有效位有效,则表明该数据块缓存在cache中,得到cache块号,加上块内地址d,可以得到该内存地址在cache中映射的地址,得到数据;如果没有找到匹配项或者有效位无效,则表示该内存块不在cache中,需要处理器到内存中读取。
实际上,直接关联型cache和全关联型cache只是组关联型cache的特殊情况,当组内cache line数目为1时,即为直接关联型cache。而当组内cache line数目和cache大小相等时,即整个cache只有一个组,这成为全关联型cache。