免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 10033 | 回复: 5

[内核入门] 从cache一致性到理解内存屏障 [复制链接]

论坛徽章:
0
发表于 2013-03-07 00:11 |显示全部楼层
本帖最后由 blake326 于 2013-03-07 00:12 编辑

http://bbs.chinaunix.net/forum.p ... =4070325&extra=
http://bbs.chinaunix.net/forum.p ... ;page=6#pid23786513
参考上面两个帖子。纯属个人总结理解,具体实现应该更复杂或者以此为基础。

先说cache 一致性的理解。
假设有cpu0, cpu1。一个虚拟地址addr。
则cpu0, cpu1都有一个addr对应的cache line, 状态有四种:有效E, 修改M,共享S, 无效I。I实际上就是说该addr在cache中没有缓存的意思。根据这四种状态,组合分析一下。

cpu0,cpu1的cache状态一样:
都是I状态:
这种最简单,cpu0读addr的话,则分配一个cache line并且从ddr把addr的值读取过来,状态变成E。cpu0写的话,状态会变成M。
都是S状态:
也很简单,读的话直接从cache读出来。写的话复杂一点,cpu0写addr,修改本地cache,状态变成M。并且发送一个inv消息给cpu1通知cpu1失效响应的cache line。
都是E,M的状态是不存在的。

cpu0,cpu1的cache状态不一样:
cpu0 I,  cpu1 E:
cpu0 读addr,发现cpu1有对应的E cache,新建一个本地的cache line将cpu1的cache line拷贝过来,并且设置大家的状态为S。
cpu0 写addr,发现cpu1有对应的E cache,发送一个inv消息告诉cpu1,然后本地新建一个cache line将ddr读进来,之后修改本地cache line,并且设置状态M。
cpu1 读addr,直接读cache。
cpu1 写addr,直接写cache,设置状态为M。

cpu0 I, cpu1 M:
cpu0 读addr,发现cpu1有对应的M cache,发送一个flush消息告诉cpu1并且等待cpu1刷新cache到ddr,然后新建一个本地cache line将ddr从内存读进来,并且设置状态为E。
cpu0 写addr,发现cpu1有对应的M cache,发送一个flush消息告诉cpu1并且等待cpu1刷新cache到ddr,然后新建一个本地cache line将ddr从内存读进来并且写,并且设置状态为M。
cpu1 读addr,直接读。
cpu1 写addr,直接写。

内存屏障,一个经典的场景,插入链表一个节点。
cpu0
new->next = next;
wmb();
prev->next = new;

cpu1
读 prev->next
rmb();
读 new->next

如果没有内存屏障,cpu1读到最新的prev->next的时候,可能还没有读到最新的new->next。内核就要挂了。
换一种舒服的例子:
cpu0
a = 1;
wmb();
b = 2;

cpu1
读 b;
rmb();
读 a;
通过内存屏障能够保证cpu1假设读取到了b=2,那么cpu1读取的a肯定等于1。

看一看实现:
假设现在a和b在不同的cache line,并且不管在哪个cpu,他们的状态都是S的。(其他状态可以一样的分析)
cpu0三条指令,通过wmb()保证 先发送inv a,在发送inv b。或者说是,cpu1先收到inv a,后收到inv b的消息。
cpu1三条指令,rmb()保证在执行后面的指令之前,rmb前面所有的inv 指令都必须执行完成。假设读b的时候,inv b已经收到并且已经执行,则b获取到了最新的值。那么在执行读a的指令之前,一定会吧inv a执行了,因为inv a在inv 本就收到了(这个是cpu0的wmb保证的)
所以wmb,rmb都是缺一不可的。


补充改一下L2 cache,arm架构经常会有l2 cache, 不同与L1cahce, L2 cache是smp共享的一个cache。上面说的cache刷新到ddr,从ddr读取到cache,其实都是经过这个L2 cache的,比如cache刷新ddr,如果l2cache也有对应的cache的话则这个cache知会刷新到l2 cache, l2 cache会等待适当的时机或者主动调用api被刷新到真正的ddr。读的话也类似。
一般来说,L2 cache对软件来说是很透明的,除了启动的时候要初始化一下,并且需要将cache刷新真正的ddr的时候可以调用响应的操作方法来刷新。比如dma操作之前,可能需要clean或者inv L2 cache。



论坛徽章:
6
金牛座
日期:2013-10-08 10:19:10技术图书徽章
日期:2013-10-14 16:24:09CU十二周年纪念徽章
日期:2013-10-24 15:41:34狮子座
日期:2013-11-24 19:26:19未羊
日期:2014-01-23 15:50:002015年亚洲杯之阿联酋
日期:2015-05-09 14:36:15
发表于 2013-03-07 08:57 |显示全部楼层
回复 1# blake326
多谢分享!呵呵
有一本书专门介绍这个的,书名叫《what every programmer should know about memory》

   

论坛徽章:
16
2015亚冠之吉达阿赫利
日期:2015-08-17 11:21:462015年迎新春徽章
日期:2015-03-04 09:58:11酉鸡
日期:2014-12-07 09:06:19水瓶座
日期:2014-11-04 14:23:29天秤座
日期:2014-03-02 08:57:52双鱼座
日期:2014-02-22 13:07:56午马
日期:2014-02-14 11:08:18双鱼座
日期:2014-02-13 11:09:37卯兔
日期:2014-02-06 15:10:34子鼠
日期:2014-01-20 14:48:19戌狗
日期:2013-12-19 09:37:46射手座
日期:2013-12-19 09:33:47
发表于 2013-06-18 16:05 |显示全部楼层
本帖最后由 embeddedlwp 于 2013-06-18 16:09 编辑

回复 1# blake326

论坛徽章:
0
发表于 2013-06-19 00:26 |显示全部楼层
这篇文章也非常好 :  CPU Cache Flushing Fallacy
http://mechanical-sympathy.blogs ... ushing-fallacy.html

论坛徽章:
9
程序设计版块每日发帖之星
日期:2016-02-13 06:20:00数据库技术版块每日发帖之星
日期:2016-06-15 06:20:00数据库技术版块每日发帖之星
日期:2016-06-16 06:20:00数据库技术版块每日发帖之星
日期:2016-06-18 06:20:00程序设计版块每日发帖之星
日期:2016-06-27 06:20:00程序设计版块每日发帖之星
日期:2016-07-09 06:20:00IT运维版块每日发帖之星
日期:2016-07-15 06:20:00IT运维版块每日发帖之星
日期:2016-07-27 06:20:00程序设计版块每日发帖之星
日期:2016-08-18 06:20:00
发表于 2015-08-21 22:43 |显示全部楼层
本帖最后由 mordorwww 于 2015-08-21 23:09 编辑




木有撸主你想的辣么复杂

CPU1 和CPU2各自用内存屏障保证各自的先后顺序
对于共享的内存单元,CPU2看到的CPU1的指令执行结果的先后顺序还是由CPU1的内存屏障保证的,和CPU2自己的内存屏障鬼的关系,如果CPU2的内存屏障把顺序反过来,你CPU1也管不了


和cache其实木有关系,要是CPU木有cache,一样的结果
cache多了个同步而已

论坛徽章:
1
水瓶座
日期:2013-09-28 21:40:25
发表于 2015-08-22 17:27 |显示全部楼层
本帖最后由 bensenq 于 2015-08-22 17:28 编辑

现代CPU都支持乱序执行的,屏障就是用来确保某个CPU的实际访存顺序的。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP