1.为什么要有缓存?
随着现代半导体工艺的发展,CPU的频率越来越快,相对内存快了一个数量级,对于访存的操作CPU就需要等待主存,这样会导致资源的白白浪费。所以cache的出现为了解决CPU与内存速度不匹配的问题。(cpu ->cache->memory)
cache的思想在我们日常的生活随处可见,我们周围的超市就是很好的例子。工厂把我们日常用品部分在超市,减少了我们去工厂购买的时间开销,方便了我们的生活。
2.CPU缓存有什么意义?
时间局部性:如果某个数据被访问,它在将来的某个时间也有可能在被访问。
空间局部性:如果某个数据被访问,那么它相邻的数据也有可能被访问。
3.CPU读取数据的过程
cache中保存着cpu刚用过的数据或者是循环使用的数据,这时,从cache中读取数据就会很快,减少了cpu等待的时间,提高了系统的性能
4.cache 缓存带来的问题
导致数据不一致的问题,对于多核系统来说。
5.如何解决缓存带来的问题,比较常见的缓存一致性(MESI),当然也有锁住总线。
我们来介绍一下缓存一致性:
在MESI协议中,每个cache line有4个状态,可用2个bit表示,它们分别是:
状态 | 描述 |
---|---|
M(Modified) | 这行数据有效,数据被修改了,和内存中的数据不一致,数据只存在于本Cache中。 |
E(Exclusive) | 这行数据有效,数据和内存中的数据一致,数据只存在于本Cache中。 |
S(Shared) | 这行数据有效,数据和内存中的数据一致,数据存在于很多Cache中。 |
I(Invalid) | 这行数据无效 |
MESI为了保证多个CPU缓存中共享数据的一致性,定义了cache line的四种状态,而CPU对cache line的四种操作可能会产生不一致的状态,因此缓存控制器监听到本地操作和远程操作的时候,需要对地址一致的cache line 状态进行一致性修改,从而保证数据在多个缓存之间保持一致性(M:modified E:Exclusive S:shared I:invalid) 。
3个Core都访问变量x,它们对应的Cache line为S(Shared)状态
下面是MESI四种状态的转换:
通过local read(内核读取本地缓存中的值),local write(本地内核写本地缓存中的值),remote read(其它内核读取其他缓存中的值),remote write(其它内核更改其他缓存中的值)。通过这四种操作来改变cache line 的状态。
在一个典型系统中,可能会有几个缓存(在多核系统中,每个核心多会有自己的缓存),共享主存总线,每个相应的CPU都会发出相应的读写请求,而缓存的目的减少CPU的读写共享主存的次数。
缓存行除了在Invalid状态都可以满足CPU读的状态,一个Invalid的缓存行必须从主存中读取来满足CPU的读请求。 一个写请求只有在该缓存行是M或者E状态时才能被执行,如果缓存行处于S状态,必须先将其它缓存中该缓存行变成Invalid状态(也既是不允许不同CPU同时修改同一缓存行,即使修改该缓存行中不同位置的数据也不允许)。该操作经常作用广播的方式来完成,例如:Request For Ownership (RFO)
缓存可以随时将一个非M状态的缓存行作废,或者变成Invalid状态,而一个M状态的缓存行必须先被写回主存。
一个处于M状态的缓存行必须时刻监听所有试图读该缓存行相对就主存的操作,这种操作必须在缓存将该缓存行写回主存并将状态变成S状态之前被延迟执行。
一个处于S状态的缓存行也必须监听其它缓存使该缓存行无效或者独享该缓存行的请求,并将该缓存行变成无效(Invalid)。
一个处于E状态的缓存行也必须监听其它缓存读主存中该缓存行的操作,一旦有这种操作,该缓存行需要变成S状态。
对于M和E状态而言总是精确的,他们在和该缓存行的真正状态是一致的。而S状态可能是非一致的,如果一个缓存将处于S状态的缓存行作废了,而另一个缓存实际上可能已经独享了该缓存行,但是该缓存却不会将该缓存行升迁为E状态,这是因为其它缓存不会广播他们作废掉该缓存行的通知,同样由于缓存并没有保存该缓存行的copy的数量,因此(即使有这种通知)也没有办法确定自己是否已经独享了该缓存行。
从上面的意义看来E状态是一种投机性的优化:如果一个CPU想修改一个处于S状态的缓存行,总线事务需要将所有该缓存行的copy变成invalid状态,而修改E状态的缓存不需要使用总线事务
对于MESI状态的转换用表哥形式记录下来: