CPU缓存一致性协议

CPU高速缓存

CPU缓存是位于cpu和内存之间的临时数据交换器,它的容量比内存小的夺但是交换速度要比内存快得多,主要是为了解决cpu运行时的处理速度与内存读写速度不匹配的问题。

cpu在执行指令时需要从内存中获取所需要的指令和数据,但是cpu的处理速度远大于内存的读写速度,所以cpu如果直接从内存中读写数据需要等待一定的时间周期,这样会造成浪费且影响性能。所以引入了cpu缓存

缓存与主存(内存)

如图。主存(内存):DRAM,缓存:SRAM

常见的CPU缓存结构为三级缓存。L1(一级缓存)、L2(二级缓存)、L3(三级缓存),级别越小越接近CPU,容量越小读写速度也越快。

L1L2属于片内缓存(CPU核内),L3是CPU之间的共享缓存。

查找缓存时也是由近及远,L1 -> L2 -> L3 -> 主存

缓存行

缓存行是缓存中可以分配的最小存储单位,通常为64个字节,CPU缓存是由一组缓存行的固定大小的数据块组成的。

局部性原理

CPU将需要重复处理的数据和指令放在CPU缓存中,而不是内存中,减少了响应时间,体现了局部性原理

  • 时间局部性:如果某个数据被访问,那它很可能在不久的将来被再次访问。
  • 空间局部性:如果某个数据被访问,那与他相邻的数据也可能很快被访问。

CPU执行计算过程

  • 程序和数据被加载到主内存
  • 指令和数据被加载到CPU高速缓存
  • CPU执行指令,把结果写回高速缓存
  • 将高速缓存中的数据写回到主内存

CPU缓存一致性协议

引入了CPU高速缓存之后提升了效率,但是同时也会引发主存与缓存不一致的问题。

为了保证多个CPU缓存中共享数据的一致性,提出了MESI协议,定义了缓存行(Cache Line)的四种状态。而CPU对缓存行的四种操作可能会产生不一致的状态,因此缓存控制器监听到本地操作和远程操作的时候,需要对地址一致的缓存行状态进行一致性的修改,从而保证数据在多个缓存之间保持一致性。

MESI协议

缓存行的四种状态:

状态 描述 监听任务 状态转换
M(Modified)修改 该缓存行有效,数据被修改导致与内存中数据不一致,数据只存在于当前CPU缓存中。 缓存行必须时刻监听所有试图读该缓存行相对就主存的操作,这种操作必须在缓存将该缓存行写回主存并将状态变成S(共享)状态之前被延迟执行。 当被写回主存之后,该缓存行的状态会变成独享(exclusive)状态。
E(Exclusive)独享 该缓存行有效,只有当前CPU有数据,与内存中数据一致,只存在于当前CPU缓存中。 缓存行也必须监听其它缓存读主存中该缓存行的操作,一旦有这种操作,该缓存行需要变成S(共享)状态。 当CPU修改该缓存行中内容时,该状态可以变成Modified状态
S(Shared)共享 该缓存行有效,与内存中数据一致,数据存在于很多CPU缓存中(多个CPU拥有相同数据) 缓存行也必须监听其它缓存使该缓存行无效或者独享该缓存行的请求,并将该缓存行变成无效(Invalid)。 当有一个CPU修改该缓存行时,其它CPU中该缓存行可以被作废(变成无效状态 Invalid)。
I(Invalid)无效 该缓存行无效。 - -

下图表示了当一个缓存行(Cache line)的调整的状态的时候,另外一个缓存行(Cache line)需要调整的状态。

状态 M E S I
M × × ×
E × × ×
S × ×
I

对于M和E状态而言总是精确的,他们在和该缓存行的真正状态是一致的,而S状态可能是非一致的

如果一个缓存将处于S状态的缓存行作废了,而另一个缓存实际上可能已经独享了该缓存行,但是该缓存却不会将该缓存行升迁为E状态,这是因为其它缓存不会广播他们作废掉该缓存行的通知,同样由于缓存并没有保存该缓存行的copy的数量,因此(即使有这种通知)也没有办法确定自己是否已经独享了该缓存行。

