ARM的cache和写缓冲器(write buffer)
一、cache简介 通常CPU与外部主存之间的访问速度差距很大,因为外部主存的低速率读写而降低了CPU的执行效率,所以引入了高速缓冲存储器cache,cache存储器是一种容量小,速度快的存储器。其实cache说到底就是一块速度非常快的内存。 而cache经常与写缓冲器(write buffer)一起使用,使用writer buffer的目的是,将处理器和cache从较慢的对主存的写操作中脱离出来。
下图是一个计算机系统结构中的存储器分层结构,更好的显示了cache和写缓冲器在存储层次结构中所处的位置。 从图中可以看出,凡是从cache中向主存中写入数据时都需要经过写缓冲器。
下图显示了有cache的系统和没有cache的系统之间的差别:
cache和存储管理单元: cache可以在放在处理器内核与MMU之间,也可以放在MMU与物理存储器之间。
在处理器和MMU之间的cache称为逻辑cache,逻辑cache在虚拟地址空间存储数据,处理器可以直接通过cache访问数据,而无需通过MMU。逻辑cache又称为虚拟cache。
在MMU与物理存储器之间的cache称为物理cache,当处理器访问存储器时,MMU必须先把虚拟地址转换成物理地址,cache存储器才可以向处理器内核提供数据。
下图是两中cache:
二、cache结构
1、cache结构
图12.4是一个4KB大小的cache存储器,这个cache存储器分为256行,每行由三部分组成:目录存储段,状态信息段和数据项段。
目录存储段:用来记录每个cache行所对应的主存中的地址,即告诉cache这个行里存放的数据时从主存的什么地方拷贝进来的。这个目录项里的数据被称为“cache标签”状态信息段:用来记录状态信息的状态位,两个常见的状态信息位是有效位(valid bit)和脏位(dirty bit)。有效位用来标记当前的cache行是活动的,即当前的cache行已经存放了从主存中取得的数据,并且可以被处理器所使用。脏位用来标记该cache行中所含的内容是与主存中的内容是否一致,即该cache行中的数据已经被改变,但还没有被写回到主存中,主存中的数据还是旧的数据。数据项段:从主存中拷贝来的数据放在数据项段
这个cache存储器拥有4KB的大小,被分成256行,而每行所占的大小为4个字(16字节)大小,所以为4KB。注意cache标签和状态信息位所占的空间并不计算在内。以上就是一个cache存储器的结构,详细看下图12.4:
2、cache控制器的基本操作
cache控制器是用来控制cache的,它将主存中的数据或代码自动拷贝到cache存储器中,搬移工作自动完成。 当CPU访问主存时,在请求被发送到存储控制器之前,主存地址会被cache控制器拦截,然后cache控制器将要访问的地址分为三个部分:标签域,组索引域和数据索引域。 注:cache存储器中的一行是对应很多个主存地址的。如图12.5中一行对应了1MB的主存地址空间
组索引:用来确定某一个cache行。因为一共有256个行,而组索引宽度是8位,所以正好查找一个cache行。标签: 其实就是用来确定当前要访问的主存地址是否已经被缓存到了所找到的cache行中。如果该标签与cache行中存放的cache标签的值相等,且该cache行是活动的,则cache命中,否则失效。数据索引:确定要访问该cache行中的哪一个数据。
当组索引确定好某个cache行后,cache控制器便会检查该行的有效位,如果当前cache行是有效的,即处于活动状态,并且标签域的值与cache标签相等,则说明要访问的主存地址中的数据已经被缓存到了该cache行中,cache命中。 否则cache失效,这时,cache控制器从要访问的主存地址中拷贝整个cache行的数据大小到cache存储器中。这种拷贝操作称为cache行填充。 在cache命中的情况下,控制器直接从cache存储器中得到数据。使用数据索引在当前cache行中选择实际的要获得的数据或指令。
详细请看下图12.5:
cache的映射方式有三种:直接映射,组相联映射和全相联映射 直接映射 上图12.5便是一个直接映射的显示,在直接映射cache中,由于主存的容量要远远大于cache的容量,所以为了让大容量的主存能够全部映射到小容量的cache中,往往是主存中的多个地址对应cache中的一行。在上图12.5的例子中行,组索引的值为0x82,于是便找到了cache存储器中对应的一个cache行。 注意,因为这一个cache行对应了多个主存地址,在本例中一个cache行对应了1M的主存地址范围,而在任一时刻,该cache行只能对应着1M地址范围中的一个主存地址,所以要用标签再确定该cache行中具体的一个主存地址。用cache行中的cache标签与标签域中的标签比较,如果相等,则cache命中,然后便对该cache行进行读写操作。如果不相等,则cache失效,那么这个cache行的整个数据会被删除,并替换为CPU要访问的主存地址的内容,同时也将数据送到处理器中,这个过程称为替换。
组相联映射 直接映射虽然简单方便,但是如果程序同时用到了对应于同一个cache行中的两个主存地址,那么就会发生冲突,结果就是导致这个cache行不停的进行替换操作。所以就有了组相联映射。
组相联映射将这cache存储器中的256个行分为了4路,每路有64个cache行。这时根据组索引找到的 cache行不再是一个,而是同时找到 4个 cache行,所以才被称为组索引。每路中包含一个cache行。如下图12.7所示,便是一个组相联映射的cache。 因为现在每路中有 64 个 cache 行,所以组索引的宽度变成了6位,而标签域的标签宽度变成了12位。 直接映射中组索引一次只能对应一个cache 行,而现在组相联映射中组索引一次能对应4个cache行,所以现在主存中的一个地址可以存放到4个cache行中的任意一行。 而在直接映射中,主存中的一个地址只能存放到对应的一个cache行中。所以一个cache行被替换的概率减少为原来的四分之一。一个组相联映射的实例:
全相联映射 随着cache的相联度提高,冲突的可能性小了。理想的目标是,尽量提高组相联程度,使主存中的一个地址能够映射到cache存储器中的任意的cache行,这样的映射关系被称为全相联映射。
简单来说直接映射可以看成是一个只有1路的组相联映射,每路有256个cache行。 上面的组相联映射有4路,每路有64个cache行。 而全相联映射有很多路,每路中只有一个cache行。下图是一个64路的组相联映射:
三、写缓冲器
写缓冲器是一个非常小的告高速存储缓冲器,用来临时存放处理器将要写入到主存中的数据,在没有写缓冲器的系统中,处理器直接写数据到主存中。在带有写缓冲器的系统中,cache直接将数据先写到写缓冲器中,然后写缓冲器再以低速写入主存中。这就将高速的CPU和cache从对主存的低速读写中脱离了出来。 写缓冲器同时还改善了cache的性能,这体现在cache行被替换时。当cache控制器要替换出一个脏的cache行时,它只将该cache行中的数据放入写缓冲器中,而不写入主存。这样就可以快速填充新的cache行数据,处理器就可以继续从cache存储器中读/写数据。 写缓冲器中的数据在没有被写入主存之前,是不能被读取的。同样,被替换的cache行在写缓冲器中时也不能进行读操作。这也是为什么写缓冲器的深度通常比较小的原因之一,一般只有几个cache行的深度。
四、cache策略 有3种可以决定cache操作的策略:写策略,替换策略和分配策略,写策略决定了处理器执行写操作时数据存放的位置。替换策略在cache失效的情况下,决定选择替换出哪一路的cache行。分配策略决定cache控制器在何时将要分配cache行。
写策略 直写法: 如果cache使用直写策略,那么CPU在写cache命中时,将同时修改cache和主存中的内容,以确保cache和主存中数据一致性。在这种策略下,CPU在每次写cache时也要写相应主存单元。由于要访问主存,直写法的速度比回写法要慢一些。
回写法:
如果cache使用回写策略,那么CPU在写cache命中时,只向cache存储器中写数据,而不立即写入主存。这样,主存地址与相应的cache行数据有可能不一致。cache中的数据时最新的,而主存中的数据可能是较早的,还没有被更新过。
配置成回写法的cahche要使用到cache行的状态信息段中的一个或多个脏位(dirty bit)。当向cache存储器中某一行写入数据时,他会将脏位设置为1。如果此后访问该cache行,那么通过脏位就可以知道cache中含有主存中没有的数据。如果一个脏位被置位的cache行要被替换,那么该cache行中的数据会被自动的先写入到相应的主存单元中,以防止主存中的信息丢失。
替换策略 替换策略用于选择要替换cache行中的数据,应该替换哪个cache行。总的来说,组索引在各个way(路)中选择可用的一组cache行,而替换策略决定在该组中哪一路中的cache行会被新的数据替换。
轮转法: 简单地将当前分配的cache行的下一行作为被替换的行。
伪随机替换法:
从特定的位置上随机地选出一行替换出去。
大多数ARM核两种策略都支持,相比之下,轮转法有更好的可预测性。然而,轮转法在存储器访问发生很小的变化时,有可能照成cache性能有较大的变化。
分配策略 在cache失效发生时,ARM的cache可以采取两种策略来分配cache行:读操作分配策略,读写操作分配策略。
读操作分配策略:
在进行存储器写操作时,如果cache未命中,只是简单的将数据写入到主存中,而不写到cache中,如果cache命中,才会将数据写到cache中。但是在进行存储器读操作时,如果没有命中,则会替换cache行中的内容。
读写操作分配策略:
当进行存储器写操作时,如果cache未命中,cache控制器会将要访问的主存地址中的数据读到cache行中,并执行写操作,将数据写入到cache中。
五、清理和清除cacheARM使用清理和清除表示对cache的两种基本操作。
清理就是把脏的(即被改写过的)cache行强制写到主存,并把cache行中的脏位清零。清理cache可以重建cache和主存之间的一致性,它只是用在回写策略的D-cache上。 清除就是指清除cache中存储的全部数据,其实就是将cache使无效,将cache行中的有效位清零,让所有访问这个cache行的操作都不命中。
对cache进项清理和清除的操作是通过协处理器CP15中的寄存器C7实现的,具体操作指令看CP15协处理器寄存器详解。