计算机组成原理

学习《深入浅出计算机组成原理》课程后总结

1. 冯·诺依曼体系

计算机基于“冯·诺依曼体系”进行构建,主要由5部分组成,分别为:

  1. 控制器
  2. 逻辑单元(ALU)
  3. 存储器
  4. 输入
  5. 输出

2. 中央处理器 CPU

冯·诺依曼体系 出发,控制器和算术逻辑单元组成初步的中央处理器。控制器控制着指令的读取、加载以及计数器自增,而算术逻辑单元负责指令的执行。

2.1 时钟周期

CPU 主频由晶振控制,如 i5-4590 主频为3.30GHz,则表示晶振 1s 可以震荡 3.30x10^6 次,频率越高,CPU 1秒内执行的次数越多,性能越好。
我们通过下面的公式来衡量 CPU 的性能:

程序的 CPU 执行时间 = 指令数×CPI×Clock Cycle Time

从公式上看,简单的提供 CPU 性能方式是提高主频,同时在 CPU 上放更多的晶体管,让 CPU 变得更快,能够处理更多的事务。但 CPU 主频不能无限提高,在 CPU 有限的空间里,为了让 CPU 更快,放置开关控制电路越多,晶体管越多,提升主频,让晶体管的“开”“关”更快,由此带来更大的耗电和发热。

CPU 功率可以用下面的公式来表示:

功耗 ~= 1/2 ×负载电容×电压的平方×开关频率×晶体管数量

在开关频率和晶体管增加的情况下,为了降低功耗,最优解法是减低电压,由于电压是平方级别降低,所减小的功耗相当可观,这也是笔记本电脑通常使用低压 CPU 的原因。不过电压也不能无限减低,因为过低电压可能导致晶体管无法正常工作,从而导致 CPU 无法使用。

提高晶体管数量另一个方式,使用更高级的制芯工艺,如 5nm、7nm,这样可以在同样空间里放入更多的晶体管。

2.2 指令周期、CPU 周期(机器周期)

那么,一条指令的完整执行,称之为指令周期,包括fetch-decode-excute-memory-writeback,CPU 内部不断循环执行前三个步骤,在 CPU 之外,指令执行完毕之后,需要访问内存,将数据写回主内存,由这五部分组成一个完整的 指令周期
一条指令的执行,需要先从内存中读取,而 CPU 从内存中读取一条指令的最短时间,我们称之为CPU 周期,一个完整的指令周期,至少包括指令的读取和指令的执行,即一个指令周期至少需要两个 CPU 周期,复杂的指令则需要更多的 CPU 周期。

2.3 程序的性能

程序性能 = 指令数 × CPI × 时钟周期

单指令周期处理器
我们希望一整条指令的执行在一个时钟周期内完成,这样我们一个时钟周期可以执行一条指令,CPI 也为1,看起来比执行一条指令需要多个时钟周期好,采取这种思路的处理器,称为“单指令周期处理器”。
由于时钟周期固定,但指令的电路复杂程度不同,所以实际上一条指令执行时间是不同的。为了保证所有指令都在一个时钟周期内完成,那么最合适的时钟周期为执行时间最长的指令,其他短执行时间的指令在执行完毕之后也需要空转等待时钟周期结束再执行下一条指令。

为了一步提升指令处理效率,引入了“指令流水线”。

2.4 指令流水线

为了解决单指令周期过长问题,引入流水线,将指令周期分割为多个流水阶段(stage),实现各个阶段可以运行在不同的时钟周期中。

将一条指令拆分为多个步骤,同时每一阶段的电路在完成对应的任务之后,可以直接执行下一条指令的对应阶段。

注意:
流水线设计不宜过深。理论上流水线更长,可以提高 CPU 频率,让 CPU 处理流水阶段更短,从而提高 CPU 效率。但是部分指令执行时间很短,而过长流水线使得即使是短指令也需要浪费时间在空阶段(NOP)流水寄存器上,导致实际效率降低 。
同时,提高 CPU 频率,使电路更加复杂,晶体管数量增多,带来了更高的发热与功耗。

2.4.1 流水线概念及设计

如果把一个指令拆分为“取指令-指令译码-执行指令”,那么它是三级的流水线;如果进一步拆分,把“执行指令”分为“指令执行-内存访问-数据写回”,那么它就是一个五级的流水线。

五级的流水线,表示在同一个时钟周期里面,可以同时运行五条指令的不同阶段。虽然对于一条指令执行时间变成了5个时钟周期,但是我们可以把CPU 主频提得更高,是单位时钟周期更小。我们不需要确保最复杂的那条指令在时钟周期里面执行完成,而只要保障一个最复杂的流水线级的操作,在一个时钟周期内完成就好了。

如果一个操作步骤的时间太长,那么我们把这个步骤拆分为更多的步骤,让所有的步骤需要执行的时间尽量都差不多。现代 ARM 或者 Intel 的 CPU 流水线计数都已经到了 14 级。

2.4.2 超长流水线瓶颈

虽然流水线可以增加吞吐率,但是流水线级数过深反而会增加性能成本。

  1. 性能开销
    流水线同步时钟周期,不再是指令级别,而是流水线阶段级别。每一级流水线输出都要放入流水线寄存器中,在下一时钟周期交给下一级流水线处理,每级流水线寄存器处理大约需要 20 皮秒。过深的流水线,即使后面无需操作的阶段,也需要把时间消耗在流水线寄存器上,导致开销增大。参考奔腾4深流水线,高频率的失败。
  2. 功耗增加
    流水线深度提升,必须提高主频,才能保持与之前 CPU 同样的性能。同时流水线深度增加,需要更多的晶体管,两者都让 CPU 功耗增加,使得耗电和散热都成为大问题。