状态 触发本地读取 触发本地写入 触发远端读取 触发远端写入
M(修改) 本地cache:M
触发cache:M
其他cache:I
本地cache:M
触发cache:M
其他cache:I
本地cache:M→E→S 触发cache:I→S 其他cache:I→S 同步主内存后修改为E独享,同步触发、其他cache后本地、触发、其他cache修改为S共享 本地cache:M→E→S→I 触发cache:I→S→E→M 其他cache:I→S→I 同步和读取一样,同步完成后触发cache改为M,本地、其他cache改为I
E(独享) 本地cache:E 触发cache:E 其他cache:I 本地cache:E→M 触发cache:E→M 其他cache:I 本地cache变更为M,其他cache状态应当是I(无效) 本地cache:E→S 触发cache:I→S 其他cache:I→S 当其他cache要读取该数据时,其他、触发、本地cache都被设置为S(共享) 本地cache:E→S→I 触发cache:I→S→E→M 其他cache:I→S→I 当触发cache修改本地cache独享数据时时,将本地、触发、其他cache修改为S共享.然后触发cache修改为独享,其他、本地cache修改为I(无效),触发cache再修改为M
S(共享) 本地cache:S 触发cache:S 其他cache:S 本地cache:S→E→M 触发cache:S→E→M 其他cache:S→I 当本地cache修改时,将本地cache修改为E,其他cache修改为I,然后再将本地cache为M状态 本地cache:S 触发cache:S 其他cache:S 本地cache:S→I 触发cache:S→E→M 其他cache:S→I 当触发cache要修改本地共享数据时,触发cache修改为E(独享),本地、其他cache修改为I(无效),触发cache再次修改为M(修改)
I(无效) 本地cache:I→S或者I→E 触发cache:I→S或者I →E 其他cache:E、M、I→S、I 本地、触发cache将从I无效修改为S共享或者E独享,其他cache将从E、M、I 变为S或者I 本地cache:I→S→E→M 触发cache:I→S→E→M 其他cache:M、E、S→S→I 既然是本cache是I,其他cache操作与它无关 既然是本cache是I,其他cache操作与它无关

(上图和表格并不是很理解。)

多核缓存协同操作

假设有三个CPU A、B、C,对应三个缓存分别是cache a、b、c。在主内存中定义了x的引用值为0。

单核读取的执行流程是:

  • CPU A发出了一条指令,从主内存中读取x
  • 从主内存通过 bus 读取到 CPU A 的缓存中(远端读取 Remote read),这时该 Cache line 修改为 E 状态(独享)。

双核读取的执行流程是:

  • CPU A发出了一条指令,从主内存中读取x
  • CPU A从主内存通过bus读取到 cache a 中并将该 Cache line 设置为E状态。
  • CPU B发出了一条指令,从主内存中读取x
  • CPU B试图从主内存中读取x时,CPU A检测到了地址冲突。这时CPU A对相关数据做出响应。此时x存储于 cache a 和 cache b 中,x在 chche a 和 cache b 中都被设置为S状态(共享)。

修改数据的执行流程是:

  • CPU A 计算完成后发指令需要修改x.
  • CPU A 将x设置为M状态(修改)并通知缓存了x的 CPU B, CPU B 将本地 cache b 中的x设置为I状态(无效)
  • CPU A 对x进行赋值。

同步数据的执行流程是:

  • CPU B 发出了要读取x的指令。
  • CPU B 通知CPU A,CPU A将修改后的数据同步到主内存时cache a 修改为E(独享)
  • CPU A同步CPU B的x,将cache a和同步后cache b中的x设置为S状态(共享)。

CPU存储模型

MESI协议为了保证多个 CPU cache 中共享数据的一致性,定义了 Cache line 的四种状态,而 CPU 对 cache 的4种操作可能会产生不一致状态,因此 cache 控制器监听到本地操作和远程操作的时候,需要对地址一致的 Cache line 状态做出一定的修改,从而保证数据在多个cache之间流转的一致性。

但是,缓存的一致性消息传递是要时间的,这就使得状态切换会有更多的延迟。

某些状态的切换需要特殊的处理,可能会阻塞处理器。这些都将会导致各种各样的稳定性和性能问题。

比如你需要修改本地缓存中的一条信息,那么你必须将I(无效)状态通知到其他拥有该缓存数据的CPU缓存中,并且等待确认。等待确认的过程会阻塞处理器,这会降低处理器的性能。因为这个等待远远比一个指令的执行时间长的多。所以,为了为了避免这种阻塞导致时间的浪费,引入了存储缓存(Store Buffer)和无效队列(Invalidate Queue)。

存储缓存

在没有存储缓存时,CPU 要写入一个量,有以下情况:

  • 量不在该 CPU 缓存中,则需要发送 Read Invalidate 信号,再等待此信号返回,之后再写入量到缓存中。
  • 量在该 CPU 缓存中,如果该量的状态是 Exclusive 则直接更改。而如果是 Shared 则需要发送 Invalidate 消息让其它 CPU 感知到这一更改后再更改。

这些情况中,很有可能会触发该 CPU 与其它 CPU 进行通讯,接着需要等待它们回复。这会浪费大量的时钟周期!为了提高效率,可以使用异步的方式去处理:先将值写入到一个 Buffer 中,再发送通讯的信号,等到信号被响应,再应用到 cache 中。并且此 Buffer 能够接受该 CPU 读值。这个 Buffer 就是 Store Buffer。而不须要等待对某个量的赋值指令的完成才继续执行下一条指令,直接去 Store Buffer 中读该量的值,这种优化叫Store Forwarding

无效队列

同理,解决了主动发送信号端的效率问题,那么,接受端 CPU 接受到 Invalidate 信号后如果立即采取相应行动(去其它 CPU 同步值),再返回响应信号,则时钟周期也太长了,此处也可优化。接受端 CPU 接受到信号后不是立即采取行动,而是将 Invalidate 信号插入到一个队列 Queue 中,立即作出响应。等到合适的时机,再去处理这个 Queue 中的 Invalidate 信号,并作相应处理。这个 Queue 就是Invalidate Queue

乱序执行

