第1章 计算机系统漫游
1.1 信息就是位+上下文
- hello程序的声明周期是从一个源程序开始的,即程序员通过编辑器创建并保存的文本文件,文件名是hello.c
- 像hello.c这样只由ASII字符构成的文件称为文本文件,所有其它文件被称为二进制文件
- 区别不同数据对象的唯一方法就是我们读到这些数据对象时的上下文。比如,在不同的上下文中,一个同样的字节序列可能表示一个整数、浮点数、字符串或者机器指令
1.2 程序被其他程序翻译成不同的格式
- 在Unix系统上,从源文件到目标文件的转化是由编译器驱动程序完成的
- GCC编译器驱动程序读取源程序文件hello.c,并把它翻译成一个可执行目标文件hello,这个翻译过程可分为四个阶段完成。执行这四个阶段的程序(预处理器,编译器,汇编器,链接器)一起构成了编译系统
- 预处理阶段:预处理器根据以字符#开头的命令,修改原始的C程序。比如hello.c中第一行的#include<stdio.h>命令告诉预处理器读取系统头文件stdio.h的内容,并把它直接插入到程序文本中,结果就得到了另一个C程序,通常是以.i作为文件扩展名
- 编译阶段:编译器将文本文件hello.i翻译成文本文件hello.s,它包含一个汇编语言程序,该程序包含函数main的定义
- 汇编阶段:接下来,汇编器将hello.s翻译成机器语言指令,把这些指令打包成一种叫做可重定位目标程序的格式,并将结果保存在目标文件hello.o中。它是一个二进制文件。
- 链接阶段:printf函数存在于一个名为printf.o的单独的预编译好了的目标文件中,而这个文件必须以某种方式合并到我们的hello.o程序中,链接器负责这种合并,结果得到hello文件,它是可执行目标文件,可以被加载到内存中,由系统执行
1.3 了解编译系统如何工作是大有益处的
- 有一些重要的原因促使程序员必须知道编译系统是如何工作的:优化程序性能,理解链接时出现的错误,避免安全漏洞
1.4 处理器读并解释储存在内存中的指令
- shell是一个命令行解释器,它输出一个提示符,等待输入一个命令行,然后执行这个命令。如果这个命令行的第一个单词不是一个内置的shell命令,那么shell就会假设这是一个可执行文件的名字,它将加载并运行这个文件,等待程序终止,shell随后输出一个提示符,等待下一个输入的命令行
1.4.1 系统的硬件组成
- 一个典型的硬件组织
- 总线:通常总线被设计为传送定长的字符快,也就是字。字中的字节数是一个基本的系统参数,各个系统不尽相同
- IO设备:每个IO设备通过一个控制器或适配器与IO总线相连。控制器和适配器之间的区别主要在于它们的封装方式。控制器是IO设备本身或者系统的主印刷电路板(主板)上的芯片组。而适配器则是一块插在主板插槽上的卡。功能都是在IO总线和IO设备之间传递信息
- 主存:从物理上来说,主存是由一块动态随机存取存储器(DRAM)芯片组成的。从逻辑上来说,存储器是一个线性的字节数组,每个字节都有唯一的地址,这些地址是从零开始的。一般来说,组成程序的每条机器指令都由不同数量的字节构成
- 处理器:处理器的核心是一个大小为一个字的存储设备,称为程序计数器(PC)。在任何时候,PC都指向主存中的某条机器语言指令。寄存器文件是一个小的存储设备,由一些单个字长的寄存器组成,每个寄存器都有唯一的名字。处理器看上去是它的指令集架构的简单实现,但是实际上现代处理器使用了非常复杂的机制来加速程序的执行。因此,我们将处理器的指令集架构和处理器的微体系结构区分开:指令级架构描述的是每条机器代码指令的效果,微体系结构描述的是处理器实际上是如何实现的
1.4.2 运行hello程序
- 初始时,shell程序执行它的指令,等待我们输入一个命令。当我们在键盘上输入字符串“./hello”后,shell程序将字符逐一读入寄存器,再把它存放到内存中
- 当我们在键盘上敲回车键时,shell程序就知道我们已经结束了命令的输入。然后shell执行一系列指令来加载可执行的hello文件,这些指令将hello目标文件中的代码和数据从磁盘复制到主存。
- 一旦目标文件hello中的代码和数据被加载到主存,处理器就开始执行hello程序的main程序中的机器语言指令。这些指令将“hello,world\n”字符串中的字节从主存复制到寄存器文件,再从寄存器文件中复制到显示设备,最终显示出来。
1.5 高速缓存至关重要
- L1和L2高速缓存是用一种叫做静态随机访问存储器(SRAM)的硬件技术实现的。
- 系统可以获得一个很大的存储器,同时访问速度也很快,原因是利用了高速缓存的局部性原理,即程序具有访问局部区域里的数据和代码的趋势。通过让高速缓存里存放可能经常访问的数据,大部分的内存操作都能在快速的高速缓存中完成
1.6 存储设备形成层次结构
1.7 操作系统管理硬件
- 操作系统有两个基本功能:防止硬件被失控的应用程序滥用。向应用程序提供简单一致的机制来控制复杂而又通常大不相同的低级硬件设备。
- 操作系统通过几个基本的抽象概念(进程、虚拟内存和文件)来实现这两个功能
- 文件是对IO设备的抽象表示
- 虚拟内存是对主存和磁盘IO设备的抽象表示
- 进程是对处理器、内存和IO设备的抽象表示
1.7.1 进程
- 操作系统保持跟踪进程所需的所有状态信息。这种状态,也就是上下文,包括许多信息,比如PC和寄存器文件的当前值,以及主存的内容。在任何一个时刻,单处理器系统都只能执行一个进程的代码。当操作系统决定要把控制权从当前进程转移到某个新进程时,就会进行上下文切换,即保存当前进程的上下文,恢复新进程的上下文,然后将控制权传递到新进程。新进程会从它上次停止的地方开始
- shell进程和hello进程:最开始只有shell进程在运行,即等待命令行上的输入,当我们让它运行hello程序时,shell通过调用一个专门的函数,即系统调用,来执行我们的请求,系统调用会将控制权传递给操作系统,操作系统保存shell进程的上下文,创建一个新的hello进程及其上下文,然后将控制权传给hello进程。hello进程终止后,操作系统恢复shell进程的上下文,并将控制权传回给它,shell进程会继续等待下一个命令行输入
1.7.2 线程
1.7.3 虚拟内存
- 虚拟内存是一个抽象的概念,它为每个进程提供了一个假象,即每个进程都在独占使用主存,每个进程看到的内存都是一致的,称为虚拟地址空间
- 简单了解每一个区
- 程序代码和数据。对于所有进程来说代码是从固定地址开始的,紧接着的是和C全局变量对应的数据位置。代码和数据区是直接按照可执行目标文件的内容初始化的,在示例中就是可执行文件hello
- 堆。代码和数据区后紧跟着的是运行时堆,代码和数据区在进程一开始运行时就被指定了大小,与此不同,当调用像malloc和free这样的函数时,堆可以在运行时动态的扩展和收缩
- 共享库。大约在地址空间的中间部分是一块用来存放像C标准库和数学库这样的共享库的代码和数据的区域
- 栈。位于用户虚拟地址空间顶部的是用户栈,编译器用它来实现函数调用,也可以动态扩展和收缩,特别的,每次调用一个函数时,栈会增长,从一个函数返回时,栈会收缩
- 内核虚拟内存。
1.7.4 文件
- 文件就是字节序列。每个IO设备,包括磁盘,键盘,显示器,甚至网络都可以看出文件。系统中所有的输入输出都是通过使用一小组称为Unix I/O的系统函数调用读写文件来实现的。
1.8 系统之间利用网络通信
- 从一个单独的系统来看,网络可视为一个IO设备,当系统从主存复制一串字节到网络适配器时,数据流经网络到达另一台机器,而不是比如说本地磁盘驱动器。相似的,系统可以读取从其他机器发送来的数据,并把数据复制到自己的主存
- 回到hello示例,我们可以使用熟悉的Telnet应用在一个远程主机上运行hello程序。假设用本地主机上的Telnet客户端连接远程主机上的Telnet服务器。在我们登录到远程主机并运行shell后,远端的shell就在等待接收输入命令
- 当我们在Telnet客户端输入“hello”字符串并敲下回车键后,客户端软件就会将这字符串发送到Telnet服务器。服务器从网络接收到后,传递给shell程序,远端shell运行程序,Telnet服务器将结果转发给Telnet客户端,客户端最终输出到本地终端
1.9 重要主题
1.9.1 Amdahl定律
- 该定律的主要思想是,当我们对系统的某个部分加速时,其对系统整体的性能的影响取决于该部分的重要性和加速程度。若以前执行需要
T
o
l
d
T_{old}
Told?。某部分所需执行时间占总时间的比例是
α
\alpha
α,而该部分性能提升比例是k,即该部分初始所需时间时
α
T
o
l
d
\alpha T_{old}
αTold?,现在所需的时间为
(
α
T
o
l
d
)
/
k
(\alpha T_{old})/k
(αTold?)/k。因此,总的执行时间为
T
n
e
w
=
(
1
?
α
)
T
o
l
d
+
(
α
T
o
l
d
)
/
k
=
T
o
l
d
[
(
1
?
α
)
+
α
/
k
]
T_{new} = (1-\alpha)T_{old} + (\alpha T_{old})/k=T_{old}[(1-\alpha)+\alpha/k]
Tnew?=(1?α)Told?+(αTold?)/k=Told?[(1?α)+α/k],由此可以计算出加速比
S
=
T
o
l
d
/
T
n
e
w
S=T_{old}/T_{new}
S=Told?/Tnew?为:
S
=
1
(
1
?
α
)
+
α
/
k
S= \frac{1} {(1-\alpha)+\alpha/k}
S=(1?α)+α/k1?。
- 该定律的主要观点——要想显著加速整个系统,必须提升全系统中相当大的部分的速度
1.9.2 并发与并行
1.9.3 计算机系统中抽象的重要性
虚拟机,它提供对整个计算机的抽象,包括操作系统、处理器和程序。
|