内存的数据被加载到了cache后,在某个时刻其要被写回内存,对于这个时刻的选取,有如下几个不同的策略。
write-through:所谓write-through,就是指在CPU改写一个cache line后,cache line也被CPU写回内存。这种策略保证了在任何时刻,内存的数据和cache中的数据都是同步的,因此write-through最容易实现cache的一致性。显然,由于CPU要频繁地将cache里的被修改的数据写回内存,这种方法最大的缺点就是速度慢,效率低。假设一段程序在频繁地修改一个局部变量,那么尽管这个局部变量的生命周期很短,而且其他程序也用不到它,CPU依然会频繁地在cache和内存之间交换数据,这样会大大增加FSB总线(见《从硬件的体系结构开始》)上的数据流量。
write-back:write-back相对于write-through而言是一种更精炼的方法,采用write-back策略,CPU在改写了cache line后,并不是马上把其写回内存,而是将该cache line标志为dirty。只有当cache中发生一次cache miss,其他的数据要占用该cache line时,CPU才会把其写回内存。在实现write-back策略时,有一个重要的问题是需要被考虑到的,当多个处理器访问同一内存时,必须保证所有处理器所看到的内存内容是相同的,也就是一致性的问题。当一个cache line被一个处理器设置为dirty后,另一个处理器要访问同一内存,那么显然,该处理器真正需要的数据是前者的cache里的数据,而不是内存中还未更新的数据,后面会讲解这个问题是如何解决的。
在此之前我们再来看两种写策略,分别是write-combining和uncacheable. 这两种策略都是针对特殊的地址空间来使用的。
write-combining是针对于具体设备内存(如显卡的RAM)的一种优化处理策略。对于这些设备来说,数据从cache到内存转移的开销比直接访问相应的RAM的开销还要高得多,所以应该尽量避免过多的数据转移。试想,如果一个cache line里的字被改写了,CPU将其写回内存,紧接着又一个字被改写了,CPU又将该cache line写回内存,这样就显得低效,符合这种情况的一个例子就是显示屏上水平相连的像素点数据。write-combining策略的引入就是为了解决这种问题,顾名思义,这种策略就是当一个cache line里的数据一个字一个字地都被改写完了之后,才将该cache line写回到内存中。
uncacheable内存是一部分特殊的内存,该内存里的数据时硬编码的,可以不需要CPU的控制就能实现一些功能,比如用来访问一些链接在外部总线(如PCIe,etc)的设备而被映射的地址空间。PCI card中的内存可以不依赖CPU的控制就能发生改变,所以它是不需要被缓存的。
在一个典型的系统中,几个cache通过共享总线来连接到内存,而这些cache又分别附属给几个不同的CPU。这些cache的共同目标就是尽可能减少对主存的使用。为了解决cache的一致性问题,cache的设计者们引入了很多不同的协议,其中MESI协议被广泛用于支持write-back cache. 还记得在前面说过,数据cache中用两位来表示一个cache line的状态,MESI协议中利用这两位组成4种状态,分别是Modified,Exclusive,Shared和Invalid,下面说明这四种状态的含义
Modified:本地处理器修改了cache line中的数据,并且数据只存在于这一个cache中,在其他cache中没有备份。
Exclusive:cache line中的数据没有被修改,并且数据只存在于这一个cache中,在其他cache中没有备份。
Shared:cache line中的数据没有本修改,该数据有可能在其他cache中有备份。
Invalid:cache line中的数据是无效的。
下面给出各个状态之间的转换图:
每两个状态之间的转换说明,网上有一位朋友描述得很详细,我将他总结的贴在下面
当前状态 |
事件 |
行为 |
下一个状态 |
I(Invalid) |
Local Read |
如果其它Cache没有这份数据,本Cache从内存中取数据,Cache line状态变成E; 如果其它Cache有这份数据,且状态为M,则将数据更新到内存,本Cache再从内存中取数据,2个Cache 的Cache line状态都变成S; 如果其它Cache有这份数据,且状态为S或者E,本Cache从内存中取数据,这些Cache 的Cache line状态都变成S |
E/S |
Local Write |
从内存中取数据,在Cache中修改,状态变成M; 如果其它Cache有这份数据,且状态为M,则要先将数据更新到内存; 如果其它Cache有这份数据,则其它Cache的Cache line状态变成I |
M |
|
Remote Read |
既然是Invalid,别的核的操作与它无关 |
I |
|
Remote Write |
既然是Invalid,别的核的操作与它无关 |
I |
|
E(Exclusive) |
Local Read |
从Cache中取数据,状态不变 |
E |
Local Write |
修改Cache中的数据,状态变成M |
M |
|
Remote Read |
数据和其它核共用,状态变成了S |
S |
|
Remote Write |
数据被修改,本Cache line不能再使用,状态变成I |
I |
|
S(Shared) |
Local Read |
从Cache中取数据,状态不变 |
S |
Local Write |
修改Cache中的数据,状态变成M, 其它核共享的Cache line状态变成I |
M |
|
Remote Read |
状态不变 |
S |
|
Remote Write |
数据被修改,本Cache line不能再使用,状态变成I |
I |
|
M(Modified) |
Local Read |
从Cache中取数据,状态不变 |
M |
Local Write |
修改Cache中的数据,状态不变 |
M |
|
Remote Read |
这行数据被写到内存中,使其它核能使用到最新的数据,状态变成S |
S |
|
Remote Write |
这行数据被写到内存中,使其它核能使用到最新的数据,由于其它核会修改这行数据,状态变成I |
I |
(注:该表引自http://blog.csdn.net/muxiqingyang/article/details/6615199)
限于个人水平,描述不当或错误之处还请指出,转载请注明出处,谢谢!