组相联cache如何快速实现cache line eviction并使用PMU events验证

15 篇文章 3 订阅
7 篇文章 3 订阅

一,什么是cache hit、miss、linefill、evict ?

cache controler 是一个管理cache 内存的硬件结构,实际上它的绝大部分行为对程序来说都是不可见的。它会自动地将代码指令或者数据从主存中搬运到cache中,响应CPU读写内存的请求,并将它们转化成对cache以及外部内存的操作:
cache controler收到CPU对某个地址进行读写的请求时,它会先检查这个地址是否存在cache中,这个动作称为cache look-up(缓存查找)。具体的的操作为:将该地址的部分bit截取下来与cache 中cache line的tag(cache line的tag包含了该cache line的地址信息)值进行比较。如果匹配成功,也称为cache hit(命中),说明CPU读写的地址已存在cache中,并且这个cache line被标记为 valid(有效),则CPU的读写操作将会使用cache 里面的内容,而不会去主存中读写。
反之,如果遍历了整个cache都没有找到能与该地址匹配的tag,或者该tag是无效的,则缓存未命中(cache miss)。这个cache miss的结果以及对该地址的读写请求会被传递给下一级内存(可能是L2、L3 cache或者主存),并且会发生 cache linefill(缓存行填充)。cache linefill是指将下一级内存中关于该被请求地址的数据拷贝到cache中,由于cache 操作的最小单位是cache line,所以一次填充一个cache line。在cache linefill的同时,被请求的数据也会发送给CPU,满足其读写请求。这个cache miss 和linefill的行为对程序员来说是不可见的,并且CPU并不用等linefill完成,才能使用该数据。假设cache line大小为64 bytes,所以一个linefill操作需要将64 bytes数据拷贝到cache当中,而CPU的读写请求可能是该cache line中的其中一个word(4 bytes),cache controler会优先访问该特定的 word,将该word送到CPU的流水线(pipeline)中,与此同时,cache硬件以及外部总线接口会将剩余的60 bytes数据读取,并填充到指定cache line中。
cache 始终是有空间限制的,如果一直miss,一直linefill,那么将cache填满了后会发生什么?eviction。为了让新的cache line数据填进cache中,cache 利用替换策略(replacement policy),在cache中选中一个cache line,并将其驱逐(evict)出去,为新的cache line数据腾出空间。被驱逐的cache line也称为victim,而被驱逐的过程,也就是写回(write back)到下一级内存(可能是L2、L3 cache或者主存)的过程。
问题随之而来:

1.1 如果要程序员分别制造出cache hit、miss、linefill、evict这四种场景,该怎么做?

首先要知道cache miss之后必然会出现cache linefill,如果cache 满了,cache linefill还会造成cache eviction。所以:

  • cache miss +linefill : 读写一个之前未曾使用过的地址,或者当cache为空的时候进行读写,即可造成miss+linefill。
  • cache hit :重复读写一个内存地址,第一遍读写会miss+linefill,但是第二遍开始就会一直hit。
  • cache evict:前面提到过,当cache 满了的时候,会将某个cache line驱逐出去,给新的cache line腾出空间。所以最简单的办法就是连续读写一段与cache容量大小的内存空间,将cache 填满。然后再读写一个新的地址时,将会发生eviction。除了这种方法,下文还会介绍针对组相联结构的cache快速制造eviction的简单方法。

二,实现cache line eviction的方法

1.1 直接填充法

在上文中我们知道,要想发生 cache line的eviction,最简单粗暴的方式就是将整个cache 填满,然后再读写一个新地址的时候,cache controler就会用replacement policy(替换策略)选择其中一个cache line,将其驱逐(也就是write back)到下一级内存中。但是将一个cahce 填满也是非常耗时的,我们可以简单计算一下:
假设当前cache 的大小为32KB,其cache line size为64 bytes,LDR/STR指令一次读写32 bit( 4 bytes)的数据。我们知道,一次读写(miss)会填充一个cache line(64 bytes),即使是每次跨一个cache line大小的空间进行读写,实际的读写次数也需要512次,如下面代码:

addr = 0x10000000
for(i=0;i<512;i++)
{
	val=*(addr);
	addr = addr+64;
}
val=*(addr+64);//eviction

