• cpu缓存以及内存屏障


    0 CPU缓存

    缓存的出现主要是为了解决CPU运算速度与内存读写速度不匹配的矛盾,因为CPU运算速度要比内存读写速度快很多,这样会使CPU花费很长时间等待数据到来或把数据写入内存。

    当CPU要读取一个数据时,首先从缓存中查找,如果找到就立即读取并送给CPU处理;如果没有找到,就用相对慢的速度从内存中读取并送给CPU处理,同时把这个数据所在的数据块调入缓存中,可以使得以后对整块数据的读取都从缓存中进行,不必再调用内存。

    按照数据读取顺序和与CPU结合的紧密程度,CPU缓存可以分为一级缓存,二级缓存,部分高端CPU还具有三级缓存,每一级缓存中所储存的全部数据都是下一级缓存的一部分,这三种缓存的技术难度和制造成本是相对递减的,所以其容量也是相对递增的。

    性能提升:对于整体性能的作用,L1 cache最大,L2次之

    0.1 CPU一级缓存

    一级缓存是相对于二级缓存来命名的,它是直接与CPU数据总线相连,传输速度接近于CPU处理速度。

    一级缓存(Level 1 Cache)简称L1 Cache,位于CPU内核的旁边,是与CPU结合最为紧密的CPU缓存,一级缓存的技术难度和制造成本最高,提高容量所带来的技术难度增加和成本增加非常大,所带来的性能提升却不明显,性价比很低。

    而且现有的一级缓存的命中率已经很高,所以一级缓存是所有缓存中容量最小的

    l1致力于更快的速度,因此采用哈佛结构是一种将程序指令存储和数据存储分开的存储器结构。所以一级缓存可以分为一级数据缓存和一级指令缓存,但是AMD和inter采用不同的方式。数据和指令分离可以做到减少冲突

    而二级缓存和三级缓存都采用的是冯·诺依曼结构将程序指令存储器和数据存储器合并在一起的存储器结构。哈佛结构的微处理器通常具有较高的执行效率

    而一级缓存小的原因在于昂贵,而且做大了以后在一级缓存中查找数据也就慢了。

    0.2 CPU二级缓存

    二级缓存是CPU性能表现的关键之一,在CPU核心不变化的情况下,增加二级缓存容量能使性能大幅度提高。

    主要原因在于二级缓存提高命中。

    根据28定律,80%的的数据在都可以直接在一级缓存中找到,而剩下的20%的80%可以再二级缓存中找到,因此就是说,96%的数据都可以在一二级缓存中找到。

    其中一二级缓存,每个核心都有一个,但是所有核心共享三级缓存

    0.3 CPU三级缓存

    三级缓存是为读取二级缓存后未命中的数据设计的—种缓存,在拥有三级缓存的CPU中,只有约5%的数据需要从内存中调用,这进一步提高了CPU的效率。

    三级缓存的作用是为了进一步提高命中。

    0.4 更多级缓存

    存在四级缓存等。

    Intel 的CPU已经有增加L4缓存的版本了,不过这里的L4主要用于解决核显和CPU之间交换数据,称为eDRAM。原先的核显没有显存,只能共享内存空间,限制了核显性能和效率。现在在CPU和GPU之间增加了128MB的eDRAM,让GPU与CPU做数据交换。

    另外服务器cpu也有四级缓存

    三级缓存的大小已经几乎是核心体积的一半了,再加缓存cpu体积会增加。

    缓存存储

    cpu缓存和内存之间交换的数据,是长度固定的块,称为缓存航.通常是2^n,一般16~256字节不等.

    大量缓存是通过硬件哈希表来实现的.这些哈希表有固定长度的哈系桶.

    每个桶能够存储一个缓存行大小的数据.然后几个桶组成一路.也就是哈希值定位到的位置.

    一般哈希都比较简单,单纯的使用4位来表示,因此也就是说有16路.每路多个桶.

    缓存一致性协议

    缓存一致性协议管理缓存行的状态.防止数据不一致或是丢失数据.

    协议十分复杂,每一个缓存行行有十几种可选的状态.但是基本的有下面四中:

    exclusive:独占,并且没有修改.也就是说某个cpu核心独占了该缓存,在其他的核心中都没有缓存该缓存行.并且该核心还没有修改该缓存行的数据,因此他可以丢弃该缓存,或是转移给其他核心

    modified:独占,并且修改了该缓存,该核心拥有该缓存行的最新数据.因此必须要将其写会内存或是移交给其他核心

    shared:非独占,多个核心可同时保持该缓存.但是不能修改,也不需要转交给别的核心

    invalid:无效,也就是说该缓存行为空,之前的缓存行从该核心中移除了.

    当一个核心需要读数据的时候,需要想起他cpu广播,那么拥有该缓存的,核心需要响应这个读消息.modified状态的缓存行的核心,必须要相应这个消息.然后将缓存行移交给核心,缓存行状态设置为shared

    写,需要向其他核心发送使无效消息

    存储缓冲和乱序执行

    当一个核心要覆盖某个缓存行中的数据是,也就是说要赋值,而不是简单的递增.

    那么该核心收到该缓存以后就要将该缓存行覆盖,也就是说他并不需要缓存行中的数据.

    但是为了等待该缓存行的到来.需要时间.

    因此为了加速这种操作.cpu在缓存之间有加了一个存储缓冲.

    也就是这些需要直接赋值(可以理解为直接覆盖)的缓存行先存储到存储缓冲中.当缓存行到了以后再覆盖回去.

    但是,这种加速操作,是存在问题的:

    在存储缓冲中的缓存行,必须需要等待缓存中的缓存行到来以后才能将其写到缓存中的缓存行.

    并且,如果缓存行没有读到缓冲之前的这段时间,cpu会继续其他的操作.例如修改该核心独占的存储缓冲.

    例如,cpu1,要覆盖a,但是缓存行a,不在cpu1.同时cpu1还要修改b,b在自己的缓冲中.

    cpu2,需要判断b的值,然后对a进行操作.并且持有缓存行a

    所以,cpu1因为要覆盖a,因此覆盖后的a存储在存储缓冲中,并且向其他核心,发送使读无效消息.(使读无效消息,延时到达cpu2,也就是说cpu之间的通信不是队列形式的,和socket有的一拼)然后继续去修改b.并且在缓存行a到来之前,修改完b了.

    然后cpu2发送读b的消息.cpu1收到以后,发送自己的缓存行b.然后cpu2收到缓存行b以后,判断b的值,可以进行下面的操作了.但是此时缓存行a的使读无效消息还没有到,因此cpu2此时使用的是a的旧数据.

    也就是说数据不一致的行为的根源在于,cpu将要覆写的数据存储在存储缓冲中,继续执行别的指令.同时使读无效消息到达别的cpu之前,别的cpu,因为之前阻塞,但是在使读无效消息到达之前,阻塞解除.使用了该数据.

    其实,理解3个cpu更好,因为那个使读无效消息到达的太晚了.

    内存屏障

    而内存屏障就是为了解决这个问题的.在于,当执行一条语句以后,如果该语句的消息必须实时更新.

    那么使用内存屏障,会将该语句后面的修改语句都存储到存储缓冲里,然后当需要修改的缓存行到达缓冲中,才会将存储缓冲里的数据依次写到缓存行里.

    这样就避免了缓存不一致的行为.

    也就是说内存屏障的意义在于,在内存屏障语句调用之前,必须先讲存储缓冲中的数据全部刷新回缓存行,后面语句修改的数据才能够再次修改缓冲行,否则,就要放入存储缓冲中.

    cpu乱序执行

    现代处理器采用指令并行技术-流水线,在不存在数据依赖性的前提下,处理器可以改变语句对应的机器指令的执行顺序来提高处理器执行速度.

    这个过程是不会引起数据不一致的.因为操作如果存在数据依赖的情况,那么使用同一数据的指令,一定是按顺序执行的.并不会乱序.

    只有使用不同数据的执行之间才会乱序.

  • 相关阅读:
    SQL之层次查询
    GROUP函数
    SQL之统计
    正则表达式
    聚合函数,分析函数
    oracle函数
    Vue3.0优化
    浅谈FC
    短链接生成原理
    Vue路由传参
  • 原文地址:https://www.cnblogs.com/perfy576/p/8582413.html
Copyright © 2020-2023  润新知