乱序执行(out-of-orderexecution:是指CPU允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理的技术。这样将根据各电路单元的状态和各指令能否提前执行的具体情况分析后,将能提前执行的指令立即发送给相应电路。

这好比请A、B、C三个名人为晚会题写横幅“春节联欢晚会”六个大字,每人各写两个字。如果这时在一张大纸上按顺序由A写好”春节”后再交给B写”联欢”,然后再由C写”晚会”,那么这样在A写的时候,B和C必须等待,而在B写的时候C仍然要等待而A已经没事了。

但如果采用三个人分别用三张纸同时写的做法, 那么B和C都不必须等待就可以同时各写各的了,甚至C和B还可以比A先写好也没关系(就象乱序执行),但当他们都写完后就必须重新在横幅上(自然可以由别人做,就象CPU中乱序执行后的重新排列单元)按”春节联欢晚会”的顺序排好才能挂出去。

所以,CPU 为什么会有乱序执行优化?本质原因是CPU为了效率,将长费时的操作“异步”执行,排在后面的指令不等前面的指令执行完毕就开始执行后面的指令。而且允许排在前面的长费时指令后于排在后面的指令执行完。

CPU 执行乱序主要有以下几种:

  • 写写乱序(store store)a=1;b=2; -> b=2;a=1;
  • 写读乱序(store load)a=1;load(b); -> load(b);a=1;
  • 读读乱序(load load)load(a);load(b); -> load(b);load(a);
  • 读写乱序(load store)load(a);b=2; -> b=2;load(a);

总而言之,CPU的乱序执行优化指的是处理器为提高运算速度而做出违背代码原有顺序的优化

[JVM] CPU缓存一致性协议的更多相关文章

  1. 并发研究之CPU缓存一致性协议(MESI)

    CPU缓存一致性协议MESI CPU高速缓存(Cache Memory) CPU为何要有高速缓存 CPU在摩尔定律的指导下以每18个月翻一番的速度在发展,然而内存和硬盘的发展速度远远不及CPU.这就造 ...

  2. C和C++中的volatile、内存屏障和CPU缓存一致性协议MESI

    目录 1. 前言2 2. 结论2 3. volatile应用场景3 4. 内存屏障(Memory Barrier)4 5. setjmp和longjmp4 1) 结果1(非优化编译:g++ -g -o ...

  3. 多线程之:MESI-CPU缓存一致性协议

    MESI(Modified Exclusive Shared Or Invalid)(也称为伊利诺斯协议,是因为该协议由伊利诺斯州立大学提出)是一种广泛使用的支持写回策略的缓存一致性协议,该协议被应用 ...

  4. CPU缓存一致性协议—MESI详解

    MESI(也称伊利诺斯协议)是一种广泛使用的支持写回策略的缓存一致性协议,该协议被应用在Intel奔腾系列的CPU中. MESI协议中的状态 CPU中每个缓存行使用的4种状态进行标记(使用额外的两位b ...

  5. CPU缓存一致性协议与java中的volatile关键字

    有关缓存一致性协议MESI自行百度. 提出问题:volatile在缓存一致性协议上又做了哪些事情?为啥它不保证原子性? 在缓存一致性协议下,CPU为了执行效率使用了写(存储)缓存和失效队列从而导致对用 ...

  6. MESI-CPU缓存一致性协议

    转http://blog.csdn.net/realxie/article/details/7317630 http://en.wikipedia.org/wiki/MESI_protocol MES ...

  7. 一篇文章让你明白CPU缓存一致性协议MESI

    CPU高速缓存(Cache Memory) CPU为何要有高速缓存 CPU在摩尔定律的指导下以每18个月翻一番的速度在发展,然而内存和硬盘的发展速度远远不及CPU.这就造成了高性能能的内存和硬盘价格及 ...

  8. 【并发编程】MESI--CPU缓存一致性协议

    原文:多线程之:MESI-CPU缓存一致性协议 概念 MESI(Modified Exclusive Shared Or Invalid)(也称为伊利诺斯协议,是因为该协议由伊利诺斯州立大学提出)是一 ...

  9. Java内存模型(二)volatile底层实现(CPU的缓存一致性协议MESI)

    CPU的缓存一致性协议MESI 在多核CPU中,内存中的数据会在多个核心中存在数据副本,某一个核心发生修改操作,就产生了数据不一致的问题,而一致性协议正是用于保证多个CPU cache之间缓存共享数据 ...

  10. 12 张图看懂 CPU 缓存一致性与 MESI 协议,真的一致吗?

    本文已收录到  GitHub · AndroidFamily,有 Android 进阶知识体系,欢迎 Star.技术和职场问题,请关注公众号 [彭旭锐] 进 Android 面试交流群. 前言 大家好 ...

随机推荐

  1. P5723 注意特殊情况

    https://www.luogu.com.cn/problem/P5723 不是难题,但是倘若忽略L<2的情况就无法AC,Lougu得分只有80.因此写完题后一定要把各种边界性质的数据想出并用 ...

  2. pycharm解决test_开头文件报错的问题

    一.问题描述 运行时报了如下错误:

  3. 01_设计一个有getMin功能的栈

    01_设计一个有getMin功能的栈 [题目] 实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返回栈中最小元素的操作. [要求] pop.push.getMin操作的时间复杂度都是O(1) 设计 ...

  4. 理解 docker volume

    1. docker volume 简介 文章 介绍了 docker image,它由一系列只读层构成,通过 docker image 可以提高镜像构建,存储和分发的效率,节省时间和存储空间.然而 do ...

  5. RL 基础 | 讲的很好的 TRPO 博客

    特意存档: 知乎 | 如何看懂TRPO里所有的数学推导细节? 感觉把 idea 讲的很清楚(虽然没有特别仔细看-

  6. AI毕业设计生成器(基于AI大模型技术开发)

    这是一个辅助生成计算机毕业设计的工具,可以自动完成毕业设计的源码.它基于几百个github上面开源的java和python项目,运用tengsorflow技术,训练出了AI大模型.基本实现了计算机毕业 ...

  7. 【解决方案】如何使用 Http API 代替 OpenFeign 进行远程服务调用

    目录 前言 一.何为OpenFeign 1.1@FeignClient注解 1.2注意事项 二.常见的Http API 2.1Apache 2.2Okhttp 2.3Hutool 三.RestTemp ...

  8. SD协议-时序

    1.SD Timing 时序主要体现在CMD和Response的时序 S - 起始位,一直为0 T - Transmitter,1表示CMD(发起端是Host),0表示Response(发起端是Car ...

  9. 【Spring 5核心原理】1设计模式

    1.1开闭原则 开闭原则(open-closed principle,OCP)是指一个软件实体(如类,模块和函数)应该对扩展开放,对修改关闭.所谓的开闭,也正是对扩展和修改两个行为的一个原则. 强调用 ...

  10. [转帖]tiup cluster scale-in

    https://docs.pingcap.com/zh/tidb/stable/tiup-component-cluster-scale-in tiup cluster scale-in 命令用于集群 ...