2 Cache地址映射和变换
2.1 背景
Cache的容量很小,L3也只有几十兆,而内存容量有好几G,在这种情况下要把内存中的内容放到cache中,需要一个映射算法和分块机制。
2.2 分块机制
cache和内存以块为单位进行数据交换。块以在内存的一个存储周期中能访问到的数据长度为限。当今主流大小都是64字节,所以一个cache line就是64大小的数据块。
2.3 映射算法
映射算法要把内存中的内容按照某种规则装入cache中,并建立cache地址与内存地址的对应关系。如果内存在cache中了,处理器访问这个数据块内容时,就把内存地址转换成cache地址,然后在cache中找到这个数据块,返回给处理器。
根据内存和cache的映射关系不同,有三类:
| 定义 | 映射过程 | 特点 |
全关联型 | 主存中任何一块内存都可以映射到cache的任意一块位置上。 | 0. 书中图2-5 1. Cache中建立一个目录表,目录表的表现有三部分:内存地址,cache块号,有效位。 2. 内存分为两部分:块地址A和块内地址B,用内存块地址A查cache中目录表。 3. 目录表中找到后,还需要有效位是有效的。 4. 通过cache块号在cache中找到缓存的内存,加上块内地址B,找到相应数据并返回处理器。这时cache命中。 | 1. 没有块冲突。 2. Cache利用率很高 3. 需要访问一个很快的相联存储器才行。当cache容量增加,电路设计复杂度也增加。所以只有容量很小的cache才设计成全关联性。比如一些TLB cache。 |
直接关联型 | 主存中的一块内存只能映射到cache的一个特定的块中。一个cache中有N个cache line,就要把内存分成N块。比如2K cache有32个64字节cache line,那么内存的第1块(地址0——63),第33块,第N*32+1块,都只能映射到第一块cache中。 | 0. 书中图2-6 1. Cache中的目录表有两个表项:区号和有效位。 2. 内存地址分成三部分:区号A,块号B,块内地址C。 3. 根据区号A找cache中目录表,找到并且有效位有效说明数据在cache中,然后用块号B获得块地址,加上块内地址C,得到最终数据。 | 1. 很死的映射方法,如果多个内存块对应同一个cache块,只有一个内被缓存。因此命中率很低。 2. 实现方法简单,匹配速度最快。 |
组关联型 | 比较广泛的一种方式。内存被分为很多组,一个组的大小为多个cache line的大小,组内任意一块可以的任意一块内存可以对应cache组的任意一个。相当于组外采用直接关联,组内采用全关联。 1M大小的4路组关联cache,有16K个cache line(64字节一个),分成4K个组。 | 0. 图2-7 1. Cache目录表有三部分:区号+块号、cache块号,有效位。 2. 内存地址分成四部分:区号A、组号B、块号C、块内地址D。 3. 以4路为例,根据组号B查找目录表,查找一组目录表现。 4. 根据区号A和块号C,在cache目录表里找到对应表项,并确认有效位有效。 5. 得到cache块号,加上块内地址D,得到内存地址在cache中的映射。 | 组关联相当于只有一个组的全关联,也相当于全部组内只有一个成员的全关联。 |
3. Cache的写策略
下表关注前两个。WC和UC针对特殊设备。
| 策略 | 优点 | 缺点 |
直写 | 数据写入到cache的同时,也写入到内存中 | 简单、可靠,保证任何时刻内存的数据和cache中的数据都是同步的。 | 浪费时间,没有必要:不是所有情景下都需要每时每刻把数据写入内存,大量没必要的操作会占用内存带宽,影响运行速度。比如一个局部变量,生命周期短,且其他线程根本用不到。 |
回写 | 在cache line的标志位字段加了一个dirty标志位,当某个处理器修改了这个cache line后,就把dirty置1,当这个处理器再次修改这个cache line并要写入cache时,发现dirty为1,会先把cache line内容写回到内存中,再写入cache。 | 高效,规避了直写的浪费。 | 多核情况下会引起一致性的问题,需要MESI机制保障。 |
Write-combining | 针对某些具体设备,比如显卡RAM的优化策略,因为这些设备上数据从cache到内存的迁移开销比直接访问内存都高。这种策略下会在cache line里的数据都写完后1,才把cache line写回到内存。 |
|
|
Uncacheable内存 | 一部分不能被存入cache的特殊内存,比如PCI设备的IO空间通过MMIO方式被映射成内存来访问,因为设备希望修改这种内存后可以立即写入设备内部。 |
|
|
小结
这里介绍了cache的映射机制,对应示例图片在《深入浅出DPDK》一书中有。另外介绍了cache中的内容修改后,写回内存的时机,也就是回写。但是回写并没有解决多处理器场景下的cache一致性问题。需要一种机制来保证同一个内存的多个cache备份保持一致。