利用空档期时间学习一下计算机系统基础,以前对这些知识只停留在应试层面,今天终于能详细理解一下了。参考课程为南京大学袁春风老师的计算机系统基础MOOC,参考书籍也是袁老师的教材,这是我的听课+自查资料整理后的笔记,以后再发次系列文章,我就按单独一节课的顺序发,不再按章节发,如果按章节发,字数太多,容易阅读疲劳
本文目录
- W1-2-1 冯诺依曼结构主要思想
- 第一台电子计算机的诞生
- 冯·诺依曼的故事
- 现代计算机的原型
- IAS计算机结构
- 冯诺依曼结构计算机模型
- 冯诺依曼结构的主要思想
- W1-2-2 现代计算机结构模型及工作原理
- 现代计算机结构模型
- 计算机是如何工作的
- 指令和数据
- W1-3-1 从机器语言到高级编程语言
- 最早的程序开发过程
- 用机器语言编写程序
- 用汇编语言开发程序
- 进一步认识机器级语言
- 指令所能描述的功能
- 用高级语言开发程序
- W1-3-2 程序的开发和执行及其支撑环境
- 编译型语言程序的开发与执行过程(以C语言为例)
- 解释型语言程序的开发与执行过程(以Python语言为例)
- 开发和运行程序需什么支撑?
- W1-4-1 编程语言和计算机系统层次
- 早期计算机系统的层次
- 现代(传统)计算机系统的层次
- W1-4-2 现代计算机系统的层次结构
- 计算机系统抽象层的转换
- 计算机系统核心层之间的关联
- 计算机系统的不同用户
- 指令集体系结构(ISA)
- ISA和计算机组成(微结构)之间的关系
- W1-教材内容补充1 计算机系统性能瓶颈
- 计算机性能的定义
- 计算机性能的测试
- 计算机性能计算公式
- 用指令执行速度进行性能评估
- 用基准程序进行性能评估
- Amdahl定律
- W1-5 本课程的主要学习内容
- 后PC时代(2000年-现在)
- 计算机系统抽象层的转换
- “计算机系统基础”课程内容概要
W1-2-1 冯诺依曼结构主要思想
第一台电子计算机的诞生
1946年,第1台通用电子计算机 ENIAC(Electronic Numerical Integrator And Computer)诞生
- 由电子真空管组成
- 美国宾夕法尼亚大学研制
- 用于解决复杂弹道计算问题
- 5000次加法/s
- 平方、立方、sin、cos等
- 用十进制表示信息并运算 采用手动变成,通过设置开关和插拔电缆来实现
冯·诺依曼的故事
- 1944年,冯·诺伊曼参加原子弹的研制工作,涉及到极为困难的计算。
- 1944年夏的一天,诺伊曼巧遇美国弹道实验室的军方负责人戈尔斯坦,他正参与ENIAC的研制工作。
- 冯·诺依曼被戈尔斯坦介绍加入ENIAC研制组,1945年,他们在共同讨论的基础上,冯·诺伊曼以“关于EDVAC的报告草案”为题,起草了长达101页的总结报告,发表了全新的“存储程序通用电子计算机方案”。
- 一向专搞理论研究的普林斯顿高等研究院批准让冯·诺依曼建造计算机,其依据就是这份报告。
现代计算机的原型
1946年,普林斯顿高等研究院(the Institute for Advance Study at Princeton,IAS )开始设计“存储程序”计算机,被称为IAS计算机(1951年才完成,并不是第一台存储程序计算机,1949年由英国剑桥大学完成的EDSAC是第一台)
在那个报告中提出的计算机结构被称为冯·诺依曼结构。
冯·诺依曼结构最重要的思想是“存储程序(Stored-program)”
- 工作方式:任何要计算机完成的工作都要先被编写成程序,然后将程序和原始数据送入主存并启动执行。一旦程序被启动,计算机应能在不需操作人员干预下,自动完成逐条取出指令和执行指令的任务。
- 冯·诺依曼结构计算机也称为冯·诺依曼机器(Von Neumann Machine)。
- 几乎现代所有的通用计算机大都采用冯·诺依曼结构,因此,IAS计算机是现代计算机的原型机。
IAS计算机结构
冯诺依曼结构计算机模型
早期,部件之间用分散方式相连(分散的,比如指令单独一条线,地址单独一条线)
现在,部件之间大多用总线方式相连(整合在一起)
冯诺依曼结构的主要思想
1、计算机应由运算器、控制器、存储器、输入设备和输出设备五个基本部件组成。
2、各基本部件的功能是:
- 存储器不仅能存放数据,而且也能存放指令,形式上两者没有区别(它们都是01二进制序列),但计算机应能区分数据还是指令;
- 控制器应能自动取出指令来执行(也就是控制器能对指令进行译码,输出控制信号);
- 运算器能进行一些应能进行加/减/乘/除四种基本算术运算,并且也能进行一些逻辑运算和附加运算(与、或、非、移位等);
- 操作人员可以通过输入设备、输出设备和主机进行通信。
3、内部以二进制表示指令和数据。每条指令由操作码和地址码两部分组成。操作码指出操作类型,地址码指出操作数的地址。由一串指令组成程序。
4、采用“存储程序”工作方式
W1-2-2 现代计算机结构模型及工作原理
现代计算机结构模型
1、 主存储器:主存储器用来存放指令和数据,简称主存或内存(内存条上有很多芯片(颗粒));
2、 算术逻辑部件(Arithmetic Logic Unit,简称ALU):ALU是用来进行算术逻辑运算的部件,在ALU操作控制信号ALUop的控制下,ALU可以对输入端A和B进行不同的运算,得到结果F;
3、 控制部件(Control Unit,简称CU):控制部件也称控制器,它是用于自动逐条取出指令并进行译码的部件。
4、输入设备和输出设备(I/O):I/O设备用来和用户交互。
5、 通用寄存器(General Purpose Register):通用寄存器用来临时存放从主存取来的数据或运算的结果。
6、 通用寄存器组(GPRs):为了临时存放从主存取来的数据或运算的结果,还需要若干通用寄存器,组成通用寄存器组(早期就是累加器),如上图中ALU两个输入端A和B的数据来自通用寄存器。
7、 标志寄存器(Program Status Word,PSW):标志寄存器用来存放ALU运算的结果产生的标志信息,例如,结果是否为0(零标志ZF)、是否为负数(符号标志SF)等,这些标志信息需要记录在专门的标志寄存器中。
标志寄存器具体标志位及其符号含义如下(看不懂可跳过,我是学过计算机组成原理和操作系统,所以查了一些拓展资料)
缩写/中文名 | 英文全称 | 等于1时 | 等于0时 | 作用 | 使用情况 |
---|---|---|---|---|---|
CF/进位标志 | Carry Flag | 进位 | 无进位 | 进位标志CF主要用来反映运算是否产生进位或借位。如果运算结果的最高位产生了一个进位或借位,那么,其值为1,否则其值为0。 | 使用该标志位的情况有:多字(字节)数的加减运算,无符号数的大小比较运算,移位操作,字(字节)之间移位,专门改变CF值的指令等。 |
PF/奇偶标志 | Parity Flag | 偶 | 奇 | 奇偶标志PF用于反映运算结果中“1”的个数的奇偶性。如果“1”的个数为偶数,则PF的值为1,否则其值为0。 | 使用该标志位的情况有:多字(字节)数的加减运算,无符号数的大小比较运算,移位操作,字(字节)之间移位,专门改变CF值的指令等。 |
AF/辅助进位标志 | Auxiliary Carry Flag | 进位 | 无进位 | 在发生下列情况时,辅助进位标志AF的值被置为1,否则其值为0:(1)、在字操作时,发生低字节向高字节进位或借位时;(2)、在字节操作时,发生低4位向高4位进位或借位时。 | \ |
ZF/零标志 | Zero Flag | 等于零 | 不等于零 | 零标志ZF用来反映运算结果是否为0。如果运算结果为0,则其值为1,否则其值为0。 | 在判断运算结果是否为0时,可使用此标志位。 |
SF/符号标志 | Sign Flag | 负 | 非负 | 符号标志SF用来反映运算结果的符号位,它与运算结果的最高位相同。在微机系统中,有符号数采用补码表示法,所以,SF也就反映运算结果的正负号。运算结果为正数时,SF的值为0,否则其值为1。 | \ |
OF/溢出标志 | Overflow Flag | 溢出 | 未溢出 | 溢出标志OF用于反映有符号数加减运算所得结果是否溢出。如果运算结果超过当前运算位数所能表示的范围,则称为溢出,OF的值被置为1,否则,OF的值被清为0。 | \ |
缩写/中文名 | 英文全称 | 等于1时 | 等于0时 | 作用 | 使用情况 |
---|---|---|---|---|---|
TF/追踪标志 | Trap Flag | 单步执行方式 | 非单步执行方式 | 当追踪标志TF被置为1时,CPU进入单步执行方式,即每执行一条指令,产生一个单步中断请求。这种方式主要用于程序的调试。 | 指令系统中没有专门的指令来改变标志位TF的值,但程序员可用其它办法来改变其值。 |
IF/中断标志 | Interrupt Flag | CPU可以响应CPU外部的可屏蔽中断发出的中断请求 | CPU不响应CPU外部的可屏蔽中断发出的中断请求 | 中断允许标志IF是用来决定CPU是否响应CPU外部的可屏蔽中断发出的中断请求。具体规定如下:(1)、当IF=1时,CPU可以响应CPU外部的可屏蔽中断发出的中断请求;(2)、当IF=0时,CPU不响应CPU外部的可屏蔽中断发出的中断请求。 | 中断允许标志IF是用来决定CPU是否响应CPU外部的可屏蔽中断发出的中断请求。但不管该标志为何值,CPU都必须响应CPU外部的不可屏蔽中断所发出的中断请求,以及CPU内部产生的中断请求。 |
DF/方向标志 | Direction Flag | 减少 | 增加 | 方向标志DF用来决定在串操作指令执行时有关指针寄存器发生调整的方向。 当该位置1时(DF=1),存储器地址自动减少,串操作指令为自动减量指令,即从高位到低位处理字符串;当该位置0时(DF=0),存储器地址自动增加,串操作指令为自动增量指令。 | | |
- I/O特权标志IOPL(I/O Privilege Level):I/O特权标志用两位二进制位来表示,也称为I/O特权级字段。该字段指定了要求执行I/O指令的特权级。如果当前的特权级别在数值上小于等于IOPL的值,那么,该I/O指令可执行,否则将发生一个保护异常。
- 嵌套任务标志NT(Nested Task):嵌套任务标志NT用来控制中断返回指令IRET的执行。具体规定如下:
当NT=0,用堆栈中保存的值恢复EFLAGS、CS和EIP,执行常规的中断返回操作;当NT=1,通过任务转换实现中断返回。 - 重启动标志RF(Restart Flag):重启动标志RF用来控制是否接受调试故障。规定:RF=0时,表示“接受”调试故障,否则拒绝之。在成功执行完一条指令后,处理机把RF置为0,当接受到一个非调试故障时,处理机就把它置为1。
- 虚拟8086方式标志VM(Virtual 8086 Mode):如果该标志的值为1,则表示处理机处于虚拟的8086方式下的工作状态,否则,处理机处于一般保护方式下的工作状态。
(上述内容大多转自:汇编语言 标志位介绍)
8、 指令寄存器(Instruction Register,简称IR):指令寄存器用来临时保存从主存取来的指令;
9、 程序计数器(Program Counter,简称PC):在执行当前指令过程中,自动计算出下一条指令的地址并送到PC中保存;
10、中央处理器(Central Processing Unit,简称CPU):通常把控制部件、运算部件和各类寄存器互连组成的电路称为中央处理器,简称处理器;
11、通用寄存器编号:CPU需要从通用寄存器中取数据到ALU运算,或把ALU运算的结果保存到通用寄存器中,因此,需要给每个通用寄存器编号。如上图中,4个通用寄存器编号分别为0~3;
12、主存地址:主存中每个单元也需要编号,称为主存地址单元,简称主存地址,如上图中,16个主存单元编号分别为0~15;
13、总线:CPU为了从主存取指令和存取数据,需要通过传输介质与主存相连,通常把连接不同部件进行信息传输的介质称为总线。其中,包含了用于传输地址信息、数据信息和控制信息的地址线、数据线和控制线。CPU访问主存时,需先将主存地址送到总线的地址线,将读/写命令送到总线的控制线,然后通过数据线发送或接收数据。
14、主存地址寄存器(Memory Address Register,简称MAR):CPU送到地址线的主存地址应先存放在主存地址寄存器中。
15、主存数据寄存器(Memory Data Register,简称MDR):CPU发送到或从数据线取来的信息存放在主存数据寄存器中。
P.S MDR和MAR是和总线相连的部件
P.S 地址总线(Address Bus)和控制总线(Control Bus)是单向总线,而数据总线是双向总线。
计算机是如何工作的
计算机是以“存储程序”的工作方式工作的。
- 数据和指令事先放在存储器中,每条指令和每个数据都有地址,指令按序存放,指令由指令寄存器IR的OP、ADDR字段组成,程序起始地址置为PC(从程序计数器PC指出来的地址去取),PC每次都加1即一条一条去取;
- OP操作码字段指出指令的操作性质、操作类型,ADDR地址字段指出这条指令处理的操作数在哪个主存单元里面。取来每条指令,首先对OP操作码字段进行译码,译码译出来到底是做加法、减法、与、或等等操作类型是什么;
- 然后根据ADDR地址字段(ADDR地址字段到可能是存储器的地址或者寄存器的编号)到主存中或者寄存器中去取操作数(操作数(operand) 计算机指令中的一个组成部分.它规定了指令中进行数字运算的量,通常一条指令均包含操作符和操作数);
- 取来操作数进行指定的操作,完成上述过程后,将运算结果放到相应的寄存器或存储单元中。
- 每一个程序的起始地址都是先放在程序计数器PC中
- 第一步:根据程序计数器PC取指令
- 第二步:CU控制器进行指令译码
- 第三步:取操作数
- 第四步:执行指令
- 第五步:回写结果
- 第六步:修改程序计数器PC的值
- 继续执行下一条指令
【疑问】学到这里,我就有了一个疑问:计算机如何将最开始的程序的起始地址如何送入程序计数器PC中?是通过哪些流程进行操作的?
【chatGPT回答】将程序的起始地址送入程序计数器(Program Counter,PC)中通常是在计算机的开机自检(Power-On Self Test,POST)和引导启动(Boot)阶段完成的。 当计算机通电并开始自检时,处理器会将程序计数器 PC 初始化为一个预先设定好的值。这个预设的值通常被称为重置向量(Reset Vector)或启动向量(Boot Vector),是一个存储器地址,指向存储器中程序代码的入口点或者操作系统的引导程序。处理器执行完初始指令后,程序控制权就被转移到了存储器中的程序代码或操作系统引导程序处。
在引导启动阶段,操作系统的引导程序会被加载到内存的一个已知地址,并将该地址值写入到程序计数器中作为初始值。当引导程序开始执行时,PC中存储的地址就是程序的起始地址,操作系统就能够开始执行该程序。
总之,将程序的起始地址送入程序计数器 PC中是由启动过程的代码实现的,在不同的情况下,实现方式和流程可能会有所不同,但通常都会涉及到将某个地址从内存中加载到 PC 中的过程。
我将执行程序的过程标注在现代计算机模型图上(图画的如果不准确,欢迎指出)
指令和数据
冯诺依曼结构计算机的功能通过执行程序实现,程序由指令组成,程序被启动后,计算机能自动取出一条一条指令执行,在执行过程中无需人的干预。
1、原子操作:所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch(切换到另一个线程)。
2、指令(instruction):指令是用0和1表示的一串0/1序列,用来指示CPU完成一个特定的原子操作,它存在存储器中。
3、数据:数据和指令一样都存在存储器中,形式上没有差别,都是0/1序列。
4、取数指令(load):取数指令的作用是从主存单元中取出数据存放到通用寄存器中。
5、存数指令(store):存数指令的作用是将通用寄存器的内容写入主存单元。
6、加法指令(add):加法指令的作用是将两个通用寄存器相加后送入结果寄存器。
7、传送指令(mov):传送指令将一个通用寄存器的内容送到另一个通用寄存器。
指令通常被划分为若干个字段,有操作码、地址码等字段。
8、操作码字段:操作码字段指出指令的操作类型,如取数、存数、加、减、传送、跳转等。
9、地址码字段:地址码字段指出指令所处理的操作数的地址,如寄存器编号、主存单元编号等。
10、操作数:操作数是运算符作用于的实体,是表达式中的一个组成部分,它规定了指令中进行数字运算的量。
11、立即数:指令要操作的数据以常量的形式出现在指令中,称为立即数,它只能作为源操作数。
12、源操作数:在应用指令中,内容不随指令执行而变化的操作数为源操作数。
13、目的操作数:在应用指令中,内容随执行指令而改变的操作数为目的操作数。
14、双操作数:双操作数又称为源操作数(source)和目的操作数(destination)。
【提问】请用通俗的语言解释何为操作数。
【chatGPT回答】在计算机的世界中,指令被设计成由两个部分组成:操作码和操作数。操作码指示计算机执行何种操作,如加、减、乘等;而操作数则是指这些操作所需要的数据。具体来说,操作数是指被计算机指令操作的数据,是指令所要操作的对象。
举个例子,如果要进行加法计算,那么这个加法计算的操作码就是“加”这个指令。而这个操作指令所涉及的两个数,就是操作数。例如:如果我们想要对数字1和数字2进行加法计算,那么这两个数字就是操作数,指令指示操作数相加。
在计算机中,操作数通常保存在寄存器中或者内存中。在指令执行时,指令会告诉计算机去哪里寻找这些操作数,并将它们读取到指定的寄存器中,然后进行操作。操作数可以是数字、字符、地址、内存中的位置等等,具体的形式取决于指令的要求。
总之,操作数就是计算机指令所要操作的数据,是指令中需要的数据部分,它可以保存在寄存器或内存中,并且在执行指令时被读取和处理。
一段指令中需要给出的信息:
- 操作性质(操作码)
- 源操作数1 或/和 源操作数2 (立即数、寄存器编号,存储地址)(加法,双目运算,有两个操作数;取反,单目运算,只有一个操作数)
- 目的操作地址(寄存器编号,存储地址)
存储地址的描述与操作数的数据结构(可能数组等)有关
15、机器字长(Machine word length):机器字长是指计算机进行一次整数运算所能处理的二进制数据的位数(整数运算即定点整数运算)。因为计算机中数的表示有定点数和浮点数之分,定点数又有定点整数和定点小数之分,这里所说的整数运算即定点整数运算。机器字长也就是运算器进行定点数运算的字长,通常也是CPU内部数据通道的宽度。
- R[r]表示编号为r的通用寄存器中的内容
- M[addr]表示地址为addr的主存单元内容
- M[PC]表示从程序计数器中取指令
- “←”表示从右向左传送数据
- R[a] op R[b]表示a号和b号寄存器指向op指令其结果送入a号寄存器
- A表示ALU的输入端A,B表示ALU的输入端B
- PC← PC当前地址 + 1表示PC增量
- F表示ALU的运算结果
假定机器字长8位,用刚才的示意图:
4个通用寄存器r0~r3,编号为0~3,16个主存单元,编号0~15,每个主存单元和CPU中的ALU,通用寄存器,IR,MDR宽度都是8位,PC和MAR的宽度都是4位,地址总线4位,数据总线和若干控制线(包括读/写命令线)共8位,机器字长8位,每条指令有8位,有R型和M型,如图所示:
R型指令的op为0000时为传送操作(MOV),为0001时为加操作(ADD);M型指令的op为1110时为取数操作(load),为1111时为存数操作(store).
比如:
- 指令1110 0110 ,它是M型指令,前四位为取数操作,后四位是其地址,即R[0] ← R[0110],表示从0110地址主存单元(0110二进制转十进制为6,即6号主存单元)中的内容取到0号寄存器
- 指令0001 0001,它是R型指令,前四位为加操作,后四位中,rt两位为00,rs两位为01,转成十进制即rt=0,rs=1,即R[0] ← R[0] + R[1]
模仿书中的例子,我写了一个z = x + y,x存在主存15号单元(即二进制1111),y存在主存5号单元(即二进制0101)中,结果z存放在主存10号单元(即二进制1010)中,则相应程序在主存单元中的初始内容如下表所示。
主存地址(二进制/十进制) | 主存单元内容 | 内容说明, I i I_{i} Ii表示第i条指令 | 指令的符号表示 |
---|---|---|---|
0/0000 | 1110 0101 | I 1 I_{1} I1:R[0] ← M[0101];op=1110:取数操作,从地址0101(十进制5)中读取数据送入0号寄存器 | load r0 , 5# |
1/0001 | 0000 0100 | I 2 I_{2} I2:R[1] ← R[0];op=0000:传送操作,将0号寄存器的值传送到1号寄存器中 | mov r1 , r0 |
2/0010 | 1110 1111 | I 3 I_{3} I3:R[1] ← M[1111];op=1110:取数操作,从地址1111(十进制15)中读取数据送入0号寄存器 | load r0 , 15# |
3/0011 | 0001 0001 | I 4 I_{4} I4:R[0] ← R[0] + R[1];op=0001:加操作,将0号寄存器和1号寄存器的值相加并将加和结果送入R[0] | add r0, r1 |
4/0100 | 1111 1010 | I 5 I_{5} I5:M[1010] ← R[0];op=1111:存数操作,将0号寄存器的值存入主存地址为1010的内存单元 | store 10# , r0 |
5/0101 | 1111 1111 | 操作数 x x x,值为-1(计算机用补码存储数据,补码为1111 1111,补码的补码即为原码,补码除符号位先取反为1000 0000,再加1,即为1000 0001,则十进制为-1) | |
… | … | … | … |
10/1010 | 0000 0000 | 运算结果 z z z,初始值为0 | |
… | … | … | … |
15/1111 | 0000 0010 | 操作数 y y y,正数的原码、反码、补码一致,十进制值为2 |
补码相加的结果为:1111 1111 + 0000 0010 = 0000 0001 ,正数的原码、反码、补码一致,结果为-1+2= 1,关于原码、反码、补码的知识可以等到W2,也可以自己先查一查,我这里举-1的例子是为了练习
对于上述程序,程序首地址(即指令 I 1 I_{1} I1所在地址)为0,最开始PC为0000,每条指令如下表所示:
I 1 I_{1} I1:1110 0101 | I 2 I_{2} I2:0000 0100 | I 3 I_{3} I3:1110 1111 | I 4 I_{4} I4:0001 0001 | I 5 I_{5} I5:1111 1010 | |
---|---|---|---|---|---|
取指令 | IR←M[0000] | IR←M[0001] | IR←M[0010] | IR←M[0011] | IR←M[0100] |
指令译码 | op=1110,取数 | op=0000,传送 | op=1110,取数 | op=0001,加 | op=1111,存数 |
PC增量 | PC←0000 + 1 | PC←0001 + 1 | PC←0010 + 1 | PC←0011 + 1 | PC←0100 + 1 |
取数并执行 | MDR←M[0101] | A←R[0]、mov | MDR←M[1111] | A←R[0]、B←R[1]、add | MDR←R[0] |
送结果 | R[0]←MDR | R[1]←F | R[0]←MDR | R[0]←F | M[1010]←MDR |
执行结果 | R[0]=-1 | R[1]–1 | R[0]=2 | R[0]=-1+2=1 | M[10] = 1 |
指令执行各阶段都包含若干个微操作,微操作需要相应的控制信号(control signal)进行控制。
比如:
- 取指令阶段IR←M[PC],微操作有:MAR←PC;控制线←Read;IR←MDR
- ALU运算R[0]←R[0] + R[1],微操作有:A←R[0];B←R[1];ALUop←add;R[0]←F
【提问】请用通俗的语言解释计算机CPU执行指令时的微操作是什么?微操作需要相应的控制信号是什么?
【chatGPT回答】计算机CPU执行指令时,会按照指令中所包含的操作码,依次执行一些基本的微操作。微操作也称为微指令,是指一些基本的、原子的操作操作,用于实现指令中的各种功能。
例如,在执行加法指令时,CPU内部会进行以下一些基本的微操作:从指定寄存器中读取操作数A和操作数B;将寄存器A和寄存器B中的数据相加,并将结果写入一个结果寄存器中;从结果寄存器中读取结果,将其写回指定的寄存器中等等。这些微操作的具体实现需要依靠相应的控制信号来实现。
控制信号是用于控制CPU内部各个部件工作的信号,主要包括时钟信号、使能信号、数据传输信号等等。当CPU需要执行指令时,控制信号会根据指令操作码的不同,将微操作分配到相应的部件上,以实现指令功能。
以执行加法指令为例,执行该指令需要的控制信号包括:时钟信号、读取A寄存器的使能信号、读取B寄存器的使能信号、ALU加法器的使能信号、从ALU结果寄存器中读取结果使能信号、将结果写回到指定寄存器的使能信号等等。这些控制信号都是CPU内部预定义好的,并可以通过指令解码器来根据指令操作码的不同进行适当的组合。
总之,微操作是如何实现指令功能的基本操作,需要相应的控制信号的支持。这些控制信号通过指令解码器来根据指令操作码的不同进行适当的组合,从而实现指令功能。
CPU中所有微操作都由时钟信号进行定时,时钟信号(clock signal)的宽度为一个时钟周期(clock cycle),一条指令包含一个或多个时钟周期。
【提问】请用通俗的语言解释计算机CPU的所有微操作都由时钟信号进行定时,那么时钟信号是什么?时钟周期是什么?
【chatGPT回答】时钟信号是计算机中一个非常重要的信号,它决定着计算机硬件中的各个部件何时可以进行数据传输和运算。时钟信号是CPU中的一个定时信号,用来控制CPU内部的各种操作,例如说,CPU通过时钟信号周期性的激活各种微操作,使得CPU能够按照指令操作码的要求,实现各种计算任务。
时钟周期是指一次完整的时钟信号所包含的时间。在时钟周期中,CPU内部完成一组特定的微操作,并等待下一个时钟周期到来从而继续进行下一组微操作。通常,计算机时钟频率是固定的,因此时钟周期的长度是稳定的,可以通过时钟频率计算得出。
举个例子,如果计算机的时钟频率是4GHz,那么每秒钟时钟信号会发出4亿次,每个时钟周期的长度就是1/4亿秒,约等于0.025纳秒。CPU在一个完整的时钟周期内可以完成的微操作是固定的,并且需要在下一个时钟周期发送完整的指令后才能开始下一组微操作。因此,在计算机内部,时钟信号对于指令的执行时间和CPU的性能起着至关重要的作用。
总而言之,时钟信号是控制CPU内部基本微操作的定时信号,时钟周期是时钟信号中的一个完整周期。计算机内部的各种操作都需要遵循时钟信号的定时规律,以实现指令的执行和CPU的各项功能。
W1-3-1 从机器语言到高级编程语言
现代通用计算机都采用“存储程序”工作方式,需要计算机完成的任何任务都应先表示为一个程序。首先,应将应用问题(任务)转化为算法(algorithm)描述,其次,将算法转换为用编程语言描述的程序,程序设计语言(programming language)与自然语言不同,它有严格的执行顺序,不存在二义性(语言的二义性,就是指由于某句话的语义太多,让人很难准确地分辨该话语的真正意思,从而导致了二义性的出现。编程语言类似,让机器无法分辨真正的含义的语句),能够唯一地确定计算机执行指令的顺序。
最早的程序开发过程
用机器语言编写程序
1、机器语言:使用特定计算机规定的指令格式而形成的0/1序列称为机器语言。
2、机器语言程序:计算机能理解和执行的程序称为机器代码或机器语言程序。
3、机器指令:机器语言程序的每条指令都由0和1组成,称为机器指令。
用机器语言编写程序,并记录在纸带或卡片上,穿孔表示0,未穿孔表示1,输入:按钮、开关;输出:指示灯等。
假设:0010-jc
0:0101 0110 // 0101是加法,0110是地址,把累加器的内容和0110地址对应的主存单元的内容相加,加出来的结果继续放入累加器
1:0010 0100 //0010,JC指令,如果相加的结果有进位,则跳转0100地址对应的主存单元,取执行0100(十进制4)号主存单元中的指令
2:…
3:…
4:0110 0111
5:…
6:…
【缺点】若在第4条指令前加入指令,则需重新计算地址码(如jxx的目标地址),然后重新打孔。不灵活!书写、阅读困难!
【提问】解释一下汇编语言jc指令
【chatGPT回答】汇编语言中的JC指令是跳转指令之一,用于根据条件是否成立来执行跳转操作。JC指令的功能是:如果最近一次运算结果产生了进位,那么就按指定的跳转地址跳转到对应的指令地址。如果进位标志位为1,则跳转;如果进位标志位为0,则继续往下执行。
具体来说,JC指令是根据CPU中的标志寄存器(也叫标志位、标志寄存器)中的进位标志位(Carry Flag)判断是否跳转。如果进位标志位为1,则表示最近一次运算结果产生了进位,那么CPU就会按照指定的跳转地址跳转到对应的指令地址执行。如果进位标志位为0,则表示最近一次运算结果没有进位,那么CPU就会继续执行下一条指令。
JC指令在实际应用中比较广泛,通常用于实现条件分支控制结构。例如,在计算一个大于等于0的整数n的阶乘时,可以使用JC指令来实现循环控制结构,当某一次循环产生进位时,就退出循环,并输出结果。
汇编语言中的JC指令的语法如下:JC label
其中,label是程序中的一个标记,代表一个跳转目标地址。当进位标志位为1时,CPU会跳转到这个标记所代表的指令地址。
用汇编语言开发程序
1、助记符(mnemonic):助记符是便于人们记忆、并能描述指令功能和指令操作数的符号,助记符是表明指令功能的英语单词或其缩写。
2、标号:用来标注指令的地址,一般由 1~8 个字母和数字组合而成,但必须以字母开头,以冒号“:”结束。
3、汇编语言:最早人们采用机器语言编写程序。机器语言程序的可读性很差,也不易记忆,给程序员的编写和阅读带来极大的困难。因此,人们引入了一种机器语言的符号表示语言,用简短的英文符号和机器指令建立对应关系,以方便程序员编写和阅读程序,这种语言称为汇编语言,汇编语言用助记符表示操作码,用标号表示位置。
【比如:1110 0110对应汇编指令load r0 , 6#】
【注】(1)add助记符,加操作,(2)jc助记符,跳转操作,(3)sub助记符,减操作。
【汇编语言的优点】
- 不会因为增减指令而需要修改其他指令
- 不需记忆指令编码,编写方便
- 可读性比机器语言强
不过,这带来新的问题,是什么呢?人容易了,可机器不认识这些指令了!所以用汇编语言写程序转换为机器语言写的程序,用汇编程序转换。
进一步认识机器级语言
1、汇编指令:机器指令对应的符号即用助记符和标号来表示的指令(与机器指令一一对应)称为汇编指令。汇编语言(源)程序由汇编指令构成。
2、机器级语言:汇编语言和机器语言都属于低级语言,它们都是面向及其结构的语言(移植难度大,不同平台的计算机上的汇编语言不同),它们统称为机器级语言。
指令的结构:
- 包含操作码和操作数或其地址码(机器指令用二进制表示,汇编指令用符号表示)
- 只能描述:取(或存一个数),两个数加(或减、乘、除、与、或等),根据运算结果判断是否转移执行。
想象用汇编语言编写复杂程序是怎样的情形?
(例如,用汇编语言实现排序(sort)、矩阵相乘)
需要描述的细节太多了!程序会很长很长!而且在不同结构的机器上就不能运行!
结论:用汇编语言比机器语言好,但是,还是很麻烦!
指令所能描述的功能
对于以下结构的机器,你能设计出几条指令吗?
Ld M#,R# (将存储单元内容装入寄存器)
St R#,M# (将寄存器内容装入存储单元)
Add R#,M# (类似的还有Sub,Mul等;操作数还可“R#,R#”等)
Jxx M# (若满足条件,则转移到另一处执行)
……
用高级语言开发程序
因为每条指令的功能非常简单,所以使用机器级语言描述程序功能时,需描述的细节很多,不仅程序设计工作效率很低,而且同一个程序不能在不同机器上运行。为此,程序员多采用高级程序设计语言编写程序。
1、高级程序设计语言(high level programming language):高级程序设计语言简称高级编程语言,它是指面向算法设计的、较接近于日常英语书面语言的程序设计语言,如Python、C/C++、Java等。它与具体的机器结构无关,可读性比机器级语言好,描述能力更强,一条语句可对应几条或几十条指令。
- 它有“面向过程”和“面向对象”的语言之分
(1)面向过程(Procedure Oriented):“面向过程”是一种以过程为中心的编程思想。这些都是以什么正在发生为主要目标进行编程,不同于面向对象的是谁在受影响。
(2)面向对象(Object Oriented):面向对象是软件开发方法,一种编程范式。面向对象是相对于面向过程来讲的,面向对象方法,把相关的数据和方法组织为一个整体来看待,从更高的层次来进行系统建模,更贴近事物的自然运行模式。 - 处理逻辑分为三种结构:顺序结构、选择结构、循环结构。
(1)顺序结构:顺序结构的程序设计是最简单的,只要按照解决问题的顺序写出相应的语句就行,它的执行顺序是自上而下,依次执行。
(2)选择结构:选择结构用于判断给定的条件,根据判断的结果判断某些条件,根据判断的结果来控制程序的流程。
(3)循环结构:循环结构是指在程序中需要反复执行某个功能而设置的一种程序结构。它由循环体中的条件,判断继续执行某个功能还是退出循环。根据判断条件,循环结构又可细分为以下两种形式:先判断后执行的循环结构和先执行后判断的循环结构。 - 有两种转换方式:“编译”和“解释”
(1)编译程序(Complier):将高级语言源程序转换为机器级目标程序(即翻译成汇编语言或机器语言目标程序),执行时只要启动目标程序即可。(如C语言)
(2)解释程序(Interpreter):将高级语言语句逐条翻译成机器,指令并立即执行,不生成目标文件。(如Python语言)
P.S 现在,几乎所有程序员都用高级语言编程,但最终要将高级语言转换为机器语言程序。
2、翻译程序(translator):将高级编程语言程序转换成机器语言程序的软件统称为翻译程序。
3、源语言和源程序:被翻译的语言和程序分别称为源语言和源程序。
4、目标语言和目标程序:翻译生成的语言和程序分别称为目标语言和目标程序。
翻译程序由以下三类:
- 汇编程序(assembler):也称汇编器,实现将汇编语言源程序翻译成机器语言目标程序。
- 解释程序,也称解释器。
- 编译程序,也称编译器。
5、MIPS指令集系统结构(MIPS架构):MIPS是指在20世纪80年代初由斯坦福大学Hennessy教授领导的研究小组研制出来的一种RISC处理器,应用广泛。
第一条指令:1000 1100 0100 1111 0000 0000 0000 0000,这是一条MIPS指令集系统结构中的指令,其中,高6位“100011”为操作码,表示取数操作,随后5位“00010”为通用寄存器编号2,再后面5位“01111”为另一个通用寄存器编号15,最后16位为立即数0。
任何高级语言程序最终通过执行若干条指令来完成。
W1-3-2 程序的开发和执行及其支撑环境
编译型语言程序的开发与执行过程(以C语言为例)
有如下C语言程序"hello.c"的代码(C语言是编译型语言):
#include <stdio.h>
int main()
{
printf("hello world!\n");
return 0;
}
功能:输出"hello world!"
(1)通过程序编辑软件得到hello.c源程序文件,hello.c源程序文件在计算机以ASCII字符方式存放,如下图所示。
- 文本文件(text file):通常把用ASCII码字符或汉字字符表示的文件称为文本文件,源程序文件都是文本文件,是可现实和可读的。
- ASCII码(American Standard Code for Information Interchange):美国信息交换标准代码是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。它是最通用的信息交换标准,并等同于国际标准 ISO/IEC 646。
(2)将hello.c源程序文件进行预处理、编译、汇编和链接,最终生成可执行目标文件,可用GCC编译驱动程序进行处理,命令如下:
> gcc -o hello hello.c
最前面的>为shell命令行解释器(在计算机科学中,Shell俗称壳(用来区别于核),是指“为使用者提供操作界面”的软件(command interpreter,命令解析器)。它类似于DOS下的COMMAND.COM和后来的cmd.exe。它接收用户命令,然后调用相应的应用程序。)的命令行提示符,gcc为GCC编译驱动程序名,-o表示后面为输出文件名,hello.c 为要处理的源程序。
以下是GCC+Linux平台中的处理过程图:
- 预处理阶段: 预处理阶段(cpp)对源程序中以字符#开头的命令进行处理,例如,将#include命令后面的.h文件内容嵌入到源程序文件中。预处理程序的输出结果还是一个源程序,以.i为扩展名。
- 编译阶段:编译程序(ccl)对预处理后的源程序进行编译,生成一个汇编语言源程序文件,以.s为扩展名,例如,hello.s是一个汇编语言源程序文件。因为汇编语言与具体的机器结构有关,所以,对同一台机器来说,不管何种高级语言,编译转换后的输出结果都是同一种机器语言对应的汇编语言源程序。
- 汇编阶段:汇编程序(as)对汇编语言源程序进行汇编,生成一个可重定位目标文件,以.o为拓展名,例如,hello.o是一个可重定位目标文件,它是一种二进制文件,因为其中的代码已经是机器指令,数据以及其他信息也都是二进制表示的,所以它是不可读的,也即打开显示出来的是乱码。
- 可重定位目标程序(relocatable object file):一个程序从功能上可以划分为多个模块,每一个功能模块可以独立编程,每一模块的程序也可以独立编译,此时,生成得到的目标文件,称为可重定位目标文件,其代码和数据可以和其他可重定位目标文件合并。比如开发者调用输入输出printf函数和scanf函数,就要把这两个可重定位目标程序和自己编写的源程序文件经过预处理、编译、汇编后的可重定位目标程序进行链接(也就是合并)。(此处引用改编自这个文章:认识可重定位目标文件和可执行目标文件)
- 链接阶段:链接程序(ld)将多个可重定位目标文件和标准函数库中的可重定位目标文件合并成为一个可执行目标文件(executable object file),可执行目标文件简称为可执行文件。如hello.o,连接器将hello.o和标准库函数printf所在的可重定位目标模块printf.o进行合并,生成可执行文件hello.
- 最终生成的可执行文件被保存在磁盘上,可以通过某种方式启动一个磁盘上的可执行文件来运行。
Hello程序的数据流动过程:
$是指Linux终端提示用户输入命令的提示符
$ ./hello 是执行hello程序
然后屏幕输出了hello world
- 在用户输入命令按下回车时,计算机系统按Red红色的线进行shell命令行处理,shell程序会将用户从键盘输入的每个字符逐一读入CPU寄存器中,然后再保存到主存储器中,在主存的缓冲区形成字符串“./hello”.
- 等到接收到回车"enter"按键时,shell将调出操作系统内核中想用的服务例程,由内核来加载磁盘上的可执行文件hello到存储器。加载可执行文件是Blue蓝色的线对应的流程。
- 而后,内核加载完可执行文件中的代码及其所要处理的手机开字符串“hello world\n”后,将hello第一条指令的地址送到程序计数器PC中,CPU永远都是将PC的内容作为将要执行的指令的地址,因此,CPU随后开始执行hello程序,它将加载到主存的字符串"hello world\n"中的每一个字符从主存取到CPU的寄存器中,然后将CPU寄存器中的字符送到显示器上显示出来,执行程序,在屏幕上打印hello world的过程如Cyan绿色的线的流程所示。
在上述过程中,涉及外部设备的操作,这些底层硬件是不能由用户程序直接访问的,需要依靠操作系统内核服务例程的支持,比如,用户程序需要调用内核的read系统调用服务例程读取磁盘文件,或调用内核的write系统调用服务例程把字符串:写“到显示器等。
计算机的硬件可以分为主机和外设两部分
- 主机:主机中的主要功能模块是CPU、主存和各个I/O模块,CPU、内存等采用高速元器件实现,使得它们和外设之间在技术特性上有很大差异,它们各自有自己的时钟和独立的时序控制,两者之间采用完全的异步工作方式。
- I/O设备(外设):键盘、磁盘和显示器等外部设备简称为外设,也称I/O设备,其中,I/O是输入/输出(Input/Output)的缩写。
- I/O控制器:外设通常由机械部分和电子部分组成,并且两部分通常是可以分开的。机械部分是外部设备本身,而电子部分则是控制外部设备工作的I/O控制器或I/O适配器。外设通过I/O控制器或I/O适配器连接到主机上,I/O控制器或I/O适配器统称为设备控制器。
- I/O模块:键盘接口、打印机适配器、显示控制卡(简称显卡)、网络控制卡(简称网卡)等都是一种设备控制器,属于一种I/O模块。
- I/O端口和“I/O空间”:I/O模块中有数据缓冲寄存器、命令字寄存器和状态字寄存器,它们统称为I/O端口。为了能够访问这些端口,需要对其进行编址,所有I/O端口的地址组成的空间称为I/O空间。
- 存储器映射方式和独立编址方式:I/O空间可以和主存空间统一编址,也可以单独编址吗,前者称为存储器映射方式,后者称为独立编址方式。
解释型语言程序的开发与执行过程(以Python语言为例)
Python 程序在执行过程中同样需要编译(Compile),编译产生的结果称之为字节码,而后由 Python 虚拟机逐行地执行这些字节码。所以,Python 解释器由两部分组成:编译器和虚拟机。
- 字节码:字节码(Byte-code)是一种包含执行程序,由一序列 op 代码/数据对组成的二进制文件,是一种中间码。
其具体流程如下,源程序文件.py送入解释器后
开发和运行程序需什么支撑?
最早的程序开发很简单
- 直接输入指令和数据,启动后把第一条指令地址送PC开始执行
用高级语言开发程序需要复杂的支撑环境 - 需要编辑器编写源程序
- 需要一套翻译转换软件处理各类源程序
(1)编译方式:预处理程序、编译器、汇编器、链接器
(2)解释方式:解释程序 - 需要一个可以执行程序的界面
(1)GUI方式:图形用户界面
(2)CUI方式:命令行用户界面
支撑程序开发和运行的环境由系统软件提供,最重要的系统软件是操作系统和语言处理系统,语言处理系统运行在操作系统之上,操作系统利用指令管理硬件
W1-4-1 编程语言和计算机系统层次
早期计算机系统的层次
- 最早的计算机用机器语言编程:机器语言称为第一代程序设计语言(
First generation programming language ,1GL )
- 后来用汇编语言编程:汇编语言称为第二代程序设计语言(Second generation programming language ,2GL ),指令集体系结构上面用操作系统对下面的体系结构进行封装,形成用户接口(用户界面,系统提供的服务)
现代(传统)计算机系统的层次
- 现代计算机用高级语言编程:
(1)第三代程序设计语言(3GL)为过程式语言,编码时需要描述实现过程,即“如何做”。
(2)第四代程序设计语言(4GL) 为非过程化语言,编码时只需说明不需要描述具体的算法实现细节。“做什么”
- 语言处理系统包括:各种语言处理程序(如编译、汇编、链接)、运行时系统(如库函数,调试、优化等功能)
- 操作系统包括人机交互界面、提供服务功能的内核例程
可以看出:语言的发展是一个不断“抽象”的过程,因而,相应的计算机系统也不断有新的层次出现。
W1-4-2 现代计算机系统的层次结构
计算机系统抽象层的转换
- 功能转换:上层是下层的抽象,下层是上层的实现,底层为上层提供支撑环境。
- 语言处理系统:提供程序编辑器和各类翻译转换软件的工具包统称为语言处理系统。
- 具有人机交互功能的用户界面和底层系统调用服务例程则由操作系统提供。
- 虚拟机(virtual machine):所有的语言处理系统都必须在操作系统提供的计算机环境中运行,操作系统是对计算机底层结构和计算机硬件的一种抽象,这种抽象构成了一台可以让程序员使用的虚拟机。
- 指令集体系结构(Instruction Set Architecture,简称ISA):从应用问题到机器语言程序的每次转换所涉及的概念都属于软件的范畴,而机器语言程序所运行的计算机硬件和软件之间需要有一个“桥梁”,这个在软件和硬件之间的界面就是ISA,又简称为体系结构或系统结构,它是软件和硬件之间接口的一个完整定义。(比如Intel x86,arm 64)
- ISA规定的内容包括:数据类型及格式,指令格式,寻址方式和可访问地址空间大小,程序可访问的通用寄存器的个数、位数和编号,控制寄存器的定义,I/O空间的编址方式,终端结构,机器工作状态的定义和切换,输入/输出结构和数据传送方式,存储保护方式等。
- 软件可见部分:指令集体系结构是指软件能感知到的部分,也称软件可见部分。
- 机器语言程序就是一个ISA规定的指令的序列,因此,计算机硬件执行机器语言程序的过程就是让其执行一条一条指令的过程。
- 微体系结构(microarchitecture):ISA是对指令系统的一种规定或结构规范,具体实现的组织称为微体系结构,简称微架构。(比如Intel x86这种ISA,很多处理器的组织方式不同,也即具有不同的微架构,但因为它们具有相同的ISA,所以一种处理器上运行的程序,在另一种处理器上也能运行)
- 微体系结构最终是由逻辑电路(logic circuit)实现的,当然,微架构中的一个功能部件可以用不同的逻辑来实现,用不同的逻辑实现方式得到的性能和成本是由差异的。
- 最后,每个基本的逻辑电路都是按照特定的器件技术(device technology)实现的(CMOS电路中使用的器件和NMOS电路中使用的器件不同)
【提问】用通俗的语言解释一下何为CMOS电路,何为NMOS电路
【chatGPT回答】CMOS是一种半导体电路技术,其中由p型和n型晶体管(Metal Oxide Semiconductor Field Effect Transistor, MOSFET)组成以实现和/或逻辑门电路。其中,CMOS指代的是能量低廉,仅需极少数量的电源开销,且在不断增长的电子电路中极度广泛使用的Complementary MOS(互补MOS)电路技术。CMOS技术具有高的抗干扰性、低功耗及高可靠性。
CMOS电路采用两种类型的晶体管:p型MOS(PMOS)和n型MOS(NMOS)。在PMOS中,当输入为“0”时,输出为“1”,而在NMOS中,当输入为“1”时,输出为“0”。因此,在CMOS电路中,PMOS和NMOS通常被同时使用,以形成互补功能,产生极低的功耗和高的速度。
NMOS电路(N-type MOS)是指使用n型MOS场效应管来实现电路的技术。它在数字和模拟电路中都广泛应用,因为它可以轻松地在单个晶体管中实现所有逻辑,且易于制造。NMOS电路的特点是能够提供一个低电平的高输出电流,但会产生静态功耗(quiescent power)。
总之,CMOS电路,作为一种半导体集成电路技术,由PMOS和NMOS晶体管组成以实现和/或逻辑门电路。NMOS电路则是指使用n型MOS场效应管来实现电路的技术。两者在数字和模拟电路中都广泛应用,因为它们能够提供极低的功耗以及高的速度和可靠性。
总而言之,程序执行结果不仅取决于算法、程序编写而且还取决于语言处理系统、操作系统、ISA、微体系结构
计算机系统核心层之间的关联
高级编程语言的翻译程序将高级语言源程序转换为机器级目标代码,或者转换为机器代码并直接执行,这个过程需要完成多个步骤,包括词法分析、语法分析、语义分析、中间代码生成、代码优化、目标代码生成和目标代码优化等。整个过程可划分为前端和后端两个阶段。(这里说的前端和后端不是web开发的前端和后端)
- 前端:通常把中间代码生成及之前各步骤称为前端。前端主要完成对源程序的分析,把源程序切分成一些基本块,并生成中间语言表示。
- 后端:后端在分析结构正确无误的基础上,把中间语言表示(中间代码)转化为目标及其支持的机器级语言程序。
- 未定义行为(Undefined Behavior):在计算机程序设计中,未定义行为是指执行某种计算机代码所产生的结果,这种代码在当前程序状态下的行为在其所使用的语言标准中没有规定。常见于翻译器对源代码存在某些假设,而执行时这些假设不成立的情况。
例如:在Intel x86处理器架构下,用gcc编译系统开发运行时,char类型按带符号整数运算,在RISC-V处理器架构是哪个,用gcc编译,char类型被当做无符号整数,这就导致了非预期结果,所以应该在确定程序中进行的是带符号整数运行的情况下,把相应的变量说明成signed char类型。 - 应用程序二进制接口ABI(Application Binary Interface):ABI是为运行在特定ISA及特定操作系统之上的应用程序规定的一种机器级目标代码层接口,包含了运行在特定ISA及特定操作系统之上的应用程序所对应的目标代码生成时必须遵循的约定。
- 应用程序编程接口API(Application Programming Interface):API定义了较高层次的源程序代码和库之间的接口,通常是与硬件无关的接口。因此,同样的源程序代码可以在支持相同API的任何系统中进行编译以生成目标代码。
在ISA层之下,处理器设计时需要根据ISA规范来设计相应的硬件接口供操作系统和应用程序使用,不符合ISA规范的处理器设计,将无法支撑操作系统和应用程序的正确运行。计算机系统中的所有行为都是由各种手册确定的,计算机系统也是按照手册造出来的。因此,如果想要了解程序的确切行为,最好的方法就是查手册。
C语言标准手册网址(国内访问可能不通畅):https://www.open-std.org/JTC1/SC22/WG14/www/docs/n1124.pdf
计算机系统的不同用户
计算机系统所完成的所有任务都是通过执行程序所包含的指令来实现。计算机系统由硬件和软件两部分组成。
- 硬件(hardware):硬件是物理装置的总称,人们看到的各种芯片、板卡、外设、电缆等都是计算机硬件。
- 软件(software):软件包括运行在硬件上的程序和数据以及相关的文档。
- 程序(program):程序是指挥计算机如何操作的一个指令序列。
- 数据(date)数据是指令操作的对象。
根据软件的用途,一般将软件分成系统软件和应用软件两大类
- 系统软件(system software):系统软件包括有效、安全地使用和管理计算机以及为开发和运行应用软件而提供的各种软件,介于计算机硬件与应用程序之间,它与具体应用关系不大。系统软件包括操作系统(Windows、UNIX、Linux)、语言处理系统(如Visual Studio、GCC)、数据库管理系统和各类实用程序。
- 应用软件(application software):应用软件指专门为数据处理、科学计算、事务管理、多媒体处理、工程设计以及过程控制等应用所编写的各类程序。
按照计算机上完成任务的不同,可以把实用计算机的用户分成以下四类:最终用户、系统管理员、应用程序员和系统程序员(语言处理系统建立在操作系统之上)。
自顶向下有:
- 最终用户(end user):实用应用软件完成特定任务的计算机用户成为最终用户工作在由应用程序提供的最上面的抽象层。
- 系统管理员(system administrator):系统管理员是指利用操作系统、数据库管理系统等软件提供的功能对系统进行配置、管理和维护,以建立高效合理的系统环境提供计算机用户使用的操作人员。系统管理员工作在由操作系统提供的抽象层。
- 应用程序员(application programmer):应用程序员是指使用高级编程语言编制应用软件的程序员,应用程序员工作在由语言处理系统(主要有编译器和汇编器)的抽象层。
- 语言处理系统建立在操作系统之上
- 系统程序员(system programmer):系统程序员是指设计和开发系统软件的程序员,如开发操作系统、编译器、数据库管理系统等系统软件的程序员,系统程序员(实现系统软件)工作在ISA层次,必须对ISA非常了解。
- 编译器和汇编器的目标程序由机器级代码组成,操作系统通过指令直接对硬件进行编程控制
ISA处于软件和硬件的交界面(接口),ISA是对硬件
的抽象,所有软件功能都建立在ISA之上,ISA分层如下:
- 机器语言机器:系统程序员所看到的机器的属性是属于ISA层面的内容,所看到的机器是配置了指令系统的机器,称为机器语言机器,工作在该层次的程序员称为机器语言程序员。
- 操作系统虚拟机:系统管理员工作在操作系统层,所看到的是配置了操作系统的虚拟机器,称为操作系统虚拟机。
- 汇编语言虚拟机:汇编语言程序员工作在提供汇编程序的虚拟机器级,所看到的机器称为汇编语言虚拟机。
- 高级语言虚拟机:应用程序员大多工作在提供编译器或解释器等翻译程序的语言处理系统层,因此,应用程序员大多用高级语言编写程序,因而也称为高级语言程序员,所看到虚拟机器称为高级语言虚拟机。
- 应用程序层:最终用户则工作在最上面的应用程序层。
指令集体系结构(ISA)
ISA指Instruction Set Architecture,即指令集体系结构,有时简称为指令系统
ISA是一种规约(Specification),它规定了如何使用硬件即ISA规定了:
- 可执行的指令的全部集合,包括指令格式、操作种类(加减乘除与或非等)以及每种操作对应的操作数的相应规定;
- 指令可以接受的操作数的类型(比如:加法指令,操作数可以是定点数或浮点数);
- 操作数所能存放的寄存器组的结构(规定了计算机中有多少个通用寄存器等),包括每个寄存器的名称、编号、长度和用途;
- 操作数所能存放的存储空间的大小和编址方式(操作数除了可以放在寄存器,还可以放在主存,规定了主存空间最大多大,规定了主存地址的位数(和存储空间大小相关), 在计算机中,编址方式是指对各种存储设备进行编码的方式(每按8位一个编码还是每16位一个号码等等));
- 操作数在存储空间存放时按照大端还是小端方式存放;
【提问】用通俗的语言解释一下何为大端模式和小端模式,并举出容易理解的简单的例子。
【chatGPT回答】大端模式和小端模式是计算机内部存储数据时的两种不同方式。这两种模式主要区别在于数据的存储顺序是从高位到低位还是从低位到高位的问题。其中,大端模式也被称为网络字节序,而小端模式则被称为主机字节序。
在大端模式下,数据的高位字节存储在内存的低地址处,低位字节存储在高地址处。而在小端模式下,数据的低位字节存储在内存的低地址处,高位字节存储在高地址处。举个例子来说,假设我们要存储二进制数10101110到内存中,那么这两种模式对于存储顺序的不同表现如下:
大端模式的存储顺序为:1010 1110
小端模式的存储顺序为:1110 1010
可以看到,在大端模式下,高位字节1010存储在了内存的低地址处,而在小端模式下,低位字节1110存储在了内存的低地址处。在实际应用中,这种模式的区别主要体现在网络通信和硬件设备之间的数据交换中。
简单来说,大端模式和小端模式是计算机在处理数据时,通过不同的方式进行存储的模式。大端模式是高位字节在内存低地址处,而小端模式则是低位字节在内存低地址处。因此,在同一数据的两种模式下存储在内存中的字节序列是不同的。
- 指令获取操作数的方式,即寻址方式;
【提问】用通俗的语言介绍一下何为寻址方式。
【chatGPT回答】寻址方式是计算机中用于指定操作数存储位置的方式。在执行指令之前,CPU需要将操作数从内存中读出来,然后进行操作。寻址方式就是为寻找内存中的操作数提供了一种规则和方法。
常见的寻址方式包括:立即寻址、直接寻址、间接寻址、寄存器寻址、寄存器间接寻址、相对寻址等。不同的寻址方式对应着不同的指令格式和对内存的访问方式。
举个例子来说明,假设现在需要对内存中的两个数进行加法运算,寻址方式可以解决如何告诉处理器两个操作数的位置。一个利用直接寻址的加法指令,需要提供一个内存地址作为操作数的存储位置。另一个利用立即寻址的加法指令,需要提供一个值,作为直接操作数使用。一些采用寄存器寻址的指令将使用寄存器中的值,而依据相对寻址方式计算操作数的地址,并把它加载到某个寄存器中。
总之,寻址方式是一种规则和方法,用于指定操作数的存储位置,常用的寻址方式包括立即寻址、直接寻址、间接寻址、寄存器寻址、寄存器间接寻址、相对寻址等。选择合适的寻址方式,可以提高计算机程序的执行速度和效率。
- 指令执行过程的控制方式,包括程序计数器(PC)、条件码定义等。
【提问】用通俗的语言解释一下何为条件码,什么是条件码定义。
【chatGPT回答】条件码是由CPU在执行运算过程中计算得到的一组标志位,用来保存运算结果是否为零、是否小于零、是否发生进位等信息。也被称作标志寄存器或者状态寄存器。这些标志位可以用来判断运算结果的正负和是否为零,从而控制处理器的分支和条件执行的流程。
一个典型的条件码包括零标志位(ZF)、进位标志位(CF)、符号标志位(SF)、调整位(AF)和溢出标志位(OF)。其中,ZF和SF分别表示运算结果是否为零和是否为负数。如果运算结果为零,ZF标志位就被设置为1,否则为0;对于负数,SF标志位就被设置为1,否则为0。而CF则表示是否发生了进位,AF表示较低的四位中是否发生了进位。OF用来表示是否溢出。
这些标志位的设置是由CPU在执行指令时控制的,通过这些标志位,CPU可以根据结果判断是否需要进一步进行计算或者执行其他操作。
总之,条件码是CPU中的一组标志位,用来保存运算结果是否为零、是否小于零、是否发生进位等信息。这些标志位用来判断运算结果的正负和是否为零,以控制流程的分支和条件执行。控制这些标志位的设置,可以帮助计算机执行正确的操作,提高程序的性能和准确性。
ISA在通用计算机系统中是必不可少的一个抽象层,没有它,软件无法使用计算机硬件;没有它,一台计算机不能称为“通用计算机”.(用指令实现各种各样的功能,这个“各种各样”即“通用”二字的含义)
ISA和计算机组成(微结构)之间的关系
不同ISA规定的指令集不同,如,IA-32、MIPS、ARM等,计算机组成必须能够实现ISA规定的功能,如提供GPR、标志、运算电路等,同一种ISA可以有不同的计算机组成,如乘法指令可用ALU(用若干次加法实现乘法)或乘法器实现,所以ISA是计算机组成的抽象。
W1-教材内容补充1 计算机系统性能瓶颈
计算机性能的定义
- 吞吐率(throughput):吞吐率表示在单位时间内所完成的工作量。
- 响应时间(response time):响应时间是指从作业提交开始到作业完成所用的时间。
- 带宽(bandwidth):带宽表示单位时间内所传输的信息量。
- 执行时间(execution time)和等待时间(latency):它们都是用来表示一个任务所用时间的度量值。
不同应用场合下,计算机用户所关心的性能是不同的。
计算机性能的测试
操作系统在对处理器进行调度时,一段时间内往往会让多个程序(更准确地说是进程)轮流使用处理器。
- CPU时间:CPU时间指CPU用于本程序执行的时间它分为用户CPU时间和系统CPU时间。
- 用户CPU时间:指真正用于运行用户程序代码的时间。
- 系统CPU时间:指为了执行用户程序而需要CPU运行操作系统程序的时间。
- 其他时间:指等待I/O操作完成的时间或CPU用于执行其他用户程序的时间。
- 系统性能:系统性能是指系统的响应时间,它与CPU外的其他部分也有关系。
- CPU性能:CPU性能是指用户CPU时间,它只包含CPU运行用户程序代码的时间。
在对CPU时间进行计算时需要用到一下几个重要的概念和指标:
- 时钟周期:计算机执行一条指令的过程被分成若干步骤(微操作)来完成,每一步都要有相应的控制信号进行控制,这些控制信号何时发出、作用时间多长,都要有相应的定时信号进行同步。因此,计算机必须能够产生同步的时钟定时信号,也就是CPU的主脉冲信号,其宽度称为时钟周期( clock cycle,tick ,clock tick ,clock )。
- 时钟频率:CPU的主频就是CPU中的主脉冲信号的时钟频率 ( clock rate),是CPU时钟周期的倒数。
- CPI(Cycles Per instruction):CPI表示执行一条指令所需的时钟周期数。
计算机性能计算公式
-
用户
C
P
U
时间
=
程序总时钟周期数
时钟频率
=
程序总时钟周期数
×
时钟周期
用户CPU时间=\frac{程序总时钟周期数}{时钟频率}=程序总时钟周期数\times 时钟周期
用户CPU时间=时钟频率程序总时钟周期数=程序总时钟周期数×时钟周期
反过来推导有如下公式:
程序总时钟周期数 = 用户 C P U 时间 × 时钟频率 程序总时钟周期数=用户CPU时间\times 时钟频率 程序总时钟周期数=用户CPU时间×时钟频率
时钟频率 = 程序总时钟周期数 用户 C P U 时间 时钟频率=\frac{程序总时钟周期数}{用户CPU时间} 时钟频率=用户CPU时间程序总时钟周期数 - 如果已知程序总指令条数和综合CPI,则 程序总时钟周期数 = 程序总指令数 × C P I 程序总时钟周期数=程序总指令数\times CPI 程序总时钟周期数=程序总指令数×CPI
- 如果已知程序中有n种不同类型的指令,第i种指令的条数和CPI分别为 C i C_{i} Ci和 C P I i CPI_{i} CPIi,则 程序总时钟周期数 = ∑ i = 1 n ( C P I i × C i ) 程序总时钟周期数=\sum\limits_{i=1}^{n}(CPI_{i}\times C_{i}) 程序总时钟周期数=i=1∑n(CPIi×Ci)
- 程序的综合CPI也可由以下公式求得,其中, F i F_{i} Fi表示第i种指令在程序中所占的比例。 C P I = ∑ i = 1 n ( C P I i × F i ) = 程序总时钟周期数 程序总指令条数 CPI=\sum\limits_{i=1}^{n}(CPI_{i}\times F_{i})=\frac{程序总时钟周期数}{程序总指令条数} CPI=i=1∑n(CPIi×Fi)=程序总指令条数程序总时钟周期数
计算机的性能可以看成是用户CPU时间的倒数,计算机M1的速度是计算机M2的速度的n倍,也就是说,在M2上执行程序的时间是在M1上指向时间的n倍。
对教材例1.1、例1.2的详细说明:
【例1.1】假设某个频繁使用的程序Р在机器M1上运行需要10秒,M1 的时钟频率为2GHz。设计人员想开发一台与M1具有相同ISA的新机器M2。采用新技术可使M2的时钟频率增加,但同时也会使CPI增加。假定程序Р在M2上的时钟周期数是在M1上的1.5倍,则M2的时钟频率至少达到多少才能使程序P在M2上的运行时间缩短为6秒?
【解】某个频繁使用的程序Р在机器M1上运行需要10秒,即该程序在M1上的用户CPU时间为10s,所以:
M
1
的程序总时钟周期数
=
M
1
的用户
C
P
U
时间
×
M
1
的时钟频率
=
10
s
×
2
G
h
z
=
10
s
×
2
×
1
0
9
h
z
=
20
×
1
0
9
h
z
=
20
G
M1的程序总时钟周期数=M1的用户CPU时间\times M1的时钟频率= 10s \times 2Ghz=10s\times 2 \times10^9hz=20 \times 10^9 hz=20G
M1的程序总时钟周期数=M1的用户CPU时间×M1的时钟频率=10s×2Ghz=10s×2×109hz=20×109hz=20G(Hz是时间的倒数)
由于Р在M2上的时钟周期数是在M1上的1.5倍
则
M
2
的程序总时钟周期数
=
1.5
×
20
G
=
30
G
M2的程序总时钟周期数=1.5\times 20G=30G
M2的程序总时钟周期数=1.5×20G=30G
若程序P在M2上的运行时间缩短为6秒,即程序P在M2上的用户CPU时间为6s,则:
M
2
的时钟频率
=
M
2
的程序总时钟周期数
M
2
的用户
C
P
U
时间
=
30
G
6
s
=
30
×
1
0
9
6
s
=
5
G
H
z
M2的时钟频率=\frac{M2的程序总时钟周期数}{M2的用户CPU时间}=\frac{30G}{6s}=\frac{30\times10^9}{6s}=5GHz
M2的时钟频率=M2的用户CPU时间M2的程序总时钟周期数=6s30G=6s30×109=5GHz
所以M2的时钟频率至少达到5GHz才能使程序P在M2上的运行时间缩短为6秒.
【结论】M2的时钟频率是M1的2.5倍,但M2的速度却只是M1的1.67倍,提高时钟频率不能保证CPU执行程序的速度有相同倍数的提高。
【例1.2】假设计算机M的指令集中包含A、B、C三类指令,其CPI分别为1、2、4。某个程序P在M上被编译成两个不同的目标代码序列P1和P2,P1所含A、B、C三类指令的条数分别为8、2、2,P2所含A、B、C三类指令的条数分别为2、5、3。请问:哪个代码序列总指令条数少?哪个执行速度快?它们的CPI分别是多少?
【解】(1)
P
1
所含指令条数
=
8
+
2
+
2
=
12
P1所含指令条数=8+2+2=12
P1所含指令条数=8+2+2=12,
P
2
所含指令条数
=
2
+
5
+
3
=
10
P2所含指令条数=2+5+3=10
P2所含指令条数=2+5+3=10,所以目标代码序列P2的指令条数少。
(2)根据公式
如果已知程序中有n种不同类型的指令,第i种指令的条数和CPI分别为 C i C_{i} Ci和 C P I i CPI_{i} CPIi,则 程序总时钟周期数 = ∑ i = 1 n ( C P I i × C i ) 程序总时钟周期数=\sum\limits_{i=1}^{n}(CPI_{i}\times C_{i}) 程序总时钟周期数=i=1∑n(CPIi×Ci)
则有:
P
1
的总时钟周期数
=
∑
i
=
1
3
(
C
P
I
i
×
C
i
)
=
1
×
8
+
2
×
2
+
4
×
2
=
20
,
(
C
1
=
P
1
(
A
)
,
C
2
=
P
1
(
B
)
,
C
3
=
P
1
(
C
)
)
P1的总时钟周期数=\sum\limits_{i=1}^{3}(CPI_{i}\times C_{i})=1\times 8+2\times 2+4\times 2=20, (C_{1}=P1(A),C_{2}=P1(B),C_{3}=P1(C))
P1的总时钟周期数=i=1∑3(CPIi×Ci)=1×8+2×2+4×2=20,(C1=P1(A),C2=P1(B),C3=P1(C))
P
2
的总时钟周期数
=
∑
i
=
1
3
(
C
P
I
i
×
C
i
)
=
1
×
2
+
2
×
5
+
4
×
3
=
24
,
(
C
1
=
P
2
(
A
)
,
C
2
=
P
2
(
B
)
,
C
3
=
P
2
(
C
)
)
P2的总时钟周期数=\sum\limits_{i=1}^{3}(CPI_{i}\times C_{i})=1\times 2+2\times 5+4\times 3=24, (C_{1}=P2(A),C_{2}=P2(B),C_{3}=P2(C))
P2的总时钟周期数=i=1∑3(CPIi×Ci)=1×2+2×5+4×3=24,(C1=P2(A),C2=P2(B),C3=P2(C))
P1与P2在同一台机器上运行,所以时钟周期一样,故总时钟周期数少的代码序列所用时间短、执行速度快,所以,P1比P2快
(3)根据公式
程序的综合CPI也可由以下公式求得,其中, F i F_{i} Fi表示第i种指令在程序中所占的比例。 C P I = ∑ i = 1 n ( C P I i × F i ) = 程序总时钟周期数 程序总指令条数 CPI=\sum\limits_{i=1}^{n}(CPI_{i}\times F_{i})=\frac{程序总时钟周期数}{程序总指令条数} CPI=i=1∑n(CPIi×Fi)=程序总指令条数程序总时钟周期数
下面P1的CPI按第一个公式算,P2的CPI按第二个公式算
由于P1的A、B、C三类指令的条数分别为8、2、2,则A类指令在程序中所占比例为
F
1
=
8
8
+
2
+
2
=
2
3
F_{1}=\frac{8}{8+2+2}=\frac{2}{3}
F1=8+2+28=32,B类指令在程序中所占比例为
F
2
=
2
8
+
2
+
2
=
1
6
F_{2}=\frac{2}{8+2+2}=\frac{1}{6}
F2=8+2+22=61,C类指令在程序中所占比例为
F
3
=
2
8
+
2
+
2
=
1
6
F_{3}=\frac{2}{8+2+2}=\frac{1}{6}
F3=8+2+22=61
P
1
的
C
P
I
=
∑
i
=
1
3
(
C
P
I
i
×
F
i
)
=
1
×
2
3
+
2
×
1
6
+
4
×
1
6
=
10
6
≈
1.67
P1的CPI=\sum\limits_{i=1}^{3}(CPI_{i}\times F_{i})=1\times\frac{2}{3}+2\times\frac{1}{6}+4\times\frac{1}{6}=\frac{10}{6}\approx1.67
P1的CPI=i=1∑3(CPIi×Fi)=1×32+2×61+4×61=610≈1.67
P
2
的
C
P
I
=
P
2
的总时钟周期数
P
2
的总指令条数
=
24
2
+
5
+
3
=
2.4
P2的CPI=\frac{P2的总时钟周期数}{P2的总指令条数}=\frac{24}{2+5+3}=2.4
P2的CPI=P2的总指令条数P2的总时钟周期数=2+5+324=2.4
【结论】指令条数少并不能代表执行时间短,时钟频率高也不说明执行速度快,要综合考虑多个因素来评价计算机的性能。
用指令执行速度进行性能评估
- MIPS(Million Instructions Per Second):指令速度所用的计量单位为MIPS,其含义是平均每秒执行多少百万条指令,其公式为:
M I P S = 指令数 执行时间 × 1 0 6 = 时钟频率 C P I × 1 0 6 MIPS=\frac{指令数}{执行时间\times10^{6}}=\frac{时钟频率}{CPI\times10^{6}} MIPS=执行时间×106指令数=CPI×106时钟频率 - MFLOPS(Million FLOating-point operations Per Second):与定点指令运行速度MIPS相对应的用来表示浮点操作速度的指标是MFLOPS或Mflop/s,它表示每秒所执行的浮点运算有多少百万次,它是基于所完成的操作次数而不是指令来衡量的。
- 早期还有一种类似于MIPS的性能估计方式,就是指令平均执行时间,也称等效指令速度法或Gibson混合法。设某类指令 i i i在程序中所占比例为 ω i \omega _{i} ωi,执行时间为 t i t_{i} ti,则等效指令的执行时间为: T = ω 1 × 1 + ω 2 × 2 + . . . + ω n × n T=\omega_{1}\times_{1}+\omega_{2}\times_{2}+...+\omega _{n}\times_{n} T=ω1×1+ω2×2+...+ωn×n( n n n为指令种类数)。若指令执行时间用时钟周期数来衡量的话,则上式计算的结果就是CPI。对指令平均执行时间求倒数就得到MIPS值。
- 峰值MIPS(peak MIPS):选取一组指令组合,使得得到的平均CPI最小,由此得到的MIPS就是峰值MIPS.
- 相对MIPS(relative MIPS):相对MIPS是根据某个公认的参考机型来定义的相应MIPS,其值的含义是被测机型相对于参考机型MIPS的倍数。
对教材的例1.3进行详细说明:
【例1.3】例1.3假定某程序Р编译后生成的目标代码由A、B、C、D四类指令组成,它们在程序中所占的比例分别为43% 、21%、12% 、24%,已知它们的CPI分别为1、2、2、2。现重新对程序Р进行编译优化,生成的新目标代码中A类指令条数减少了50%,其他类指令的条数没有变。请回答下列问题。
(1)编译优化前后程序的CPI各是多少?
(2)假定程序在一台主频为50MHz的计算机上运行,则优化前后的 MIPS各是多少?
【解】(1)
由于生成的新目标代码中A类指令条数减少了50%,则A类指令现在所占比例为
43
%
2
=
21.5
%
\frac{43\%}{2}=21.5\%
243%=21.5%,重新计算A、B、C、D四类指令占比为:
A
类指令所占比例
=
21.5
%
21.5
%
+
21
%
+
12
%
+
24
%
≈
27
%
A类指令所占比例=\frac{21.5\%}{21.5\%+21\%+12\%+24\%}\approx27\%
A类指令所占比例=21.5%+21%+12%+24%21.5%≈27%
B
类指令所占比例
=
21
%
21.5
%
+
21
%
+
12
%
+
24
%
≈
27
%
B类指令所占比例=\frac{21\%}{21.5\%+21\%+12\%+24\%}\approx27\%
B类指令所占比例=21.5%+21%+12%+24%21%≈27%
C
类指令所占比例
=
12
%
21.5
%
+
21
%
+
12
%
+
24
%
≈
15
%
C类指令所占比例=\frac{12\%}{21.5\%+21\%+12\%+24\%}\approx15\%
C类指令所占比例=21.5%+21%+12%+24%12%≈15%
C
类指令所占比例
=
24
%
21.5
%
+
21
%
+
12
%
+
24
%
≈
31
%
C类指令所占比例=\frac{24\%}{21.5\%+21\%+12\%+24\%}\approx31\%
C类指令所占比例=21.5%+21%+12%+24%24%≈31%
根据公式
程序的综合CPI也可由以下公式求得,其中, F i F_{i} Fi表示第i种指令在程序中所占的比例。 C P I = ∑ i = 1 n ( C P I i × F i ) = 程序总时钟周期数 程序总指令条数 CPI=\sum\limits_{i=1}^{n}(CPI_{i}\times F_{i})=\frac{程序总时钟周期数}{程序总指令条数} CPI=i=1∑n(CPIi×Fi)=程序总指令条数程序总时钟周期数
优化前的
C
P
I
=
1
×
43
%
+
2
×
21
%
+
2
×
12
%
+
2
×
24
%
=
1.57
优化前的CPI=1\times43\%+2\times21\%+2\times12\%+2\times24\%=1.57
优化前的CPI=1×43%+2×21%+2×12%+2×24%=1.57
优化后的
C
P
I
=
1
×
27
%
+
2
×
27
%
+
2
×
15
%
+
2
×
31
%
=
1.73
优化后的CPI=1\times27\%+2\times27\%+2\times15\%+2\times31\%=1.73
优化后的CPI=1×27%+2×27%+2×15%+2×31%=1.73
(2)根据公式
M I P S = 指令数 执行时间 × 1 0 6 = 时钟频率 C P I × 1 0 6 MIPS=\frac{指令数}{执行时间\times10^{6}}=\frac{时钟频率}{CPI\times10^{6}} MIPS=执行时间×106指令数=CPI×106时钟频率
优化前的
M
I
P
S
=
时钟频率
C
P
I
×
1
0
6
=
50
M
H
z
1.57
×
1
0
6
=
50
×
1
0
6
H
z
1.57
×
1
0
6
≈
31.85
M
I
P
S
优化前的MIPS=\frac{时钟频率}{CPI\times10^{6}}=\frac{50MHz}{1.57\times10^{6}}=\frac{50\times10^{6}Hz}{1.57\times10^{6}}\approx31.85MIPS
优化前的MIPS=CPI×106时钟频率=1.57×10650MHz=1.57×10650×106Hz≈31.85MIPS
优化后的
M
I
P
S
=
时钟频率
C
P
I
×
1
0
6
=
50
M
H
z
1.73
×
1
0
6
=
50
×
1
0
6
H
z
1.73
×
1
0
6
≈
28.90
M
I
P
S
优化后的MIPS=\frac{时钟频率}{CPI\times10^{6}}=\frac{50MHz}{1.73\times10^{6}}=\frac{50\times10^{6}Hz}{1.73\times10^{6}}\approx28.90MIPS
优化后的MIPS=CPI×106时钟频率=1.73×10650MHz=1.73×10650×106Hz≈28.90MIPS
【结论】从MIPS数值来看,优化后程序执行速度反而变慢了,这显然是错误的,用MIPS数进行性能估计是不可靠的。
用基准程序进行性能评估
- 基准程序(benchmark):benchmark是进行计算机性能评测的一种重要工具。
- 现在有很多benchmark工具,比如AID64,娱乐大师(鲁大师),CPU-Z,电脑跑分软件都是benchmark类工具。
我现在用的平台如上图所示(CPU体质不好,超频超不上去)。各大视频网站有很多博主搞PC机DIY的,经常用这些跑分工具,但我觉得这玩意就图一乐,真生产力和游戏还得看实测。 - 也可以将执行时间进行归一化来得到被测试的机器相对于参考机器的性能,其公式为:
执行时间的归一化值 = 参考机器上的执行时间 被测机器上的执行时间 执行时间的归一化值=\frac{参考机器上的执行时间}{被测机器上的执行时间} 执行时间的归一化值=被测机器上的执行时间参考机器上的执行时间
Amdahl定律
- 阿姆达尔定律(Amadahl Law)是计算机系统设计方面重要的定量原则之一,1967年由IBM 360系列机的主要设计者阿姆达尔首先提出。阿姆达尔定律定了增强或加速部分部件而获得得整体性能的改进成都,它有两种表示形式:
改进后的执行时间 = 改进部分执行时间 改进部分的改进倍数 + 未改进部分执行时间 改进后的执行时间=\frac{改进部分执行时间}{改进部分的改进倍数}+未改进部分执行时间 改进后的执行时间=改进部分的改进倍数改进部分执行时间+未改进部分执行时间
整体改进倍数 = 1 ( 改进部分执行时间 改进部分倍数 ) + 未改进部分执行时间 = 1 改进后的执行时间 整体改进倍数=\frac{1}{(\frac{改进部分执行时间}{改进部分倍数})+未改进部分执行时间}=\frac{1}{改进后的执行时间} 整体改进倍数=(改进部分倍数改进部分执行时间)+未改进部分执行时间1=改进后的执行时间1 - 若 t t t表示改进部分执行时间比例, n n n为改进部分的改进倍数,则 1 − t 1-t 1−t为未改进部分执行时间比例,整体改进倍数为: p = 1 t n + 1 − t p=\frac{1}{\frac{t}{n}+1-t} p=nt+1−t1,当 1 − t = 0 1-t=0 1−t=0时,则最大加速比 p = n p=n p=n;当 t = 0 t=0 t=0时,最小加速比 p = 1 p=1 p=1;当 n → ∞ n\to \infty n→∞时,极限加速比 p → 1 1 − t p\to \frac{1}{1-t} p→1−t1,这就是加速比的上限。
对教材的例1.4进行详细说明:
【例1.4】假定计算机中的整数乘法器改进后可以加快10倍,若整数乘法指令在程序中占40% ,则整体性能可改进多少倍?若整数乘法指令在程序中所占比例达60%和90%,则整体性能分别能改进多少倍?
【解】(1)改进部分的改进倍数为10,由于整数乘法指令在程序中占40%,说明程序执行总时间中40%是整数乘法器所用,其他部件所用时间占60%,根据阿姆达尔定律可知:
整体改进倍数
=
1
(
0.4
10
)
+
0.6
=
1
改进后的执行时间
≈
1.56
整体改进倍数=\frac{1}{(\frac{0.4}{10})+0.6}=\frac{1}{改进后的执行时间}\approx1.56
整体改进倍数=(100.4)+0.61=改进后的执行时间1≈1.56
(2)若整数乘法指令在程序中所占比例达60%和90%,则整体改进倍数分别为:
x
1
=
1
(
0.6
10
)
+
0.4
=
1
改进后的执行时间
≈
2.17
x_{1}=\frac{1}{(\frac{0.6}{10})+0.4}=\frac{1}{改进后的执行时间}\approx2.17
x1=(100.6)+0.41=改进后的执行时间1≈2.17
x
2
=
1
(
0.9
10
)
+
0.1
=
1
改进后的执行时间
≈
5.26
x_{2}=\frac{1}{(\frac{0.9}{10})+0.1}=\frac{1}{改进后的执行时间}\approx5.26
x2=(100.9)+0.11=改进后的执行时间1≈5.26
【结论】从上述例子中可以看出,即使执行时间占总时间90%的高频使用部件加快了10倍,所带来的整体性能也只能加快5.26倍。想要改进计算机系统整体性能,不能仅加速部分部件,计算机系统整体性能还受慢速部件的制约。
【例】某程序在某台计算机上运行所需时间是100s,其中,80s用来执行乘法操作。要使该程序的性能是原来的5倍,若不改进其他部件而仅改进乘法部件,则乘法部件的速度应该提高到原来的多少倍?
【解】设乘法部件的速度应该提高到原来的
n
n
n倍,
n
n
n为自然数(改进部分的改进倍数),要使该程序的性能是原来的5倍(整体改进倍数),根据公式:
若 t t t表示改进部分执行时间比例, n n n为改进部分的改进倍数,则 1 − t 1-t 1−t为未改进部分执行时间比例,整体改进倍数为: p = 1 t n + 1 − t p=\frac{1}{\frac{t}{n}+1-t} p=nt+1−t1,当 1 − t = 0 1-t=0 1−t=0时,则最大加速比 p = n p=n p=n;当 t = 0 t=0 t=0时,最小加速比 p = 1 p=1 p=1;当 n → ∞ n\to \infty n→∞时,极限加速比 p → 1 1 − t p\to \frac{1}{1-t} p→1−t1,这就是加速比的上限。
整体改进倍数为:
p
=
5
=
1
t
n
+
1
−
t
=
1
80
n
+
1
−
80
p=5=\frac{1}{\frac{t}{n}+1-t}=\frac{1}{\frac{80}{n}+1-80}
p=5=nt+1−t1=n80+1−801
即
400
n
+
100
=
1
\frac{400}{n}+100=1
n400+100=1,这个方程显然得不到自然数的解,故得出结论,无论怎样对乘法部件进行改进,整体性能都不可能提高到原来的5倍。
W1-5 本课程的主要学习内容
后PC时代(2000年-现在)
- 后PC时代的特征:
(1)计算资源多样化,I/O设备无处不在,数据中心、PMD与PC等共存;
(2)软件和硬件协同设计(硬件、OS和编译器之间的关联更加密切)
(3)对应用程序员的要求更高:编写高效程序必需了解计算机底层结构;必需掌握并行程序设计技术和工具;应用问题更复杂,领域更广:气象、生物、医药、地质、天文等领域的高性能计算;Google、百度等互联网应用领域海量“大数据“处理;物联网(移动设备、信息家电等)嵌入式开发;银行、保险、证券等大型数据库系统开发和维护;游戏、多媒体等实时处理软件开发。
(大规模,分布式,多粒度并行,“并行”成为重要主题)
计算机系统抽象层的转换
- 计算机学科主要研究的是计算机系统各个不同抽象层的实现及其相互转换的机制。
- 计算机学科培养的应该主要是在计算机系统或在系统某些层次上从事相关工作的人才。
“计算机系统基础”课程内容概要
本课程有三大主题:
1、表示(Representation):
- 不同数据类型(包括带符号整数、无符号整数、浮点数、数组、结构等)在寄存器或存储器中如何表示和存储?
- 指令如何表示和编码(译码)?
- 存储地址(指针)如何表示?如何生成复杂数据结构中数据元素的地址?
2、转换(Translation):
- 高级语言程序对应的机器级代码是怎样的?如何转换并链接生成可执行文件?
3、执行控制流(Control flow):
- 计算机能理解的“程序”是如何组织和控制的?
- 如何在计算机中组织多个程序的并发执行?
- 逻辑控制流中的异常事件及其处理
- I/O操作的执行控制流(用户态→内核态)