计算机组成原理1:概述
1 计算机体系结构知识图谱
2 冯·诺依曼架构
图1 以运算为中心的冯·诺依曼架构
冯·诺依曼架构的主要思想为:
1. 计算机应由运算器、控制器、存储器、输入设备和输出设备五个基本部件组成。各基本部件的功能是:存储器不仅能存放数据,而且也能存放指令,形式上两者没有区别,但计算机应能区分数据还是指令;控制器应能自动取出指令来执行;运算器应能进行加、减、乘、除四种基本算术运算,并且也能进行一些逻辑运算和附加运算;操作人员可以通过输入设备、输出设备和主机进行通信;
2. 内部以二进制表示指令和数据。每条指令由操作码和地址码两部分组成。操作码指出操作类型,地址码指出操作数的地址。由一串指令组成程序;
3. 采用"存储程序"工作方式。
随着通信网络、云计算、大数据的发展,计算机的架构有一个以运算为中心向以数据为中心发展的趋势。
图2 以数据为中心的冯·诺依曼架构
3 计算机体系结构发展史
1945年冯·诺依曼架构开始流行,第一台通用电子计算机诞生于1946年,此后70几年来计算机的性能遵循摩尔定律飞速发展。
图3 CPU性能变化趋势
指数级的性能提升主要得益于两个方面:计算机制造技术的发展和计算机系统结构的创新。图4列出了计算机技术的迭代,其中IBM的贡献非常耀眼。主要可以概括为:新的制造技术和体系结构创新、大规模集成电路和微处理器应用、RISC结构出现以及并行化技术。
图4 计算机体系结构的迭代
而从软硬件生态的维度看计算机的发展史,还经历了三次变革。- 统一的指令集架构ISA,经典的 Intel 8080,程序员可以通过 assembly language 对计算机进行编程,当需要加入新的指令特性的时候,Intel 就会在它的指令集里面新增,CISC就是这么玩的。
- 解放程序员的生产力,计算机的设计也从原来的面向汇编语言友好的设计思路,转化成面向编译器友好的设计思路,C语言、RISC架构由此诞生。
- 高级编程语言再次抽象,go语言,MATLAB,python的诞生。
4 指令集
指令集:计算机的全部指令称为该计算机的指令集(instruction set)。指令集架构ISA(Instruction Set Architecture)决定了计算机的结构,实现软件兼容、通用、标准化,同时ISA是一种规约(Specification),它规定了如何使用硬件。
1. 可执行指令的集合,包括指令格式、操作种类以及每种操作对应的操作数的规定;
2. 指令可以接受的操作数的类型;
3. 操作数所能存放的寄存器组的结构,包括每个寄存器的名称、编号、长度和用途;
4. 操作数所能存放的存储空间的大小和编址方式;
5. 操作数在存储空间存放时按照大端还是小端方式存放;
6. 指令获取操作数的方式,即寻址方式;
7. 指令执行过程的控制方式,包括程序计数器(PC)、条件码定义等。
现代计算机体系以指令集为中心,向上为软件开发,向下为硬件实现。设计符合“标准”的计算机硬件,同时构建统一ISA的软硬件生态,才能成为一台“通用计算机”。
图5 指令集架构体系
按照指令集架构分类,CPU市场格局如图6所示。整体来看,以高通骁龙,联发科,三星Exynos,苹果A系列为代表的ARM架构RISC处理器占据了移动处理器的市场。而在个人电脑领域以Wintel联盟为基础的X86架构CISC处理器占据了该市场。MIPS,Power,Alpha等架构虽然已经不是市场的主流,但在特定领域内仍然在被使用。
图6 CPU市场格局
## 5 计算机是如何工作的? 首先,给出一个计算机模拟网站,可以从寄存器级的视角观察计算机的内部运行。
http://www.buthowdoitknow.com/but_how_do_it_know_cpu_model.html
图7 CPU内部构造
根据冯诺依曼架构的计算机的程序存储执行的思想,指令和数据事先放在存储器中,指令由OP(操作码,这个指令是做什么的)、ADDR(地址,指出待处理的操作数的存储位置)字段组成,每条指令和数据都有各自的地址,指令按序存放,通过PC(program counter)按顺序加载处理。 > 程序执行步骤如下(以c=a+b为例):step1:根据PC取指令(add c,a,b)
step2:指令译码 (根据指令集解码出操作数、地址)
step3:取操作数,分配相应的功能单元(add)
step4:指令执行(调用add单元,计算a+b的结果放到寄存器)
step5:回写结果(将c结果写到存储器相应的地址)
step6:修改PC的值(PC+1, 准备下一次取指令)
程序员都是基于高级语言开发的,例如C, Python,那么如何得到上述计算机输入的指令呢?此时需要介绍指令集以上部分的内容。高级语言到机器语言的转换过程如下图所示:
图8 高级语言到指令的转换
1. 编译器(Complier):将C程序转换成机器能理解的符号形式的汇编语言程序(二进制)。
2. 汇编器(Assembler):是将汇编语言翻译为机器语言的程序。一般而言,汇编生成的是目标代码,需要经链接器(Linker)生成可执行代码才可以执行。
3. 链接器(Linker): 把各个独立汇编的机器语言程序组合起来并且解决所有未定义的标记,最后生成可执行文件。
4. 加载器(loader):把目标程序装载到内存中以准备运行的系统程序。
我们打开程序的汇编代码,第一列即为PC,第二列是机器码,第三列则为汇编代码。
00000000007abcb8 <ssl3_do_change_cipher_spec>:
7abcb8: a9bd7bfd stp x29, x30, [sp, #-48]!
7abcbc: 52800223 mov w3, #0x11 // #17
7abcc0: 52800421 mov w1, #0x21 // #33
7abcc4: 910003fd mov x29, sp
7abcc8: f9000bf3 str x19, [sp, #16]
7abccc: aa0003f3 mov x19, x0
7abcd0: f9405402 ldr x2, [x0, #168]
MIPS汇编和机器码的对照举例,高级语言实现的功能模块根据指令架构转换为汇编代码,进一步将汇编对应到指令字段,以16进制表示,最终生成二进制指令文件,作为计算机的输入。
op: 指令的基本操作,通常称为操作码(opcode),表示操作和格式的字段。
rs :第一个源操作数寄存器,
rt: 第二个源操作数寄存器。
rd:用于存放操作结果的目的寄存器。
shamt:位移量。(移位指令和该术语,不使用这个字段时,内容为0。)
funct:功能。一般称为功能码(function code),用于指明 op字段中操作的特定变式。
6 存储器
现代CPU普遍采用了层次存储结构。引入cache的起因是CPU运行速率与存储器读写速率的巨大差异,存储逐渐成为计算机显著的性能瓶颈。
引入Cache的理论基础是程序局部性原理,包括时间局部性和空间局部性。即最近被CPU访问的数据,短期内CPU 还要访问(时间);被 CPU 访问的数据附近的数据,CPU 短期内还要访问(空间)。因此如果将刚刚访问过的数据缓存在Cache中,那下次访问时,可以直接从Cache中取,其速度可以得到数量级的提高。
CPU缓存(Cache Memory)位于CPU与内存之间的临时存储器,它的容量比内存小但交换速度快。在缓存中的数据是内存中的一小部分,但这一小部分是短时间内CPU即将访问的,当CPU调用大量数据时,就可避开内存直接从缓存中调用,从而加快读取速度。
图9 计算机的层次存储
不同存储介质的参数为:
7 功耗和能耗
计算机系统是动态能耗,CMOS能耗是主要来源,与系统的电压、电容频率都有关系。
能耗指的是计算机系统在一定时间内的能量消耗,单位是焦耳
J
J
J;功耗指的是计算机系统消耗能量的速率,或者说是单位时间内的能量消耗,单位是瓦特
w
w
w。
能耗:
E
=
Σ
t
t
+
△
t
P
d
t
E=Σ^{t+△t}_tPdt
E=Σtt+△tPdt, 其中,E是系统的能耗,P是系统的功耗。
功耗:
P
a
v
g
=
△
E
△
t
P _{avg} = \frac {△E}{△t}
Pavg=△t△E, 其中,ΔE是在Δt时间内消耗的能量。
不得不提功耗墙问题,在后PC时代, 能量是真正关键的资源。对于个人移动设备来说,电池寿命比性能更为关键。对于具有 100000个服务器的仓储式计算机来说,冷却费用非常高,因此设计者要尽量降低其功耗。在评价功耗时,使用能耗比功耗更加合理,能耗的单位是焦耳/秒。
图10 时钟频率与功耗的变化趋势
为什么时钟频率增长为1000倍,而功耗只增长为30倍呢?因为能耗和功耗是电压平方的函数,能够通过降低电压来大幅减少,每次工艺更新换代时都会这样做。一般来说,每代的电压降低大约15%。20多年来,电压从5V降到了1V。这就是功耗只增长30倍的原因所在。目前的问题是如果电压继续下降会使晶体管泄漏电流过大,就像水龙头不能被完全关闭一样。目前40%的功耗是由于泄漏造成的,如果晶体管的泄漏电流再大,情况将会变得无法收拾。计算机设计中必须开辟新的路径。8 计算机的性能度量
不同的应用场景有不同的性能度量方法,主要由以下几种:
1. CPl (clock cycle per instruction):表示执行每条指令所需的时钟周期数的平均值。
2. 吞吐率:也叫带宽(bandwidth),表示单位时间内完成的任务数量。
3. 响应时间:也叫执行时间(execution time),是计算机完成某任务所需的总时间,包括硬盘访问、内存访问、IO访问、操作系统开销和CPU执行时间等。
4. 系统/用户CPU时间
5. 基准测试SPECINT
经典的CPU性能公式为:
C
P
U
时间
=
指令数
×
C
P
I
×
时钟周期时间
CPU时间=指令数×CPI×时钟周期时间
CPU时间=指令数×CPI×时钟周期时间
常以IPC(instruction per clock cycle)代替CPI评价CPU的性能,相同时钟周期(也就是说主频相同),相同指令数的情况下,IPC越高,CPU时间越少。CPU的通用计算性能是由IPC、主频、指令数三者共同决定。IPC提升是CPU通用性能提升的必要条件,由微架构组成决定。主频的提升通常由CPU制程的进步产生。算法和编译器可以优化指令数。
从指令的角度看CPU的性能,可以将CPU性能的影响因素归纳如下:
图11 CPU性能优化方法
汪老师还提到了阿姆达尔定律:一种性能改进的递减规则,如果仅仅对计算任务中的一部分做性能改进,则改进得越多 S e S_e Se,所得到的总体性能的提升就越有限:如果只针对整个任务的一部分进行改进和优化,那么所获得的加速比不超过 1 / ( 1 − F e ) 1/(1-F_e) 1/(1−Fe) :
S n = T 0 T n = 1 ( 1 F e ) + F e S e S_n = \frac {T_0}{T_n} = \frac {1}{(1F_e)+ \frac {F_e}{S_e}} Sn=TnT0=(1Fe)+SeFe1
9 计算机体系结构的8个思想
根据《计算机组成与设计:硬件/软件接口》的介绍,现代处理器的设计主要遵循8个伟大思想,这也是CPU性能优化的基础。
- “面向摩尔定律的设计”
- “使用抽象简化设计”
- “加速大概率事件”
- “采用并行提高性能”
- “采用流水线提高性能”
- “采用预测提高性能”
- “存储器层次”
- “通过冗余提高可靠性”
这些思想贯彻了计算机的指令架构设计、软硬件架构设计以及制造工艺上,例如:高级语言的抽象,指令并行,ROB和Tomasulo算法,cache的设计,分支预测技术等等。后面会依次介绍。