3.2 针对组相联cache的固定set number 填充法

ARM一般使用组相联结构的cache,针对组相联cache,不必将整个cache填满才会发生eviction,我们可以利用cache的set 和way快速地制造eviction,具体的原理如下参考下文。
假设有一个 4 way+ 256 set的cache,cache line大小为64 bytes,很容易得出该cache的大小为64 Bytes * 256 * 4 = 64 KB,其结构如下:
在这里插入图片描述
在这里插入图片描述
可以发现,传入cache的一个内存地址会被cache 分成三部分:Tag+Index+offset。这三部分决定了该地址上的数据将会被加载到cache中的哪个cache line。

  • Tag:一个地址的高位bits可以用来当作Tag,可以告诉cache该cache line的数据来自主存的哪里。
  • Index: 地址的中间部分可以用来表示 Set的下标,也就是set的行号,不同way中index相同的cache line的集合称为set。
  • Offset:word index + byte index,一个cache line有64 bytes,而一个地址上的数据可能只有4 bytes,我们可以用该offset找到该数据位于cache line的哪个word或者byte。

当CPU 读写一个地址后,假设该地址为0xB0001234,包含该地址数据的一个cache line大小的数据将会被填充到cache中。
我们先来分析该cache line将会被放在cache 的哪个位置。
0xB0001234会被分成三部分:
在这里插入图片描述
蓝色部分为Tag信息,红色部分为Set的index,绿色部分为offset:

  • Tag = 0b1011 0000 0000 0000 00
  • Set index = 0b 100100 = 0x24 = 36
  • offset: word index = 0b 1101 = 13, byte index = 0

解析出了这些信息,我们就可以给这个cache line找个家了:

  • 位于哪个way:由于是4 way组相联的cache,所以该cache line可以位于 way0、way1、way2、way3中的任意一个way。
  • 位于哪个Set:set index为36,所以该cache line位于某个way的第36行。
  • 位于cache line的第13个word的第 0 byte
    在这里插入图片描述
    需要注意的是,该地址不是64 bytes对齐的地址,所以加载到cache line的64 bytes数据应该是从 0xB0001200开始到 0xB0001240的 64 bytes数据。
    在这里插入图片描述

我们虽然不知道该cache line位于哪个way,但是way 的个数只有四个,如果连续写入四个 set index都为36的cache line,那么写入第五个的时候会发生什么?eviction

  1. 写入第一个set index为36 的cache line,cache line 可以保存在way0,way1,way2,way3,任意一个way,姑且假设放入way2。
  2. 写入第二个set index为36 的cache line,cache line 可以保存在way0,way1,way3,任意一个way,姑且假设放入way3。
  3. 以此类推,当写入第四个set index为36 的cache line后,way0,way1,way2,way3都保存了一个set index为36且来自不同地址的cache line。
  4. 如果再写入第五个set index为36 的cache line,cache controler将会根据替换策略,在现有的四个set index为36的cache line中选择一个,将其驱逐出去,为第五个set index为36 的cache line腾出空间,也就发生了cache eviction。
    在这里插入图片描述

所以接下来我们只要找到四个set index为36,但是Tag不同的地址即可,只要保证地址的[13:6]=0b0100 100,即可保证其set index为36 ,比如:

  • 0xA0001200
  • 0xC0001200
  • 0xD0001200
  • 0xE0001200
    在这里插入图片描述
    所以CPU只需先读写这四个地址,然后再读写0xB0001234的时候,将会发生cache eviction,总共只需读写五次即可实现。

三,使用PMU events验证 cache line eviction

光是这样推测是远远不够的,我们可以利用PMU(Performance Monitors Unit)的事件监控功能,把cache 相关的事件用PMU来监控,验证是否真的发生了预期的cache 操作。具体的event 可以是:
在这里插入图片描述
在这里插入图片描述
一个eviciton 操作实际上是将旧的cache line写回到下一级缓存,然后把新的cache line 加载进来,所以可以利用PMU以下的event来监控:

  • L1D_CACHE_WB
  • L2D_CACHE_REFILL
  • L2D_CACHE
  • L1D_CACHE
  • L1D_CACHE_REFILL

四,思考:全相联和直接映射型cache 如何实现 cache eviction ?

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SOC罗三炮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值