您好,欢迎来到12图资源库!分享精神,快乐你我!我们只是素材的搬运工!!
  • 首 页
  • 当前位置:首页 > 开发 > WEB开发 >
    与顺序员相关的CPU缓存知识
    时间:2020-03-07 21:10 来源:网络整理 作者:网络 浏览:收藏 挑错 推荐 打印

     良久没有写一些微观方面的文章了,明天写一篇关于 CPU Cache 相关的文章,这篇文章比较长,主要分红这么几个部分:基础知识、缓存的命中、缓存的分歧性、相关的代码示例和延伸阅读。其中会讲述一些多核 CPU 的系统架构以及其原理,包括对顺序功用上的影响,以及在停止并发编程的时分需求留意到的一些成绩。这篇文章我会尽量地写复杂和深刻易懂一些,主要是讲清楚相关的原理和成绩,而关于一些细节和延伸阅读我会在文章最后会给出相关的资源。

    由于无论你写什么样的代码都会交给 CPU 来执行,所以,假设你想写出功用比较高的代码,这篇文章中提到的技术还是值得仔细学习的。

    基础知识

    首先,我们都知道如今的 CPU 多核技术,都会有几级缓存,老的 CPU 会有两级内存(L1 和 L2),新的 CPU 会有三级内存(L1,L2,L3 ),如下图所示:

    与顺序员相关的CPU缓存知识

    其中:

    L1 缓分红两种,一种是指令缓存,一种是数据缓存。L2 缓存和 L3 缓存不分指令和数据。

    L1 和 L2 缓存在第一个 CPU 核中,L3 则是一切 CPU 中心共享的内存。

    L1、L2、L3 的越离 CPU 近就越小,速度也越快,越离 CPU 远,速度也越慢。

    再往前面就是内存,内存的前面就是硬盘。我们来看一些他们的速度:

    L1 的存取速度:4 个 CPU 时钟周期

    L2 的存取速度: 11 个 CPU 时钟周期

    L3 的存取速度:39 个 CPU 时钟周期

    RAM 内存的存取速度:107 个 CPU 时钟周期

    我们可以看到,L1 的速度是 RAM 的 27 倍,但是 L1/L2 的大小基本上也就是 KB 级别的,L3 会是 MB 级别的。例如:Intel Core i7-8700K ,是一个 6 核的 CPU,每核上的 L1 是 64KB(数据和指令各 32KB),L2 是 256K,L3 有 12MB(我的苹果电脑是 Intel Core i9-8950HK,和 Core i7-8700K 的 Cache 大小一样)。

    我们的数据就从内存向上,先到 L3,再到 L2,再到 L1,最后到寄存器停止 CPU 计算。为什么会设计成三层?这里有下面几个方面的思索:

    一个方面是物理速度,假设要更大的容量就需求更多的晶体管,除了芯片的体积会变大,更重要的是少量的晶体管会招致速度下降,由于拜访速度和要拜访的晶体管所在的位置成正比,也就是当信号途径变长时,通讯速度会变慢。这部分是物理成绩。

    另外一个成绩是,多核技术中,数据的形状需求在多个 CPU 中停止同步,并且,我们可以看到,cache 和 RAM 的速度差距太大,所以,多级不同尺寸的缓存有利于提高全体的功用。

    这个世界永远是平衡的,一面变得有多光鲜,另一面也会变得有多黑暗。树立这么多级的缓存,一定就会引入其它的成绩,这里有两个比较重要的成绩,

    一个是比较复杂的缓存的命中率的成绩。

    另一个是比较复杂的缓存更新的分歧性成绩。

    尤其是第二个成绩,在多核技术下,这就很像散布式的舷了,要对多个中央停止更新。

    缓存的命中

    在阐明这两个成绩之前。我们需求要解一个术语 Cache Line。缓存基本下去说就是把前面的数据加载到离本人近的中央,关于 CPU 来说,它是不会一个字节一个字节的加载的,由于这十分没有效率,普通来说都是要一块一块的加载的,关于这样的一块一块的数据单位,术语叫“Cache Line”,普通来说,一个主流的 CPU 的 Cache Line 是 64 Bytes(也有的 CPU 用 32Bytes 和 128Bytes),64Bytes 也就是 16 个 32 位的整型,这就是 CPU 从内存中捞数据下去的最小数据单位。

    比如:Cache Line 是最小单位(64Bytes),所以先把 Cache 散布多个 Cache Line,比如:L1 有 32KB,那么,32KB/64B = 512 个 Cache Line。

    一方面,缓存需求把内存里的数据放到放出去,英文叫 CPU Associativity。Cache 的数据放置的策略决议了内存中的数据块会拷贝到 CPU Cache 中的哪个位置上,由于 Cache 的大小远远小于内存,所以,需求有一种地址关联的算法,可以让内存中的数据可以被映射到 Cache 中来。这个有点像内存地址从逻辑地址向虚拟地址映射的办法,但不完全一样。

    基本下去说,我们会有如下的一些办法。

    一种办法是,任何一个内存地址的数据可以被缓存在任何一个 Cache Line 里,这种办法是最灵敏的,但是,假设我们要知道一个内存能否存在于 Cache 中,我们就需求停止O(n)复杂度的 Cache 遍历,这是很没有效率的。

    另一种办法,为了降低缓存搜索算法,我们需求运用像 Hash Table 这样的数据结构,最复杂的 hash table 就是做“求模运算”,比如:我们的 L1 Cache 有 512 个 Cache Line,那么,公式:(内存地址 mod 512)* 64 就可以直接找到所在的 Cache 地址的偏移了。但是,这样的方式需求我们的顺序对内存地址的拜访要十分地平均,不然抵触就会十分严重。这成了一种十分理想的状况了。

    为了避免上述的两种方案的成绩,于是就要容忍一定的 hash 抵触,也就出现了 N-Way 关联。也就是把延续的N个 Cache Line 绑成一组,然后,先把找到相关的组,然后再在这个组内找到相关的 Cache Line。这叫 Set Associativity。如下图所示。

    关于 N-Way 组关联,能够有点不好了解,这里个例子,并多说一些细节(不然前面的代码你会不能了解),Intel 大少数处置器的 L1 Cache 都是 32KB,8-Way 组相联,Cache Line 是 64 Bytes。这意味着,

    32KB 的可以分红,32KB / 64 = 512 条 Cache Line。

    由于有 8 Way,于是会每一 Way 有 512 / 8 = 64 条 Cache Line。

    于是每一路就有 64 x 64 = 4096 Byts 的内存。

    为了方便索引内存地址,

    Tag:每条 Cache Line 前都会有一个独立分配的 24 bits 来存的 tag,其就是内存地址的前 24bits

    Index:内存地址后续的 6 个 bits 则是在这一 Way 的是 Cache Line 索引,2^6 = 64 刚好可以索引 64 条 Cache Line

    Offset:再往后的 6bits 用于表示在 Cache Line 里的偏移量

    如下图所示:(更多的细节可以读一下《Cache: a place for concealment and safekeeping》)

    与顺序员相关的CPU缓存知识

    (图片来自《Cache: a place for concealment and safekeeping》)

    这也意味着:

    L1 Cache 可映射 36bits 的内存地址,一共 2^36 = 64GB 的内存

    由于只需头 24bits 相反就会被映射到同一个 Way 中,所以,基本上就是说,有2^12 = 4096 个地址会放在同一 Way 中。

    当 CPU 要拜访一个内存的时分,经过这个内存的前 24bits 和中间的 6bits 可以直接定位相应的 Cache Line。

    (责任编辑:admin)