ARMv8 cache 模型
L1 cache是每个核心独有,L2 cache是每个簇共享, L3 cache是所有簇共享
cache 术语
-
tag是内存地址的一部分,保存在cache中,用来唯一标识主内存和cache line 之间的联系。
一个cache line最高位的几位,是用来告诉cache这个信息是保存在内存什么地方,也被称作tag。总的cache大小是它能保存的所有数据的大小,尽管保存tag的RAMs并不在这个计算当中。但是tag确实是占用了cache的物理空间的。 -
每个tag地址只保留一个字长的数据是很低效的,因此是好几个字长的数据存放在一个tag地址后面,这个数据叫做cache line。cache line是cache最小的被load的单元,也是内存中一串相邻的字。如果cache line中存放了cache data或者指令,那它就是有效的,否则就是无效cache。
和cache line数据在一起的是一或多位的状态位。典型地,有一个有效位用来标记这个cache line存放的数据是否是可用的。这意味着tag表示了一些真正的信息。在D-cahe中,还有一或多个dirty位来表示这个cache line中的数据是否和主内存中的一致。
-
index 是内存地址的一部分,决定在cache的哪些行中,这个地址可以被找到
-
way 是对cache的一个划分,每个way都是一样的大小而且用同样的方式索引。
-
set 所有way中index一样的cache line组成。
-
这意味着,地址的最低位,叫做offset的,不需要保存在tag中。你需要的是整行的地址,而不是每个字节的地址,因此第五或第六最低有效位通常都是0.
cache 理解
- way,是对caches的一种划分,比如将L1 cache划分成2~4个Way
- set,是对Way的一种划分,属于同一index的cache lines划分到一个Set
- Tag,在set内部,根据内存地址的部分高位bits和cache line的tag做比较,选择匹配的cache line,如果没有就往上级存储查询
- word,offset,说明地址保存的数据是在cache line中的第几个word
全包括cache和独有cache
一句话解释,最大的区别是,如果要从上层存储load数据,那么该数据所属的cache line大小的数据会被拷贝到所有的下层cache中。
一个具体的例子,LDR X0, [X1]
,从X1寄存器的值指向的地址拷贝一个64bit数据到X0寄存器:
-
如果X1指向内存中的这个地址被标记为可缓冲的,那么会有一次L1 cache查询
-
如果在L1 cache中找到,就会把这个值load进X0寄存器内
-
如果L1 cache没有找到,但是在L2cache中找到,cache line会从L2 cache拷贝到L1,L1中某个cache line可能会被清除来为这个line让位置,同时,数据返回到X0中,且这个cache line会在L2 cache中保留
-
如果L1 和 L2 中都没有,数据会从内存中拷贝到L1 和 L2 cache,并返回X0。这个操作可能会导致L1 和 L2中的cache line被清除
上面是全包括cache的一种最简单情况,如果还有L3 cache等存储结构的话,会依次从下往上查询,以及从上往下load。
对于独有cache 来说,数据只会保留在一个cache中,即如果L1找到,就返回,如果L1没找到L2找到,那么会从L2中读取数据,并不会同时拷贝到L1 cache中。
cache 策略
写回
在写回的时候,先只是修改了cache line中的值,并标记为dirty,这个过程很好理解,关键是什么时候写回内存呢?两种情况:1)该cache line被迫被清除,清除前会将数据写回内存;2)显示的清除该cache line。这说明数据会尽可能的呆在cache中,知道不再被使用或者人为地清除cache line。
写入
这种写入方式,会同事更新cache和外部内存,且不会把cache line标记为dirty
inner & outer 属性
通用内存的可缓冲属性,分成inner和outer两种。一般来说,inner内存会使用处理器集成的cache,outer属性的会使用外部的cache。
正常内存会被随机性的由处理器访问,把数据读到cache中,而不需要显式地由指令发起这个过程。然而,这个随机性可以由程序员来指定,这就是预取指令: