4-1. 计算机系统结构(笔记)
Course:电子科技大学 - 计算机系统结构
Textbook:《计算机组成与设计:硬件/软件接口第四版》- David A.Patterson,《计算机体系结构:量化研究方法第五版》- John L. Hennessy
ISBN:9787111353058, 9787115297655
第一章 计算机概要与技术
1.1. 引言
1.1.1. 计算机硬件&操作系统发展史
第一代(1945 ~ 1955):真空管(电子管)和穿孔卡片
第二代(1955 ~ 1965):晶体管和批处理系统
第三代(1965 ~ 1980):集成电路和多道程序设计
第四代(1980 ~ 至今):个人计算机
第五代(1990 ~ 至今):移动计算机
1.1.2. 冯诺依曼体系结构
数学家冯·诺依曼提出了计算机制造的三个基本原则,这些原则统称为冯·诺依曼体系结构:
- 采用二进制代码表示程序和数据
- 计算机由五个部分组成:运算器、控制器、存储器、输入设备、输出设备
- 计算机采用存储程序的工作方式,即将程序像数据一样存储在存储器中
1.1.3. 哈弗体系结构
与冯诺依曼体系结构不同,哈弗结构是一种将指令存储和数据存储分开的存储器结构。具体来说:
- 整体上看也使用存储程序的工作方式,但程序存储器与数据存储器互相独立
- 将计算机看作三大部件的组成:CPU、程序存储器(存储程序,有独立的指令存储区和指令总线)、数据存储器(存储数据,有独立的数据存储区和数据总线)
相比之下,冯诺依曼体系结构的实现简单,而哈弗体系结构为了提高数据处理速度,将指令和数据分开存储,这带来了实现上的复杂性。
1.2. 现代计算机分类
按照指令流和数据流的数量进行分类:
- 单指令流单数据流(SISD):单处理器,可看做顺序的计算机
- 单指令流多数据流(SIMD):同一个指令由多个使用不同数据集的处理器执行,实现了数据级并行
- 多指令流单数据流(MISD):到目前为止,还没有这种类型的商用多处理器
- 多指令流多数据流(MIMD):每个处理器都可以执行自己的指令集,操作自己的数据集,实现了任务级并行
主流计算机类别及特性:
特征 | 个人移动设备 | 台式机 | 服务器 | 集群/仓库级计算机 | 嵌入式 |
---|---|---|---|---|---|
系统价格 | \$100 ~ $1000 | \$300 ~ $25,000 | \$5000 ~ $10,000,000 | \$100,000 ~ $200,000,000 | \$10 ~ $100,000 |
微处理器价格/per proc | \$10 ~ $100 | \$50 ~ $500 | \$200 ~ $2,000 | \$50 ~ $250 | \$0.01 ~ $100 |
关键系统设计 | 成本、功耗、多媒体性能、响应速度 | 性价比、图形性能、能耗 | 可靠性、可扩展性、吞吐量 | 性价比、吞吐量、能耗、均衡性 | 价格、能耗、应用特有性能 |
1.3. 计算机体系结构定义
计算机的实现包括两个方面:组成和硬件
- 组成:包含了计算机设计的高阶内容,如:存储器系统、存储器相连、设计 CPU(算术、逻辑、分支、数据传输等),有时候也用 “微体系结构” 来代替 “组成”
- 硬件:指一个计算机的具体实现,包括详细逻辑设计和封装技术。
在满足功能性需求和非功能性需求(价格、功耗、性能等)的条件下,计算机体系结构涵盖计算机设计的三个方面:
- 指令集体系结构
- 组成
- 硬件
1.4. 技术趋势
集成电路逻辑技术
- 晶体管密度每年增加大约 35%,差不多每四年翻两番
- 晶片大小每年增长 10% ~ 20%
- 综上,每个芯片的晶体管数目每年增加 40% ~ 55%,大约 18 ~ 24 个月翻番(摩尔定律)
半导体 DRAM
- 单个 DRAM 芯片的容量每年增加 25% ~ 40%
- 目前 DRAM 存在容量壁垒,容量增长速度也在放缓,因为制造更小型的 DRAM 存储单元难度更大
半导体闪存
个人移动设备的标准存储器件,如手机、数码相机、游戏机等移动设备的外存,固态硬盘 SSD 等。
磁盘技术
- 如今(2004 以后)磁盘密度每年提高大约 30%
- 硬盘技术是服务器和仓库寄存储的核心技术
网络技术
- 网络性能取决于交换机性能和传输系统的性能
- 传输系统用了 5 年左右,从百兆网逐渐升级到了千兆网
1.5. 集成电路的功耗趋势
功率:单位时间的能耗,1瓦 = 1焦/秒,
能耗:功率与时间的乘积,1度 = 1千瓦时 = 1000焦 * 3600秒 = 3600000焦
1.6. 成本趋势
1.7. 可靠性
可靠性:广义上指可靠性、安全性和可用性
计算机系统的可靠性:用于表示系统提供给用户服务的质量,这里 “可靠性(Dependability)” 可用 “信任(Reliance)” 代替
模块可靠性:从模块可用到出现故障的持续服务度量
- MTTF:平均无故障时间
- MTTR:平均修复时间,产品由故障状态转为工作状态时修理时间的平均值
- FIT:故障率,等于 (1/MTTF)
- MTBF:平均故障间隔时间,等于 (MTTF + MTTR)
- 模块可用性:等于 (MTTF / MTBF)
提高可靠性的方法:冗余(Redundancy)
- 时间冗余:重复操作直到无错
- 资源冗余:配置另外的相同部件,有错时用于替代出错部件
1.8. 性能的测量、报告和汇总
MIPS(Million Instructions Per Second)
单字长定点指令平均执行速度,即每秒处理的百万级的机器语言指令数。这是衡量 CPU 速度的一个指标。例如:某 CPU 执行一条计算平方根的指令需要 100 个时钟周期,每个时钟周期 \(1 \mu s\),则该机器执行该指令的速度可记为 0.01 MIPS
CPU时间
执行某一任务在 CPU 的花费的时间,计算公式如下:
由此可以得到,改进性能的方向:
- 减少时钟周期数
- 增加时钟频率(等价于缩短时钟周期,即减少单条指令平均执行时间)
解:$\mbox{CPU时钟周期数}_A = \mbox{CPU时间}_A \times \mbox{时钟频率}_A = 10s \times 2GHz = 2 \times 10^{10} $
$\mbox{时钟频率}_B = \frac{\mbox{CPU时钟周期数}_B}{\mbox{CPU时间}_B} = \frac{1.2 \times 2 \times 10^{10}}{6s} = 4GHz $
CPI(Clock cycle per instruction)
表示执行每条指令所需的平均时钟周期数,是一个程序全部指令所用时钟周期数的平均值。
解:$\mbox{CPU时间}_A = \mbox{程序指令数}_A \times CPI_A \times \mbox{时钟周期}_A = x \times 2.0 \times 250ps = x \cdot 500ps $
$\mbox{CPU时间}_B = \mbox{程序指令数}_B \times CPI_B \times \mbox{时钟周期}_B = x \times 1.2 \times 500ps = x \cdot 600ps $
因为 $\mbox{CPU时间}_A < \mbox{CPU时间}_B $
所以计算机 A 更快
不同视角看影响程序性能的因素:
- ISA:指令数、CPI、时钟频率
- 编程语言:指令数、CPI
- 编译程序:指令数、CPI
- 算法:指令数、CPI
SPEC 比值
用基准计算机的执行时间和待评价计算机的执行时间共同衡量性能高低
1.9. 计算机设计的量化原则
并行性
改善计算机性能最重要的方法,按照不同层次可分为
- 线程级或任务级:使用多个处理器,GPU
- 指令级:流水线、超标量、OOO等
- 操作级:并行加法器、组相联缓存、功能部件流水线
局部性原理
程序会经常重复使用它们最近使用过的数据或指令,两种经典的局部性表现
- 最近访问过的内容很可能在短期内被再次访问
- 地址相邻的数据可能会在短期内用到
经常性事件
对设计进行权衡时,常见情形优于非常见情形。如果某一场景频繁出现,那么对其优化会产生更显著的效果,这也引出了著名的 Amdahl 定律。
Amdahl 定律
用于衡量改进计算机某一部分后所获得的性能增益
两个指标:
- 升级比例:原计算机计算时间中可升级部分所占的比例,如 60s 的程序中有 20s 可以升级,则升级比例为 \(\frac{20}{60}\)
- 升级加速比:某一部分升级前的执行时间,与升级前后的比值,如程序某一部分升级前需要 5s,升级后需要 2s,则升级加速比为 \(\frac{5}{2}\)
系统加速比公式:
解:$\mbox{升级比例} = \frac{\mbox{可升级部分执行时间}}{\mbox{总执行时间}} = 0.4 $
$\mbox{升级加速比} = \frac{\mbox{升级部分原执行时间}}{\mbox{升级部分升级后执行时间}} = \frac{10}{1} = 10 $
\(\mbox{总加速比} = \frac{1}{(1 - \mbox{升级比例}) + \frac{\mbox{升级比例}}{\mbox{升级加速比}}} = \frac{1}{(1 - 0.4) + \frac{0.4}{10}} \approx 1.56\)
1.10. 综合:性能、价格、功耗
第二章 指令系统
2.1. 简介
2.2. 指令集体系结构的分类
指令集体系结构按照处理器内部数据的存储类型不同,可以分为如下几种:
- 堆栈体系结构:操作数隐含地位于栈顶
- 累加器体系结构:累加器即为隐含的操作数
- 通用寄存器体系结构:明确指定操作数,要么是寄存器,要么是存储器地址
对于通用寄存器体系结构,显式操作数可能从存储器直接读取,也可能要加载到寄存器中再访问。按照访问方式不同,划分为以下几种:
- Register-Memory 体系结构:一般指令都可以访问存储器
- Register-Register 或 Load-Store 体系结构:只能通过 load 和 store 指令来访问存储器
- Memory-Memory:这是一种理论上的体系结构,实际应用中并不存在。它把所有的数据都保存在存储器中,数据使用时直接读取或写入存储器
通用寄存器体系结构出现的原因:
- 寄存器比存储器快,加速了程序运行,且由于地址比存储器地址的位数少,改善了代码密度
- 编译器使用寄存器更灵活,比使用其他存储形式效率更高。如堆栈体系结构限制了指令执行的顺序
- 寄存器用来存放变量,减少了总线上的数据流量
2.3. 存储器寻址
存储器地址表示
我们讨论的所有指令系统都是字节寻址的,都提供了字节(8bit)、半字(16bit)和字(32bit)寻址,大多数的计算机还提供了双字(64bit)寻址。
字节序问题
- 大端模式:数据的高字节保存在内存的低地址中,低字节保存在内存的高地址中
- 小端模式:数据的高字节保存在内存的高地址中,低字节保存在内存的低地址中
简答来说就是,大端模式符合人们的书写阅读习惯;而小端模式符合逻辑处理方式。考虑数字 305419896 = 0x12345678,以小端模式存储在计算机中,字节地址顺序向后依次是 0x78564321;以大端模式存储在计算机中,字节地址顺序向后依次是 0x12345678。
对齐问题
在许多计算机中,对大于 1 字节的数据进行寻址时都必须是对齐的。大小为 s 字节的数据,字节地址为 A,若满足 A mod s = 0,则该数据的寻址是对齐的。
字或双字整数倍对齐访问存储器,可以简化硬件实现的复杂性;再者,对齐的存储器访问效率更高,可以使程序运行的比非对齐方式更快。
寻址方式
给定地址后,就知道了去访问哪些字节。但如何给定地址呢?寻址方式描述的就这个问题,即体系结构如何指定要访问对象的地址。除了存储器,寻址方式还可以指定常量和寄存器。下图列出了近期计算机中用到的所有寻址方式。
2.4. 操作数大小和类别
如何指定操作数的类型:
- 最常用方法,通过在操作码中进行编码来指定
- 用硬件解释的字段标记数据,以表示数据类型,但这种不灵活的带标签的计算机已经成为历史
常见操作数类型:
- 字节:8bit
- 半字(短整数):16bit
- 字(整数):32bit
- 双字(长整数):64bit
- 浮点类型:单精度 32bit,双精度 64bit
通常定点数使用补码来表示,而字符型通常是 ASCII 编码格式,浮点数一般按照 IEEE 754 标准进行表示。
2.5. 指令系统的操作
大多数指令集体系结构支持的操作可以按照下表分类:
指令系统一条规律:使用最多的往往是一些固定的简单指令。一般所有的计算机都提供对基本功能支持的指令,但像后四类这些不常见指令的支持数量可能为0,也可能包含大量特殊指令。
2.6. 控制流指令
控制流指令寻址方式
控制流指令中的目标地址在任何情况下都要指定。在绝大多数情况下,这个地址是在指令中明确指定的(过程返回除外,因为编译阶段无法知道要返回的位置)。
- PC 相对寻址:指定一个相对位移量,其会被加到 PC 寄存器上实现跳转
- 寄存器间接寻址:给出包含目标地址的寄存器名称
对于PC 相对寻址,其跳转的位置通常并不远,所以需要的位数较少。另外 PC 相对寻址不受程序物理位置的影响,这一特性称为位置无关。而寄存器间接寻址则适用于编译时不知道目标位置的情况,如:调用返回,分支语句 switch-case,虚拟函数或抽象函数,高阶函数或函数指针,动态共享库。在执行跳转前把地址从存储器载入到寄存器。
过程调用中的寄存器保存
- 调用者保存:调用者调用其他过程时,必须保存在调用过程后还要使用的寄存器
- 被调用者保存:被调用的过程必须保存它要使用的寄存器
有时候,如果两个不同的过程都要访问相同的全局变量,则必须使用调用者保存方法。大多数实际使用的编译器会结合使用这两种方法。
2.7. 指令集编码
指令集编码
按照何种规则将指令转换为计算机执行的二进制形式。这不仅影响编译后的程序大小,也影响着处理器的实现。处理器必须能对其进行译码,快速找到操作类型和操作数。
指令集编码考虑的问题
- 允许尽可能多的寄存器和寻址方式
- 寄存器字段和寻址方式字段的大小,会影响平均指令大小及平均程序大小
- 编码后的指令长度应易于流水线处理
常见指令集编码
- 变长编码:允许对所有操作采取任意寻址方式,当存在多种操作和寻址方式时,此方案是最佳选择。生成的代码规模较短,因为不存在无用的位。译码复杂,不适合流水线
- 定长编码:通常所有指令大小都相同,操作和寻址方式较少时效果最好。生成的代码规模较大。译码简单,适合流水线
- 混合编码:减少过多的指令,以减轻多种结构的指令带来的工作负担,但仍提供多种指令长度以减少代码长度
下图展示了三种指令集编码的格式:
总结
- 关注代码量大小,选择变长编码
- 关注程序的执行性能,选择定长编码
- 折中可以选择混合编码
2.8. 编译器的角色
2.9. MIPS 系统结构
MIPS(Microprocessor without Interlocked Pipelined Stages,无内部互锁流水线级微处理器)架构是一种采取精简指令集(RISC)的处理器架构,最早由斯坦福大学研究。它基于一种定长编码的指令集,并采用 Load/Store 模型。在网关,机顶盒及其它嵌入式设备上非常受欢迎。最早的 MIPS 架构是 32 位,最新的版本已经变成 64 位,也就是本节的 MIPS 64。
关注问题
- 一种简单64位 Load/Store 系统结构
- 针对流水线效率的设计,包括定长指令集编码,译码简单
- 编译器编译的效率,更容易产生高效的目标代码
寄存器
- 32 个 64bit 的通用寄存器(GPR),名称为 R0,R1,…,R31,也称为寄存器
- 32个 64bit 的浮点寄存器(FPR),名称为 F0,F1, …,F31,既可以作为 32 个单精度寄存器来使用(一半不使用),也可以作为 32 个双精度寄存器来使用
- R0 的值永远置为 0
数据类型
- 整型:8bit 字节、16bit 半字、32bit 字、64bit 双字
- 浮点型:32bit 单精度、64bit 双精度
寻址方式
- 立即数寻址:直接在指令中放置 16 位的操作数,不需要按地址查找
- 基址寻址:存放在寄存器中的基地址,与相对该基址的一个 16 位移量相加获得。如:LW R2, 128(R3) => ((R3) + 128) -> R2
- 寄存器间接寻址:位移量置为 0
- 16 位绝对地址寻址:R0作为基址寄存器,因为 R0 恒为 0
MIPS 存储器使用 64 位地址进行字节寻址,即最终访问存储器时,需要给出一个 64 位的绝对地址,这个地址可以按照上面任一种寻址方式产生。存储器访问支持软件选择大端小端,涉及 GPR/FPR 的存储器访问,可以是字节、半字、字、双字/单精度、双精度,需要对齐访问。
指令格式
因为 MIPS 只有两种寻址方式,可以将它们编码到操作码中。为了便于流水线的实现,所有的指令长度都是 32 位的,其中前 6 位固定为基本操作码。指令可分为如下三种:
类型 | 格式(字段长度) | |||||
I型 | op(6) | rs(5) | rt(5) | immediate(16) | ||
R型 | op(6) | rs(5) | rt(5) | rd(5) | shift(5) | funct(6) |
J型 | op(6) | address(26) |
各个字段的含义:
-
I型
- op:操作码,决定功能,6bit
- rs:源操作数寄存器,5bit
- rt:目的操作数寄存器,存储运算结果,5bit
- immediate:立即数,16bit,计算时要扩展到 32bit,按功能有零扩展和符号扩展
-
R型
- op:固定为 000000
- rs:源操作数 1 寄存器,5bit
- rt:源操作数 2 寄存器,5bit
- rd:目的操作数寄存器,存储运算结果,5bit
- shift:位移量,读写专用寄存器或者移位操作指定移动次数,5bit
- funct:决定功能,6bit
-
J型
- op:操作码,决定功能,6bit
- address:立即数表示的转移地址,会作为偏移量加到 PC 上,26bit
操作分类
- Load-Store(除 R0 外所有 GPR 和 FPR 均可)
- ALU 运算
- 分支与跳转
- 浮点运算
指令举例:
R | ADD R1,R2,R3 | 加 | Regs[R1] $\leftarrow$ Regs[R2] + Regs[R3] |
SUB R1,R2,R3 | 减 | Regs[R1] $\leftarrow$ Regs[R2] - Regs[R3] | |
SUBU R1,R2,R3 | 减无符号数 | Regs[R1] $\leftarrow$ Regs[R2] - Regs[R3] | |
SLL R1,R2,5 | 字逻辑左移,立即数 | Regs[R1] $\leftarrow$ Regs[R2] << 5 | |
SLT R1,R2,R3 | 置小于 | if(Regs[R2] < Regs[R3]) then Regs[R1] $\leftarrow$ 1 else Regs[R1] $\leftarrow$ 0 | |
I | ADDI R1,R2,30 | 加立即数 | Regs[R1] $\leftarrow$ Regs[R2] + 30 |
SUBI R1,R2,30 | 减立即数 | Regs[R1] $\leftarrow$ Regs[R2] - 30 | |
LD R1,30(R2) | 载入双字 | Regs[R1] $\leftarrow_{64bit}$ Mem[30+Regs[R2]] | |
LD R1,30(R0) | 载入双字,无基址 | Regs[R1] $\leftarrow_{64bit}$ Mem[30+0] | |
LW R1,30(R2) | 载入字 | Regs[R1] $\leftarrow_{64bit}$ $(SE_{32bit})$ + Mem[30+Regs[R2]] | |
L.S F0,30(R3) | 载入单精度浮点数 | Regs[F0] $\leftarrow_{64bit}$ Mem[30+Regs[R3]] + $(ZE_{32bit})$ | |
L.D F0,30(R3) | 载入双精度浮点数 | Regs[F0] $\leftarrow_{64bit}$ Mem[30+Regs[R3]] | |
S.D R3,30(R4) | 存储双精度字 | Mem[30+Regs[R4]] $\leftarrow_{64bit}$ Regs[R3] | |
SB R2,30(R3) | 存储字节 | Mem[30+Regs[R3]] $\leftarrow_{8bit}$ $Regs[R2]_{56-63}$ | |
BEQ R1,R2,30 | 相等则跳转 | if (Regs[R1] == Regs[R2]) then PC = PC + 4 + 30 else PC += 4 | |
J | J name | 跳转 | $PC_{36-63} \leftarrow name$ |
JAL name | 跳转并链接,即保存返回地址 | Regs[R31] $\leftarrow$ PC + 4, $PC_{36-63} \leftarrow name$ | |
JALR R2 | 寄存器跳转并链接 | Regs[R31] $\leftarrow$ PC + 4, PC $\leftarrow$ Regs[R2] | |
JR R3 | 寄存器跳转 | PC $\leftarrow$ Regs[R3] | |
MOVZ R1,R2,R3 | 等于零时赋值 | if (Regs[R3] == 0) Regs[R1] $\leftarrow$ Regs[R2] |
其中:
- \(ZE_i\):零扩展:,用 0 进行高位填充,长度为 \(i\)
- \(SE_i\):符号扩展,用符号位进行高位填充,长度为 \(i\)
- 跳转指令 name:本身 26bit,左移两位后覆盖 PC 的低 28bit
第三章 单周期 MIPS 处理器
3.1 引言
决定一台计算机性能的三个关键因素
- 指令数目:编译器和指令集决定
- 时钟周期长度:处理器实现方式决定
- 平均每条指令所需的时钟周期数(CPI):处理器实现方式决定
第四章章节分类(9787111353058)
- 理解处理器及其性能:Ch 4.3、4.4、4.6
- 如何建立一个处理器:Ch 4.2、4.7、4.8、4.9
3.2 一个基本实现
指令集
- 存储器访问指令:取字(lw),存储字(sw)
- 算术逻辑指令:加法(add),减法(sub),与(and),或(or),小于则设置(slt)
- 分支指令:相等则分支(beq),调整(j)
实现方式概述
- 取指令:根据 PC 的值从指令存储器取出要执行的指令,然后 PC + 4
- 取操作数:根据指令中的操作数字段,选择读取 1 或 2 寄存器,或立即数送进 ALU
- 分析指令:将指令中的操作码送入控制器,分析指令功能,产生相应的物理信号
- 执行指令:ALU 根据控制器的控制信号完成指定的运算
多选器使用场景
- 控制 PC 写入的值,或是经加法器计算 PC + 4 后得到,或是分支目的地址(PC + 4 + offset)
- 选择目的寄存器,对于 R 型指令使用 rd,对于 I 型指令使用 rt。
- 选择写入寄存器堆的值,或是 ALU 的输出,或是存储器的载入
- 决定 ALU 的第二个操作数,或是来自寄存器堆,或是指令的偏移字段
ALUOP
指令 | 操作码 |
数据传输(lw、sw) | 00 |
分支(beq) | 01 |
R 型指令(add、sub) | 10 |
控制信号
控制信号名称 | 含义 | 值为 0 | 值为 1 |
RegWrite | 寄存器堆写信号 | 不写入寄存器 | 要写入寄存器 |
RegDst | 选择目的寄存器 | rt 作为目的寄存器 | rd 作为目的寄存器 |
M2Reg | 标识写入寄存器的数据来源 | 写入寄存器的内容来自 ALU | 写入寄存器的内容来自存储器 |
MemRead | 存储器读信号 | 无操作 | 存储器读有效 |
MemWrite | 存储器写信号 | 无操作 | 存储器写有效 |
ALUSrc | ALU 源操作数选择 | 来自寄存器堆的第二个输入 | 指令低 16bit 符号扩展 |
PCSrc | PC 源选择 | PC = PC + 4 | PC = 分支目标地址 |
3.2 逻辑设计惯例
下图所示的控制和数据通路,可以实现 add、sub、addi、subi、lw、sw、beq、j 指令的功能
lw
sw
add rd,rs,rt
beq r1,r2,offset
j name
3.3 中断及异常
中断
在运行过程中,如果发生某种随机事件,导致 CPU 暂停执行当前程序,转去执行为该随机事件的处理程序,处理完毕后再自动恢复原程序的执行。
中断的时机
- 中断的发生(任意性):即随机事件(外部 IO,内部故障)可能在任意时间点发生
- 中断的处理(完整性):当执行某条指令出现中断时,中断在指令执行过程中就可以被检测到,但会等到该指令执行完毕后(一个或者数个时钟周期),处理器才会跳转异常事件处理程序
中断与异常的区别
- 中断:属于系统的正常现象,系统暂停当前正在运行的程序,转向其它服务,可能是其优先级更高或者程序主动安排。这是 CPU 硬件支持的功能
- 异常:由软件错误引起的意料之外的情况,通常是开发过程中没有考虑到的程序错误
中断响应条件
- 当前发生的中断未被屏蔽
- CPU 处于开中断模式
- 中断源优先级比当前程序优先级更高
第四章 流水线 MIPS 处理器
4.1. 流水线概述
流水线技术
一种实现多条指令重叠执行的技术,通常包含多个流水段(Pipeline Stage,流水级、流水线),流水段之间并行使用系统中的不同组件,以最大化系统效率。
流水线带来的性能提高,是通过增加指令的吞吐率,而不是减少单条指令的执行时间实现的。实际应用程序通常由成千上万条指令,因此指令的吞吐率是一个很重要的参数。理想情况下(流水线各阶段操作平衡,指令数量很大),那么在流水线系统上的指令执行时间约为:
流水线分类
- 按照各过程段用时是否相等
- 均匀流水线:各过程段用时完全相等
- 非均匀流水线:各过程段用时不完全相等
- 按照处理的数据类型
- 标量流水处理机
- 向量流水处理机
- 按照流水线的规模
- 操作流水线:把处理机的算术逻辑部件分段,使得各种数据类型的操作都能流水线化,规模最小,粒度最细
- 指令流水线:把执行指令的过程流水线化,如取指、分析、执行分开
- 宏流水线:使用不同的处理器串行对数据流进行处理,每个处理器完成一项任务
- 按功能分类
- 单功能流水线:只能完成一种固定功能的流水线,如浮点加法器流水线、浮点乘法器流水线
- 多功能流水线:流水线各段可以进行不同的连接,实现不同功能
- 按流水线工作方式
- 静态流水线:在同一时间,多功能流水线的各段按照同一种功能的连接方式工作。通常只有输入是一串相同运算任务时,才能发挥流水线的效率。如同时支持加法和乘法的流水线,不能在同一时间既运行加法任务又运行乘法任务,即使使用流水线中的空闲部件也不行,需要等流水线中加法任务完毕后再执行乘法任务
- 动态流水线:在同一时间,多功能流水线的各段可以按照不同的连接方式,同时执行多种功能
- 按照连接方式
- 线性流水线:流水线各段串行连接,没有反馈回路
- 非线性流水线:流水线各段串行连接,但也有反馈回路,使得某些阶段可以重复执行
- 按照控制方式
- 顺序流水线
- 乱序流水线
- 线性流水线又可按照控制方式
- 同步流水线
- 异步流水线
流水线特点
- 流水线处理的最好是连续任务,只有连续不断的任务才能充分发挥流水线的效率
- 流水线依靠多个功能部件并行工作以缩短程序的总执行时间,实际上是把一个大的功能部件分解为多个子过程
- 流水线中的每一功能部件后面都要有一个缓冲寄存器(锁存器),以便缓和各个功能段延时时间的不一致
- 流水线中各段时间应尽量相等,避免段延时过长引起的相互等待
- 流水线需要有 “装入时间” 和 “排空时间”
4.2. 流水线时空图及性能分析
时空图
下图为各段时间均相等的流水线时空图:
下图为各段时间不等的流水线时空图:
吞吐率
在单位时间内流水线所完成的任务数量或输出结果的数量。假设指令数量为 \(n\),流水线完成所有任务需要的总时间为 \(TK\),吞吐率为 \(TP\),则:
- 若流水线各段时间相等(都是 \(\Delta t\)),假设流水线的级数为 \(k\),指令数量为 \(n\),根据上式则有:
- 若流水线各段时间不完全相等,则有:
加速比
流水线的加速比是完成某个任务顺序执行所用时间与流水线执行所用时间之比。假设不使用流水线(即顺序执行)所用的时间为 \(TS\),使用流水线后所用的时间为 \(TK\),则该流水线的加速比 \(S\) 为:
- 若流水线各段时间相等(都是 \(\Delta t\)),则有:
- 若流水线各段时间不完全相等,则有:
效率
指流水线的设备利用率。在时空图上,流水线的效率定义为 \(n\) 个任务占用的时空区与 \(k\) 个功能段总的时空区(可以理解为时空图面积)之比,因此流水线的效率包含时间和空间两个方面的因素。
4.4. 流水线中的冒险问题
流水线中存在这样一种问题,到达下一个时钟周期后,后续的指令却无法执行,这种情况称为冒险。导致冒险的原因有:
-
结构冒险:流水线中重叠执行的指令,存在硬件层面的资源竞争,比如访存和取指令并行执行
- 插入暂停周期:即让流水线在完成前一条指令对存储器的访问时,暂停取后一条指令(指令存储器)的操作
- 硬件冗余:设置相互独立的指令存储器和数据存储器或设置相互独立的指令Cache和数据Cache
- 预取指令技术:在重叠操作中,在前一条指令的执行过程中,就提前取出后面的指令进行相应处理
-
数据冒险:指令见存在着数据依赖关系
- 暂停流水线
- 使用专用数据通路:如转发/旁路技术,即在指令未完全结束时,提前将缺少的运算项交付给需要的指令
- 编译优化调度:静态调度,即编译程序通过调整指令的顺序,减少流水线的冲突
- 动态调度:用硬件方法在运行过程中调度指令的执行,以减少流水线冲突
-
控制冒险:通常发生在分支和跳转结构中,后续指令的地址依赖于当前正在执行指令的结果
- 阻塞:缺点是效率低
- 静态分支预测:即预测分支不发生,默认按照流水线方式顺序执行,如果最终发生了分支,则移除流水线中的指令,重新执行
- 动态分支预测:根据程序已执行的指令,进行动态预测,并根据历史预测记录调整当前预测结果,提高准确率
4.5. 记分牌算法
考虑如下指令序列:
LD F6, 34(R2)
LD F2, 45(R3)
MULT.D F0, F2, F4 # 乘法执行延迟:10 个时钟周期
SUB.D F8, F6, F2 # 加法执行延迟:2 个时钟周期
DIV.D F10, F0, F6 # 除法执行延迟:40 个时钟周期
ADD.D F6, F8, F2
画出执行过程中的记分牌(按照时钟周期):
4.6. Tomasulo 算法
第五章 存储器层次结构
第六章 I/O
第七章 多核、多处理器和集群
第八章 图形和 GPU 计算
拓展
1. 存储器
内存(Memory)又叫主存,即冯诺依曼体系结构中的存储器,是 CPU 用来直接寻址和存储的空间。它相当于一座桥梁,用以负责诸如硬盘、主板、显卡等硬件上的数据与处理器之间数据交换。我们可以把内存看作一个高速的数据缓存区,外存上的软件/数据要调入内存,才能让 CPU 执行/使用,因为 CPU 和内存的数据交换速度远高于外存。
内存分为随机存取存储器(Random Access Memory,RAM)和只读存储器(Read-Only Memory,ROM)两种。RAM 可以理解为主存,而 ROM 在计算机中所占比重很小,如 BIOS 程序(个人电脑启动时加载的第一个程序)通常固化在一个特定的 ROM 芯片上。
1.1. RAM
RAM 可以随时读写(刷新时除外),而且速度很快,通常作为操作系统或其他正在运行中的程序的临时数据存储介质。它与 ROM 的最大区别是数据的易失性,即一旦断电所存储的数据将随之丢失。RAM在计算机和数字系统中用来暂时存储程序、数据和中间结果。具有静电敏感性(静电会干扰存储器内电容器的电荷,引致数据流失,所以更换内存条前需要释放静电)。
所谓 “随机存取”,指的是当存储器中的数据被读取或写入时,所需要的时间与这段信息所在的位置或所写入的位置无关。只要知道地址,即可在 O(1) 时间复杂度内完成读写。相对的,读取或写入顺序访问存储设备(如磁带、磁盘等)中的信息时,其所需要的时间与位置就会有关系(需要执行机械操作,即先将磁带或者磁盘磁头移动到指定位置)。
SRAM 和 DRAM:二者都是 RAM 的一种,静态随机存取存储器(Static Random-Access Memory,SRAM)中所谓的 “静态”,是指这种存储器只要保持通电,里面储存的数据就可以长期保持。相比之下,动态随机存取存储器(Dynamic Random Access Memory,DRAM)中所储存的数据则需要周期性地更新,否则即使持续通电数据也有可能丢失。但不论 SRAM 还是 DRAM,二者在断电后数据均会丢失,也就是都满足 RAM 的易失性。此外,SRAM 有它的缺点,即它的集成度较低,功耗较 DRAM 大 ,相同容量的 DRAM 内存可以设计为较小的体积,但是 SRAM 却需要很大的体积。同样面积的硅片可以做出更大容量的 DRAM,因此 SRAM 显得更贵。
1.2. ROM
ROM 是一种在正常工作时其存储的数据固定不变,其中的数据只能读出,不能写入,即使断电也能够保留数据。要想在只读存储器中存入或改变数据,必须具备特定的条件。常见 ROM 类型如下:
- 掩膜ROM(专用掩膜板)
- PROM(可一次性编程 ROM)
- EPROM(紫外线擦除可改写 ROM)
- EEROM(电擦除可改写 ROM)
- Flash ROM(快闪 ROM)
1.3. FLASH(闪存)
闪存是属于内存器件的一种,是一种非易失性( Non-Volatile )内存,在没有电流供应的条件下也能够长久地保持数据,其存储特性相当于硬盘,这项特性正是闪存得以成为各类便携型数字设备的存储介质的基础。
Flash是非挥发性随机存取存储器(NVRAM),它可以作为缓存或作为直接存储的底层设备。虽然比动态随机存储器(DRAM)慢10倍,但尽管这样,它还比硬盘快得多。它的速度和耐用性,让写操作变得比直接写硬盘快很多。将FLASH作为一个持续的高速缓存,再让它慢慢的写回磁盘作永久数据保存。
NAND Flash 的读写以 Page 为单位,在写入前(在这里称之为编程),需要先擦除,擦除以 Block 为单位,这些操作都会减少器件的寿命。由于 NAND Flash 的这种特性,使得它在编程时带来了写放大的副作用,并且管理算法更复杂,例如需要垃圾回收算法。所以一般我们对 NAND Flash 编程的步骤是,先把其中的有效数据 Page 搬移到内存或者其他 Block 中,然后擦除这个 Block,再把有效数据和新数据写回去。这个过程造成了多余的写入和擦除,这就是所谓的写放大。
NAND Flash 一般不单独使用,需要和专用控制器搭配组成一个系统。目前常见的使用 NAND Flash 的产品主要有固态硬盘,eMMC,SD卡和U盘等。其中 SSD 和eMMC 稳定性和性能要求比较高,一般需要使用品质优良的 NAND Flash。