第一章 计算机系统简介

作者: 橡树人 | 来源:发表于2020-10-09 22:16 被阅读0次

    学习目标

    • 描述组成一个计算机系统的基本组件,及这些组件之间相互关系;
    • 解释一个处理器执行一条指令的步骤;
    • 理解中断的概念,以及处理器要使用中断的原因;
    • 列举和描述一台典型的计算机存储层级
    • 能对多处理器结构和多核架构的基本特征进行解释;
    • 讨论局部性这一概念,并分析多级存储的性能问题。
    • 理解栈的操作,以及如何使用栈来支持函数调用和返回。

    因为操作系统不仅要利用一个或者多个处理器等硬件资源来为系统用户提供服务,还要代表用户来管理二级存储和I/O设备,所以在学习操作系统之前,对底层计算机硬件有一些理解是非常重要的。

    本章提供的是对计算机系统硬件的简介。虽然大部分的介绍是简短的,但是由于有些部分对本书后续的主题很重要,所以对这些部分的介绍是详细的。更进一步的主题,请参见附录C。

    1.1节 基本组成

    首先,从整体上看,一台计算机由处理器、内存、I/O模块等组件组成,其中每类组件都有一个或者多个模块。
    其次,这些组件之间要通过某种方式互相连接来实现计算机的主要功能,即执行程序,所以共有4类主要的结构组件:


    计算机组件整体视图.png
    • 处理器
      控制计算机的运行,执行数据处理功能;
    • 主内存
      存储数据和程序;
      主内存是易失的,即当电脑关机时,主内存的内容就丢失了;
      跟主内存相比,即使电脑关机了,磁盘存储的内容还保留着;
    • I/O组件
      在计算机和外部环境之间移动数据,这里的外部环境由各种设备组成,比如二级存储、通信设备、终端等;
    • 系统总线
      提供处理器、主内存、I/O模块之间的通信;

    处理器的功能之一就是跟主内存交换数据。为了实现这一功能,处理器通常利用两个内部寄存器:内存地址寄存器(记录的是下一次要读或写的内存地址)、内存缓冲寄存器(记录要写入内存的数据,或者接收从内存中读取的数据)。
    类似地,I/O地址寄存器记录的是特定的I/O设备,I/O缓冲寄存器用于I/O模块和处理器之间的数据交换。

    主内存是由按照顺序编号的地址组成的集合。每个地址包含一个位模式,其中该位模式可被解释为数据或者指令。

    I/O组件从外部设备转移数据到处理器和主内存,或者从处理器、主内存转移数据到外部设备。它包含内部缓冲区来暂时持有数据,直到数据能被发送。

    1.2节 微处理器的历史

    微处理器的发明带来了桌面级计算和手持计算。最初的微处理器在一个芯片上有一个处理器器。虽然最初的单芯片处理器要比多芯片处理器慢很多,但是微处理器一直在不断发展,且发展到了一个节点:由于其能在亚纳秒的时间内传输信息,所以微处理器现在比之前快多了。

    微处理器不仅成为了当前可用的最快的通用目的处理器,而且是多核处理,即每个芯片包含多个处理器,其中每个处理器有多级较大的缓存,且多个逻辑处理器共享每个核的执行单元。截止2010年,已经很常见了:一台笔记本电脑上有2个或者4个核,其中每个核有两个硬件线程,共有4个或者8个逻辑处理器。

    尽管处理器对大部分形式的计算提供了非常好的性能,但是对数值计算来说,性能需求是越来越高。GPU使用在超级计算机中使用的SIMD技术来对阵列数据提供高效地计算。GPU不再仅用来渲染高级图形,还用来通用的数值处理,比如游戏的物理计算或者大型表格的计算。同时,伴随着将功能强大的向量单元整合进入X86和AMD64系列的处理器中,CPU也获得可对阵列数据的处理能力。

    处理器和GPU并不现代PC计算故事的终点。
    还有DSP,可用于处理流式信号,比如音频或者视频;可嵌入I/O设备,比如调制解调器;可用在手持设备中。
    还有其他的特定计算设备跟CPU一起支持其他的标准计算,比如编解码声音和视频,或者提供对加密和安全的支持。
    还有Soc,是为了满足手持设备的需求开发的:在同一块芯片上,不仅有CPU、缓存,还有系统的其他组件,比如DSP、GPU、I/O设备、主内存等。

    1.3 执行指令

    处理器要执行的程序是由保存在内存中的指令组成的集合。
    指令处理的最简单形式是由两步组成:处理器一次从内存中读取多条指令,然后执行每条指令。
    程序的执行过程就是重复地进行指令获取和指令执行的过程。
    根据指令的不同,指令的执行可能包含若干步操作。

    一条指令的处理过程(读取指令和执行指令)就是一个指令周期

    一个指令周期分为指令获取阶段和指令执行阶段。

    程序执行什么时候停止?
    关闭处理器
    发生不可恢复的错误
    碰到了使处理器停止的程序指令

    在每次指令周期的开始,处理器从内存中获取一条指令。
    通常,程序计数器记录了下一条待获取的指令的地址。
    除非有其他的指示,否则在每次获取指令后,处理器会递增程序计数器,以便待会获取下一条指令。
    比如,考虑一台简化的计算机,它的每条指令占据16比特的字长。假设程序计数器的当期值是300,则处理器下一次要获取的指令位于地址300。在接下来的指令周期内,处理器一次获取地址为301、302、303等的指令。注意,这个序列可能会根据指令的依次解释而有所改变。

    获取到的指令被加载到指令寄存器IR中。
    指令包含描述处理器要执行的操作信息的比特位。
    处理器解释指令,执行所需的操作。

    通常,指令操作分为四类:

    • 处理器-内存指令
      数据可能是从处理器到内存,也可能是从内存到处理器;
    • 处理器-I/O指令
      数据通过在处理器和I/O模块之间传输,可能是从处理器传输到外围设备或者反过来。
    • 数据处理指令
      处理器可能对数据执行算术操作或者逻辑操作
    • 控制指令
      一条控制指令描述的是被改变的程序序列。比如处理器可能从地址149获取到了一条指令,该指令描述的是下一条指令在182。然后,处理器就设置PC为182。因此,在下一次指令获取阶段,下一条指令就是从地址182而不是150获取。

    考虑一个简单的例子:
    处理器包含一个数据寄存器,即累加器。
    指令和数据都是16位长。
    内存按照大小为16位的字长来组织。
    指令格式提供了4位用于操作码,共支持16种不同的操作码。操作码定义了处理器执行的操作类型。
    剩余的12位,共可直接访问2^{12}=4096个字长的地址。

    步骤1:PC的值为300,这是第一条指令的地址。该指令被加载到IR,并递增PC值为301。

    步骤2:在IR里的指令的前4位的值为1,表明:要从内存中加载数据到AC中。剩余的12位描述的是数据在内存中的地址,即940。

    步骤3:从地址301处获取下一条指令,并递增PC值为302。

    步骤4:在IR里的指令的前4位的值为5,表明要从内存中获取数据,并将其跟AC中的值相加。剩余的12位描述的是数据在内存中的地址。

    步骤5:从地址302处读取指令,并递增PC值为303。

    步骤6:在IR里的指令的前4位的值为2,表明要将AC中的值保存到内存中。剩余的12位描述的是往内存中写入的数据的地址,即941。

    1.4 中断机制

    几乎所有的计算机都会提供一种机制,来让其他模块(比如内存、I/O等)来中断处理器的正常执行。

    有哪些常见的中断?

    • 程序中断
      由指令执行而触发的条件生成,比如算术溢出、除0操作、尝试去执行一条非法的机器指令、引用超出用户合法的内存空间等。
    • 计时器中断
      由位于处理器内部的计时器生成;
      允许操作系统每隔固定时间执行某些操作;
    • I/O中断
      由I/O控制器生成;
      为了发送操作正常完成的信号,或者发送一大类错误条件的信号;
    • 硬件故障中断
      由一个故障生成,比如断电、存储分区错误等;

    为什么需要中断机制?
    主要是因为中断提供了一种提升处理器利用率的方式。比如,大部分I/O设备要比处理器慢的多。假设处理器使用两阶段的指令执行周期来传输数据给打印机。每次写操作之后,处理器必须暂停,在打印机追赶上处理器前一直处于空闲。这类处理器暂停的长度的数量级是数千个甚至数百万个指令周期。显然,这是在浪费处理器。

    看一个具体的例子:考虑一台有1GHz的PC,一秒钟大约能执行10^9条指令。一块典型的硬盘,转速是每分钟7200转,半磁道的旋转时间为4毫秒,比处理器满了400万倍。

    用户程序执行一系列跟处理交叉的写调用。
    流程是:处理1->写操作1->处理2->写操作2->处理3

    代码段1、代码段2、代码段3表示的是没有I/O的指令序列。
    写操作调用的是一个I/O例程,属于系统工具的一部分,将执行真正的I/O操作。
    这个I/O操作由3个部分组成:

    • 为真正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模块就给处理器发送一个中断请求信号。
    处理器的响应是暂停当前程序的执行;跳转到为该I/O设备服务的一个例程,即中断处理程序;等服务完该设备后,恢复被打断程序的执行。
    注意,中断可以发生在main程序的任何一个点,不仅仅是某一条特定指令。

    对用户程序来说,一个中断会暂停当前的正常执行序列。当中断处理结束后,重新恢复执行。

    因此,用户程序没必要包含任何处理中断的代码,由处理器和操作系统负责暂停用户程序并在同样的位置恢复用户程序。

    为了处理中断,需要在指令周期中加入中断阶段。

    在中断阶段,处理器会检查是否有中断发生,即是否有中断信号。如果没有待处理的中断,则处理器进入指令读取阶段,开始读取当前程序的下一条指令。如果有未决的中断,则处理器暂停当前程序的执行,执行中断处理例程。中断例程会判断中断的类型,执行所需的操作。当中断处理程序执行结束后,处理器能在中断点处恢复用户程序的执行。
    注意:中断处理例程通常是操作系统的一部分。

    在我们的示例中,中断处理例程判断是由哪个I/O模块生成了中断,可能会跳转到一个程序,该程序会将更多的数据写入到该I/O模块。

    显然,在这个过程中有一些开销。比如,必须要执行额外的指令来判断中断的类型和确定合适的操作。

    跟简单地等待I/O操作浪费的时间相比,使用中断机制后,处理器的利用率会更高

    中断处理

    1. 设备控制器或者其他系统硬件发布一个中断
    2. 处理器完成当前指令的执行
    3. 处理器发送中断确认信号
    4. 处理器将PSW和PC压入栈
    5. 基于中断,处理器加载新的PC值
    6. 保存剩余的进程状态信息
    7. 中断处理程序处理进程中断
    8. 恢复进程状态信息
    9. 恢复旧的PSW和PC

    在中断处理过程中,需要保存被中断程序的哪些状态信息?如何保存?

    • 处理器负责将被打断进程的PSW和PC值压入栈中保存;
    • 中断处理程序负责将处理器的所有寄存器值,及其他状态信息压入栈中保存;

    由于中断的发生是不可预测的,可以在任何时候发生,可以在用户程序执行的任何点发生,所以为了供以后恢复使用,保存有关被中断程序的所有状态信息是重要的。

    相关文章

      网友评论

        本文标题:第一章 计算机系统简介

        本文链接:https://www.haomeiwen.com/subject/mzprpktx.html