预热 - CPU 一文解决你所有疑问

本文是个意外,就像有时候忘了那啥相同,纯属意外,我们看个热烈,就当个预热吧,打算写这部分的,内容太多了,看资料看的头疼

本文源于一个 JY 关于 volatile 可见性的疑问,下面是我的作答:

很高兴又看到一个乐意刨根问底的小伙伴,其实你的问题十分好,核心本质是你不了解 CPU 的整套运转逻辑。整个 CPU 国际都跑在这套底层运转逻辑上的,一切的上层逻辑都要依附于,适配这套底层运转逻辑 CPU 硬件包括 2 方面: 硬件 IC 规划 + CPU运转逻辑(CPU 驱动),CPU 也是有驱动的

MESI 协议是在多线程技能之后发生的,很古老,之后又诞生了 多核、乱序履行、流水线 等新的技能。CPU 这个范畴毕竟是一个商业范畴,技能的挑选要以商业体现来衡量,在技能的发展中一定会遇到相互对立的时刻,MESI 协议便是这样。 MESI 协议是次序一致性的,在处理音讯时必定造成整个流水线中止等候数据改写,而这个等候本钱十分的大,甚至说是致命的

现代 CPU 一个时钟周期能够处理 2-3 条指令,L1 的拜访速度 1-2 个时钟周期,L2/L3 的拜访速度会依次更慢,到内存时拜访速度会到达 80-150 个时钟周期,小伙伴你想想,MESI 中止的价值肯定是不能承受的,你中止一下的机遇都够完结整个方法的核算了…所以现在都有一个 InvalidataQueue 无效行列,一切的 MESI 发送的无效音讯接纳都是直接承受的,可是履行的话便是立即了,而是等候 cpu 空闲或许与内存、缓存的仿存操作完毕后再履行

我把现代 CPU 流水线大约给你说一下:(以 ARM A53 为例)

  1. 取指: 4 个时钟周期去取一次指令,一次取 4-6 条,然后储存在 CPU 核心拟定缓存内
  2. 解码: 里边有 2-4 个独立行列,每个行列在 4 个时钟周期内把自己分配到的指令 解码成 更微小的,CPU 硬件 IC 能处理的微指令,然后这个微指令解码后被发送到 CPU 内部拟定缓存行列中
  3. 乱序发射: 没有逻辑相关性的微指令都会被排入发射行列的待发射行列中,一旦下游处理单元空闲就发过去一条微指令去真实的核算 比如:int a = 0; int a++; int b = a+2; int c = 3+1; b 在逻辑上依靠 a,c 不依靠他人,所以 a、c 的核算都会进入待发射行列等候履行,b 只要等候前面的 a 核算完结才会进入待发射行列
  4. 履行单元: 这儿处理每一个伪指令,a++ 便是在这儿真实核算的,每个 CPU 都有至少 10 几个 履行单元,相同类型的履行单元都是复数,都有多个,并行履行。履行单元需求的微指令由上一步乱序履行待发射行列传送过来
  5. 重命名行列: 咱们代码是按次序写的,那么终究怎样保证成果也是次序正确的,这一步便是做的这个事。咱们写的一条代码终究解析成多条微指令在 CPU 中履行,那么上一步履行单元核算完的成果会先保留在 一个专门的行列中,当着一条代码解析出来的一切微指令悉数履行完结,再综合出一个成果,然后这一条指令才算完结,适当于数据库中的业务。解码出的微指令是一条一条进入不同的处理单元的,可是改写核算成果时是打包还原成一条完整的指令写回内存、缓存的

上面我对 CPU 流水线的描绘并不是十分正式,是我漫笔简略写的,意图便于我们有个开始理解

CPU 流水线大约基本便是这样,咱们回到 volatile 的问题,cpu 指令集针对要在 乱序履行中 保持 次序履行的特性,供给了 内存屏障,有多条不同类型,成组的内存屏障指令,高于言语的编译器在 看见 volatile 润饰的数据时,会根据自身言语的特性和 CPU 渠道,挑选不同的内存屏障组指令 在 内存屏障指令之后的 r/w/rw 操作都必须等内存屏障指令前面的履行完结才干进入待发射行列,用内存屏障指令给 volatile 之后的操作人为加上了一个逻辑相关性

然后你写一个 volatile 就能实现可见性了。为啥,volatile 之后的操作即便在 cpu 内部解码完结了,也得在 乱序履行单元的缓存中等候 volatile 加的内存屏障指令之前的代码都履行完,这儿说的代码可是逻辑上的代码。你想 整个 CPU 都停下来等了,MESI 协议自然有充足的时刻去完结自己的任务。完结了 volatile 句子在 重命名行列 中完结弹出行列了,后边的操作才干履行 这个价值便是整个 CPU 中止,等… 时刻本钱适当高,对 CPU 效率响应巨大,能直接把 cpu 性能瞬间拉低到 1% 的程度

所以有句话,volatile 能不必就不必,一个是因为容易出问题,一个是性能太低了

cpu 运转逻辑要是有爱好能够联系我要书单:这块的书都很贵的,最贵的一本 180(;¬_¬)