2.4.3 CPU 流水线设计

  1. 结构冒险
    仍使用冯·诺依曼体系结构

    • 参考“哈佛架构”,增加指令缓存、数据缓存,解决资源冲突问题(从“硬件层面”解决问题)
    • 插入 NOP (停顿/冒泡)
  2. 数据冒险

    • 依赖关系

      1. 数据依赖 –先写后读
      2. 反依赖 –先读后写
      3. 输出依赖 –先写再写
    • NOP 操作和指令对齐
      不需操作的 stage 运行一次 NOP,一定不和前一条指令的相同 stage 在同一时钟周期,这样保证前后两指令不在同一时钟周期重叠产生竞争,产生结构冒险。

      NOP 对齐,有可能插入过多的 NOP 导致 CPU 空转,所以有了下面的操作数前推:

    • 操作数前推(Operand Forwarding)
      或者叫“操作数旁路”(Operand Bypassing)
      前一指令与后指令有依赖关系,前指令执行结果直接传入下一指令中运行,跳过后面的写入内存操作。该操作更像是将结果转发到下一指令。

    • 乱序执行

  3. 控制冒险

    • 硬件加速
      将条件判断、地址跳转提前到译码阶段,而不是在指令执行阶段

    • 分支预测

      • 静态分支预测
        假装分支不发生
      • 动态分支预测
        根据之前条件跳转比较结果预测
        • 一级分支预测/1 比特饱和计数
        • 双模态预测器/2 比特饱和计数

2.4.4 提升 CPU 吞吐率

  1. SuperScalar 超量发射
  2. VLIW 超长指令字

2.4.5 CPU 指令集

  1. CISC (Complex Instruction Set Comptuing) 复杂指令集
  2. RISC(Reduced Instruction Set Comptuing) 精简指令集
  3. RISC-V 开源指令集

2.5 图像处理芯片 GPU

假设显示器分辨率为 640*480,那么有 30 万个像素,每秒 60 帧渲染,那么每秒需要 1800 万次单像素渲染。
从栅格化开始,有3个流水线步骤,即使每个步骤只有一个指令,也需要 5400 万条指令。

所以依靠 CPU 是无法完成这个工作。因为图形渲染有固定流程,所以直接用硬件来处理这部分内容,由于计算流程固定,所以也不需要流水线停顿、乱序等导致 CPU 计算变复杂问题,使得硬件制造相对简单便宜。

图形渲染流程:图形流水线

顶点处理 – 图元处理 – 栅格处理 – 片段处理 –像素操作

  1. 顶点处理 ->> 三维转二维
  2. 图元处理 ->> 点连成图形形状
  3. 栅格处理 ->> 将图形形状转换为小格
  4. 片段处理 ->> 对栅格进行处理,色彩处理
  5. 像素操作 ->> 将图像片段渲染至屏

2.6 特殊用途的处理器

  1. FPGA(Field-Programmable Gate Array)现场可编程门阵列
    可通过代码编辑,使之完成特定的电路功能。芯片开发
  2. ASIC(Application-Specific Integrated Circuit) 专用集成电路
    为专门用的场景设计的芯片。如摄像头芯片、录音笔芯片等,单独处理一种场景。
  3. 特别的 ASIC – TPU
    深度训练处理芯片

3. 存储器

3.1 存储设备类型

  1. SRAM(static random-access memory)
    静态随机存取存储器,掉电数据小时,使用在 CPU 内存
  2. DRAM(dynamic random acces memory)
    动态随机存取存储器。密度高,容量大,相对 SRAM 便宜,需要定时刷新充电,保持数据。电脑运行内存(内存条)
  3. SSD(solid-static drive)HDD(hard disk drive)
    硬盘,外部存储介质,容量更大,更便宜

3.2 数据访问优化

  1. 局部性原理

    1. 时间局部性
      如果一个数据被访问了,那么它在短时间内还会被再次访问。
    2. 空间局部性
      如果一个数据被访问了,那么和它相邻的数据也很快会被访问。
  2. 缓存算法
    LRU(Least Recently Used)

  3. 根据需要选择合适程序架构,以及合适的存储介质
    广告推荐系统(DMP)举例,详细查阅 52章《MongoDB并不是什么灵丹妙药.pdf》

    • 数据管道:大量数据,顺序读写,响应时间不要求
      Kafka,HDD
    • 数据仓库:读多场景,超大数据,长时间存储
      Arvo/Hive,HDD
    • KV数据库:随机读写,响应高
      AeriSpike ,SSD

4. 输入设备

4.1 总线

  1. 双独立总线
    1. 本地总线(后端总线)
      连接 CPU 和内部高速缓存
    2. 前端总线
      连接 CPU 和主内存
  2. 另一种设计:三种线路和多总线架构
    在 CPU 和主内存中间接入北桥芯片,一分为二
    1. 系统总线:CPU 和北桥芯片连接
    2. 内存总线:主内存和北桥芯片连接
    3. I/O总线:北桥芯片和I/O总线连接
      事实上,真实的计算机总线分更细,根据不同设备还会分成独立的 PCI 总线、ISA 总线等

4.2 信号和地址:发挥总线的价值

  1. I/O 设备挂载在总线,两者使用映射的内存地址:内存映射IO(Memory-Mapped I/O)简称MMIO
  2. 还有通过端口通信,端口映射(Port-Mapped I/O)简称 PMIO,或者叫独立输入输出(Isolated I/O)

5. 输出设备

显示器