- 论坛徽章:
- 0
|
本帖最后由 blake326 于 2014-06-29 22:25 编辑
好吧没人回,我自己理解下,关键的一点:
“ 状态为S时,数据将直接写入到Cache中,并将状态改为M,同时其他CPU保存该数据副本的Cache行状态将从S或者O迁移到I(Probe Write Hit)。”这个是否原子?
这个操作看起来有很多小步组成的,写数据到cache,修改m,同时发送inval request到其他cpu,可能还要处理其他cpu回来的inval replay。所以,当然不是原子的了,要不然肯 定很影响性能的。
但是,更关键的一点,mesi会保证整个一套动作是安全的,之前的例子,cpu0,cpu1同时写s的cache line,那么对于这同一个cache line,mesi应该会有一个同步机制(类似 mutex)之类的保证同时只有一个cpu操作了addr响应的cache line.比如,cpu0,cpu1同时开始写,首先,mesi会仲裁选择一个cpu进行对cache line进行操作,另外一个cpu只能等 待,待的就是之前说的一些列操作:状态为S时,数据将直接写入到Cache中,并将状态改为M,同时其他CPU保存该数据副本的Cache行状态将从S或者O迁移到I)。因此,我这个帖子 的结果就是,最终cache line的值是0, 1, 2, 3, 4, 5, 6, 7. arm-linux-gcc同志是正确的。
重新整理一下cache一致性的状态切换:
假设有cpu0, cpu1。一个虚拟地址addr。
则cpu0, cpu1都有一个addr对应的cache line, 状态有四种:有效E, 修改M,共享S, 无效I。I实际上就是说该addr在cache中没有缓存的意思。根据这四种状态,组合分析一下 。
cpu0,cpu1的cache状态一样:
都是I状态:
cpu0读的话,首先会像mesi申请cache line使用权,然后开始分配一个cache line并且从ddr把addr的值读取过来,状态变成E。
cpu0写的话,首先会像mesi申请cache line使用权,然后开始分配一个cache line并且从写addr,状态变成E。
都是S状态:
cpu0读的话,首先会像mesi申请cache line使用权,如果其他cpu已经获取了cache line的使用权的话,则这里要等待。获得cache line使用权之后,直接把cache line的值读出来 就好了。
cpu0写的话,首先会像mesi申请cache line使用权,cpu0写addr,修改本地cache,状态变成M,且发送一个inv消息给cpu1通知cpu1失效响应的cache line,当然cpu1应该会发送一 个inval replay回来。
都是E,M的状态是不存在的。因为,E/M状态的核心一点就是表示cache line只在本地cpu中存在,不存在竞争关系。
cpu0,cpu1的cache状态不一样:
cpu0 I, cpu1 E:
cpu0 读addr,首先会像mesi申请cache line使用权,发现cpu1有对应的E cache,新建一个本地的cache line将cpu1的cache line拷贝过来,并且设置大家的状态为S。
cpu0 写addr,首先会像mesi申请cache line使用权,发现cpu1有对应的E cache,发送一个inv消息告诉cpu1,并且等待其inval replay返回,然后本地新建一个cache line将ddr 读进来,之后修改本地cache line,并且设置状态M。
cpu1 读addr,因为E状态,无需向mes申请cache line使用权,直接读cache。
cpu1 写addr,因为E状态,无需向mes申请cache line使用权,直接写cache,设置状态为M。
cpu0 I, cpu1 M:
cpu0 读addr,首先会像mesi申请cache line使用权,发现cpu1有对应的M cache,发送一个flush消息告诉cpu1并且等待cpu1刷新cache到ddr,然后新建一个本地cache line将ddr 从内存读进来,并且设置状态为E。
cpu0 写addr,首先会像mesi申请cache line使用权,发现cpu1有对应的M cache,发送一个flush消息告诉cpu1并且等待cpu1刷新cache到ddr,然后新建一个本地cache line将ddr 从内存读进来并且写,并且设置状态为M。
cpu1 读addr,因为M状态,无需向mes申请cache line使用权,直接读。
cpu1 写addr,因为M状态,无需向mes申请cache line使用权,直接写。
cpu乱序模型:
http://bbs.chinaunix.net/thread-3593865-1-1.html
cpu乱序,cache一致性,和内存屏障。
内存屏障mb() 是和cpu乱序,chache一致性相关的。下面的老例子:
cpu0
a = 1;
wmb();
b = 2;
cpu1
读 b;
rmb();
读 a;
cpu乱序模型会让a=1,a=2执行顺序颠倒。 读b,读a顺序颠倒。
wmb() 会使 a=1先执行,然后再执行 b=1, 说的再细一点同cache一致性就有关系了,因为a=1,之前说了是一个很多小步骤组成的过程,获取cache使用权,写cache,发送inval a ,修改m状态。wmb实际上就是保证,在wmb之前所有的inval request已经发了出去。就是说保证先发inval a, 然后再发inval b.
rmb() 会先执行读b,然后再执行读a,仔细一点,实际上就是说在rmb之前所有的inval request完成了。那么,我们刚才已经知道了cpu1先收到的inval a然后是inval b,假设在 rmb()时,inval b已经执行了,那么这个时候会处理掉所有的inval request,确保inval a也应执行了。就是说cpu1假设读到了b=2,那么rmb()之后,a肯定是1.
cache alias:
http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=1972593
cache一般有几种类型:
pipt
vivt
vipt noalias
vipt alias
实际上armv7 的dcache是vipt noalias的。icache是vipt alias的。
为什么会有cache alias问题呢,为什么amv7 dcache又没有呢。
一个cache由 cache line size * num set * way 组成。
一般是 32 * 256 * 4 = 32KB.
如果line size * num set = 8KB大于page size的话那么就有可能有alias问题。
假设0xf000 0000和0xf000 1000两段地址都是映射同一个page的话,那么访问0xf000 0000和0xf000 1000时,他们在cache中的num是不同的,就是有各自的cache line,但是映射的物理地址是一样的。如果硬件不能自动处理的话,软件一定要处理好。
现在假设dcache是vipt alias的话,文件系统写一个page cache时,会调用flush_dcache_page()来解决这个alias问题。
最终会调用到flush_pfn_alias(),好久不看相关的东西,看不懂这个鸟玩意了,请高手帮忙分析下。
|
|