点击查看【bilibili】

计算机运算速度进步巨大,从早期 1 秒 1 次运算,到现在有千赫甚至兆赫的CPU。

早期计算机提速方式

早期,通过减少晶体管的切换时间,来提升 CPU 速度。

  • 晶体管组成了逻辑门,ALU 以及前几集的其他组件
  • 碰到了瓶颈

提升 CPU 性能的新技术

提升 CPU 性能,不但让简单指令运行更快,也让它能进行更复杂的运算。

专门电路处理复杂操作(复杂度 vs 速度的平衡)

  • 现代 CPU 直接在硬件层面设计了除法,可以直接给 ALU 除法指令
    • 缺点:让 ALU 更大也更复杂一些
    • 优点:但是运算速度更快(用一连串减法代替除法的操作要多个时钟周期,很低效)
  • 现代处理器有专门电路来处理图形操作, 游戏、解码压缩视频, 加密文档 等等
    • 优点速度快,而如果用标准操作来实现,要很多个时钟周期
    • 缺点:指令不断增加,人们一旦习惯了它的便利就很难删掉,所以为了兼容旧指令集,指令数量越来越多
      • 英特尔 4004,第一个集成CPU,有 46 条指令
      • 但现代处理器有上千条指令,有各种巧妙复杂的电路

缓存 Cache

问题引入:超高的时钟速度带来另一个问题,如何快速传递数据给 CPU? ——给 CPU 加缓存

缓存的作用

  • 提高数据存取速度,更快喂给 CPU
  • 解决CPU运算速率与内存读写速率不匹配的矛盾

    • 一条”从内存读数据”的指令可能要多个时钟周期,使得 CPU 空等数据,造成延迟

      缓存的容量

  • 处理器里空间不大,所以缓存一般只有 KB 或 MB

    • 缓存保证高速率,内存负责较大的容量

      缓存工作的原则

  • 缓存工作的原则,就是“引用的局部性”,这可以分为时间局部性和空间局部性

    • CPU 从 RAM 拿数据时, RAM 不只传一个,可以传一批,虽然花的时间久一点,但数据可以存在缓存加快之后的访问速度。
    • 以 计算餐馆销售额 为例:
      • 算餐厅的当日收入,先取 RAM 地址 100 的交易额。
      • RAM 与其只给 1 个值,不如直接把地址 100 到 200 的一批值都复制到缓存
      • 当处理器要下一个交易额时,交易额原本存储在 RAM 地址 100,但现在已经存储在缓存中,就不需要去 RAM 中取了
      • 缓存离 CPU 近, 一个时钟周期就能给数据;而去 RAM 读取数据可能要多个时钟周期
      • 因此,从缓存中读取数据,比反复去 RAM 拿数据快得多,让 CPU 不用空等
  • 如果想要的数据已经在缓存,叫 缓存命中
  • 如果想要的数据不在缓存,叫 缓存未命中
  • 缓存也可以当临时空间一些中间值,适合长/复杂的运算
    • 以 计算餐馆销售额 为例:
      • 假设 CPU 算完了一天的销售额,想把结果存到 RAM 地址 150
      • 但是现在先不让它存到 RAM 里,而是存在缓存,这样不但存起来快一些,后续运算取值也更快
    • 问题:缓存和 RAM 不一致
      • 解决办法:脏位 Dirty bi**t**
      • 脏位用来记录缓存和 RAM 的不一致
      • 当缓存满了,而 CPU 又要从 RAM 读取新的数据放入缓存,就要先进行同步
      • 同步时,检查脏位,如果是”脏”的, 在加载新内容之前, 会把数据写回 RAM

指令流水线

并行处理 parallelize

假设指令执行分为 3 个阶段:取指 → 解码 → 执行。

  • 若按序处理:

image.png

  • 并行处理:

image.png
可以看到,使用并行处理,每个阶段利用 CPU 的不同部分,不同任务重叠进行,同时用上 CPU 里不同部分。
这样的流水线,使得指令吞吐量 x 3

但,并行处理,也带来了两个主要问题:

问题一:指令之间的依赖关系——>乱序执行

eg. 第二条指令读某个数据,而并行正在执行的第一条指令会改这个数据,那并行执行第二条指令的话,这个数据还没被改,也就是说拿的是旧数据。
因此流水线处理器 要先弄清数据依赖性,必要时停止流水线,避免出问题。

解决方案:乱序执行 out-of-order execution

  • 定义:高端 CPU,比如笔记本和手机里那种,会更进一步,动态排序 有依赖关系的指令,最小化流水线的停工时间,即乱序执行
  • 缺点:这种电路非常复杂
  • 优点:流水线非常高效,几乎所有现代处理器都实现了流水线

问题二:条件跳转——>推测执行 & 分支预测

条件跳转指令指令会改变程序的执行流。

解决方案

  • 简单的流水线处理器,看到 JUMP 指令会停一会儿,等待条件值确定下来,再继续流水线。
    • 缺点:造成延迟
  • 推测执行 speculative execution
    • 定义:可以把 JUMP 想成是 “岔路口”,高端 CPU 会猜哪条路的可能性大一些,然后提前把指令放进流水线,这叫 “推测执行”
  • 分支预测 branch prediction
    • 定义:推测执行如果如果 CPU 猜错了,就要清空流水线。为了尽可能减少清空流水线的次数,CPU 厂商开发了复杂的方法,来猜测哪条分支更有可能,叫”分支预测”
    • 现代 CPU 的正确率超过 90%

优化 1 个指令流的吞吐量

超标量处理器

如果只有一个单核 CPU ,且 CPU 中各个部件(例如 ALU、缓存等)只有一套,则使用流水线时,理想情况下,一个时钟周期完成 1 个指令。
超标量处理器,使得一个时钟周期完成多个指令。

工作原理
即便有流水线设计,在指令执行阶段,处理器里有些区域还是可能会空闲。比如,执行一个 “从内存取值” 指令期间,ALU 会闲置。所以一次性处理多条指令(取指令+解码) 会更好,如果多条指令要 ALU 的不同部分,就多条同时执行。

多个相同电路/部件(eg. ALU)

超标量处理其更进一步,加多几个相同的电路执行出现频次很高的指令,eg. 很多 CPU 有四个, 八个甚至更多 完全相同的 ALU ,可以同时执行多个数学运算。

同时运行多个指令流

多核 CPU

一个 CPU 芯片里,有多个独立处理单元。
它们整合紧密,可以共享一些资源,比如缓存,使得多核可以合作运算。

多个独立 CPU

多核不够时,可以用多个 CPU,提升性能。

超级计算机

如果要做怪兽级运算,比如模拟宇宙形成,你需要强大的计算能力,给普通台式机加几个 CPU 没什么用。需要成千上万个 CPU !

神威·太湖之光有 40960 个CPU,每个 CPU 有 256 个核心,总共超过1千万个核心,每个核心的频率是 1.45GHz,每秒可以进行 9.3 亿亿次浮点数运算,也叫 每秒浮点运算次数 (FLOPS)。