计算机系统漫游
前言
这是学习深入理解计算机系统(Computer Systems A Programmer’s Perspective)的第一章的总结。
C语言程序Hello World是怎么执行的
1. 在虚拟机中新建一个hello.c文件
cd /home
mkdir learnCSPP
cd learnCSPP
vim hello.c
# 编辑hello.c的内容如下:
#include <stdio.h>
int main()
{
printf("hello,world\n");
return 0;
}
2. hello.c的编译流程详解
编译命令如下:
gcc -o hello hello.c
执行完编译命令,会发现在当前目录(/hello/learnCSPP)下多了一个可执行文件hello。
这里hello.c程序的实际编译流程如下:
hello.c编译成可执行文件hello其实经历了4个阶段:
预处理阶段
预处理器会根据以字符#开头的命令,修改源程序。第一行的内容,就是告诉预处理器将stdio.h中的内容插入源代码中,这样就得到了另外一个程序hello.i。
编译阶段
编译器会将hello.i翻译成hello.s,这里的hello.s其实是一个汇编语言程序。
汇编阶段
汇编器会将hello.s翻译成机器语言指令,这些机器语言指令是以二进制的形式存储在hello.o中。
链接阶段
hello.c程序中调用了printf函数。它是标准C库中的一个函数,存放在一个名为printf.o的预编译好的目标文件中。链接器会将printf.o合并到hello.o中,并生成一个可执行文件hello。
3. 运行可执行文件hello
# hello是一个可执行文件,直接在shell中输入它的文件名即可
./hello
# 这里会输出 hello,world
shell是一个命令行解释器。如果输入该命令行的第一个单词不是shell的内置命令,它会将其当做一个可执行文件,进行加载并运行。因此这里会输出 hello,world。
系统硬件结构
一个典型系统的硬件组成如下:
总线
这里的总线包括I/O总线、系统总线、内存总线。它是一组贯穿整个系统的电子管道,负责系统中各个部件的信息字节的传递。
I/O设备
这里的I/O设备包括鼠标、键盘、显示器、磁盘。它是系统与外部世界的联系通道,每个I/O设备都是通过控制器或适配器与I/O总线相连。控制器和适配器的区别主要在于它们的封装方式。控制器是I/O设备或系统主板上的芯片组,而适配器就是一块插在主板插槽上的卡。
主存
主存是一个临时存储设备,在处理器执行程序时,用来存放程序和程序处理的数据。从物理来说,它由一组动态随机存取存储器芯片组成。从逻辑来说,它是一个线性的字节数组。
处理器
中央处理单元即处理器,是解释(或执行)主存中指令的引擎。处理器的核心是一个大小为一个字的存储设备(寄存器),称为程序计算器(PC)。在任何时刻,PC都指向主存中的某条指令。
从系统通电开始,直到系统断电,处理器会一直不断地执行程序计算器指向的指令,然后再更新程序计算器,使其指向下一个指令。如以下指令CPU进行的操作:- 加载:从主存复制一个字节或一个字到寄存器,以覆盖寄存器原来的内容。
- 存储:从寄存器复制一个字节或一个字到主存的某个位置,以覆盖这个位置上的内容。
- 操作:把两个寄存器中的内容复制到ALU,ALU对这两个字做算术运算,并将结果保存到一个寄存器中,以覆盖该寄存器中原来的内容。
- 跳转:从指令本身中抽取一个字,并将这个字复制到程序计算器中(PC)中,以覆盖PC中原来的值。
从硬件层次来看系统是如何运行可执行文件hello
- 在键盘中输入”./hello”,shell程序会将字符逐一读入寄存器,再把它存放在主存中。
- 当我们敲下回车键,shell程序知道我们已经结束了命令的输入。shell会执行一系列命令来加载可执行的hello文件,将hello目标文件中的代码和数据从磁盘复制到主存中。数据包括最终会输出的字符串“hello,wrold\n”。利用直接存储器存储技术(DMA),数据可以不通过处理器而直接从磁盘复制到主存中。
- 目标文件hello中的代码和数据加载到主存后,处理器会开始执行hello程序main程序中的机器语言指令。这些指令最终会将“hello,wrold\n”字符串中的字节从主存复制到寄存器文件中,再从寄存器文件复制到显示设备,即显示在屏幕上。
高速缓存
从hello程序的运行可以看出,系统花费了大量的时间进行信息的挪移。如数据字符串“hello,wrold\n”开始在磁盘,会被复制到主存,再复制到显示设备上。这些复制操作都是开销。高速缓存的意义,就是减少这些复制操作的开销。
根据机械原理,较大的存储设备要比较小的存储设备运行慢,同一类型的存储设备运行快的造价远高于运行慢的造价。如:一个典型系统上的磁盘驱动器可能比主存大1000倍,但对于CPU而言,从磁盘驱动器中读取一个字的时间要比从主存中读取的开销大1000万倍。一个典型的寄存器文件只能存几百字节的信息,而主存可存储几十亿字节的信息,但CPU从寄存器中读数据要比从主存中读取快100倍。
例如:处理器级别的高速缓存存储器(cache memory),可以理解为:在寄存器与主存间,加一个比寄存器存储空间大、比从主存读取数据速度快的设备。
高速缓存结构图如下:
其中心思想:上一层存储器作为下一层存储器的高速缓存。我们常讲的CPU三级缓存,就是在寄存器(L0)与主存间(L4),还有L1、L2、L3三种存储器。
操作系统管理硬件
上例的hello程序是无法之间访问计算机的键盘、显示器、磁盘或主存的。它是依靠操作系统提供的服务才能运行的。操作系统的功能:防止硬件被失控的应用滥用;向应用程序提供简单一致的机制来控制庞复杂而又大不相同的低级硬件设备。
- 计算机系统中的抽象概念
进程,是对操作系统上一个正在运行的程序的抽象。一个系统能同时运行几个程序,操作系统会让每个程序看起来就像在独享处理器、主存和I/O设备。
并发运行,就是一个进程的指令与另外一个进程的指令交错执行,让用户觉得这两个应用在同时进行。操作系统实现这中交错执行的机制称为上下文切换。
操作系统会保存进程运行时所需的所有状态信息。这种状态,成为上下文,包括PC和寄存器文件当前的值,以及主存中的内容。在任何一个时刻,单处理器都只能执行一个进程的代码。当操作系统准备将控制权从当前进程转移到一个新进程时,会进行上下文切换,即保存当前进程的上下文,恢复新进程的上下文,然后将控制权交给新进程。新进程就会从上次停止的地方开始。
详情可见下图:
Amdahl定律
当我们对系统的某个部分进行性能优化时,其对整体性能的影响取决于该部分的重要性和加速程度。
一个系统执行某个应用程序的时间为T0,假设系统某部分所需执行时间占T0的比例为a,该部分性能提升比例为k。则现在该系统执行该应用程序的总时间为:T1=(1-a)*T0+a*T0/k。则加速比为T0/T1。