从硬件引申出内存屏障,带你深入了解Linux内核RCU
本文简介
本文从硬件的角度引申出内存屏障,这不是内存屏障的详尽手册,但是相关知识对于理解RCU有所帮助。这不是一篇单独的文章,这是《谢宝友:深入理解Linux RCU》系列的第2篇,前序文章:
谢宝友: 深入理解Linux RCU之一——从硬件说起
作者简介
谢宝友,在编程一线工作已经有20年时间,其中接近10年时间工作于Linux操作系统。在中兴通讯操作系统产品部工作期间,他作为技术总工参与的电信级嵌入式实时操作系统,获得了行业最高奖----中国工业大奖。
同时,他也是《深入理解并行编程》一书的译者。该书作者Paul E.McKeney是IBM Linux中心领导者,Linux RCU Maintainer。《深入理解RCU》系列文章整理了Paul E.McKeney的相关著作,希望能帮助读者更深刻的理解Linux内核中非常难于理解的模块----RCU。
联系方式:
mail:scxby@163.com
微信:linux-kernel
稿件征集
欢迎您给Linuxer投稿,赢得人民邮电异步社区任意在售技术图书。您随便挑,详情:Linuxer-"Linux开发者自己的媒体"首月稿件录取和赠书名单
Linuxer-"Linux开发者自己的媒体"第二月稿件录取和赠书名单
一、内存Cache还有哪些不足?
上一篇文章我们谈到了内存Cache,并且描述了典型的Cache一致性协议MESI。Cache的根本目的,是解决内存与CPU速度多达两个数量级的性能差异。一个包含Cache的计算机系统,其结构可以简单的表示为下图:
仅仅只有Cache的计算机系统,它还存在如下问题:
1、Cache的速度,虽然比内存有了极大的提升,但是仍然比CPU慢几倍。
2、在发生"warmup cache miss"、"capacity miss"、"associativity miss"时,CPU必须等待从内存中读取数据,此时CPU会处于一种Stall的状态。其等待时间可能达到几百个CPU指令周期。
显然,这是现代计算机不能承受之重:)
二、Write buffer是为了解决什么问题?
如果CPU仅仅是执行foo = 1这样的语句,它其实无须从内存或者缓存中读取foo现在的值。因为无论foo当前的值是什么,它都会被覆盖。在仅仅只有Cache的系统中,foo = 1 这样的操作也会形成写停顿。自然而然的,CPU设计者应当会想到在Cache 和CPU之间再添加一级缓存。由于这样的缓存主要是应对写操作引起的Cache Miss,并且缓存的数据与写操作相关,因此CPU设计者将它命名为"Write buffer"。调整后的结构示意图如下(图中的store buffer即为write buffer):
通过增加这些Write buffer,CPU可以简单的将要保存的数据放到Write buffer 中,并且继续运行,而不会真正去等待Cache从内存中读取数据并返回。
对于特定CPU来说,这些Write buffer是属于本地的。或者在硬件多线程系统中,它对于特定核来说,是属于本地的。无论哪一种情况,一个特定CPU仅仅允许访问分配给它的Writebuffer。例如,在上图中,CPU 0不能访问CPU 1的存储缓冲,反之亦然。
Write buffer进一步提升了系统性能,但是它也会为硬件设计者带来一些困扰:
第一个困扰:违反了自身一致性。
考虑如下代码:变量"a"和"b"都初始化为0,包含变量"a"缓存行,最初被CPU 1所拥有,而包含变量"b"的缓存行最初被CPU0所拥有:
1 a = 1;
2 b = a + 1;
3 assert(b == 2);
没有哪一位软件工程师希望断言被触发!
然而,如果采用上图中的简单系统结构,断言确实会被触发。理解这一点的关键在于:a最初被CPU 1所拥有,而CPU 0在执行a = 1时,将a的新值存储在CPU 0的Write buffer中。
在这个简单系统中,触发断言的事件顺序可能如下:
1.CPU 0 开始执行a = 1。
2.CPU 0在缓存中查找"a",并且发现缓存缺失。
3.因此,CPU 0发送一个"读使无效(read-invalidate message)"消息,以获得包含"a"的独享缓存行。
4.CPU 0将"a"记录到存储缓冲区。
5.CPU 1接收到"读使无效"消息,它通过发送缓存行数据,并从它的缓存行中移除数据来响应这个消息。
6.CPU 0开始执行b = a + 1。
7.CPU 0从CPU 1接收到缓存行,它仍然拥有一个为"0"的"a"值。
8.CPU 0从它的缓存中读取到"a"的值,发现其值为0。
9.CPU 0将存储队列中的条目应用到最近到达的缓存行,设置缓存行中的"a"的值为1。
10.CPU 0将前面加载的"a"值0加1,并存储该值到包含"b"的缓存行中(假设已经被CPU 0所拥有)。
11.CPU 0 执行assert(b == 2),并引起错误。
- 工控机在IC卡加油工程中的应用(05-13)
- 联网汽车为什么选择Linux开源平台?(07-10)
- 多网络和Linux代理的Android无线远程控制系统(02-02)
- 基于嵌入式Linux的家居监控系统设计(02-22)
- 基于嵌入式Linux系统的导航软件设计思路(03-17)
- 新型嵌入式机器视觉系统的设计研究(04-21)