第一章 计算机系统漫游
简介:
我们通过跟踪hello程序的生命周期来开始对系统的学习—-从它被程序员创建开始,到在系统上运行,输出简单的消息,然后终止
我们将沿着这个程序的生命周期,简单得介绍一些逐步出现的关键概念、专业数据和组成部分
hello代码:
#include <stdio.h>int main(){printf("hello, workd\n");return 0;}
1.1、信息就是位+上下文
hello程序的生命周期从源程序开始
源程序:即源文件,程序员通过创建并保存的文本文件,文件名是hello.c
hello.c程序是以字节序列的方式存储在文件中的,其ASCII文本表示:
hello.c的表示方法说明一个基本思想:
程序中所有的信息—-包括磁盘文件、内存中的程序、内存中的数据及网络上传送的数据,都是一串比特表示的
区分不同数据对象的方法就是读取这些数据对象时的上下文
1.2、程序被其他程序翻译成不同的格式
为了在系统上运行hello.c程序,每条C语句都必须被其他程序转化为一系列的低级机器语言指令。然后这些指令按照一种称为可执行目标程序的格式打好包,并以二进制磁盘文件的形式存放起来。目标程序也称为可执行目标文件
在Unix系统上,从源文件到目标文件的转化是由编译器驱动程序完成的:
linux> gcc -o hello hello.c
在这里 GCC编译器驱动程序读取源程序文件hello.c,并把它翻译成一个可执行目标文件hello。这个翻译过程可以分为四个阶段完成:
预处理阶段:
cpp(预处理器)根据以字符#开头的命令,修改原始的C程序,比如hello.c中第1行的#include <stdio.h> 命令告诉预处理器读取系统头文件stdio.h的内容,并将它直接插入程序文本中。结果得到另一个C程序,通常是以.i作为文件扩展名
编译阶段(具体过程查看编译原理) :
编译器(ccl)将文本文件hello.i翻译成文本文件hello.s,它包含一个汇编语言程序。该程序包含函数main的定义,如下所示:
main:subq $8, %rspmovl $.LCO, %edicall putsmovl $0, %eaxaddq $8, %rspret
定义中2-7行每条语句都以一种文本格式描述了一条低级机器语言指令
汇编阶段
汇编器(as)将hello.s 翻译成机器语言指令,把这些指定打包成一种叫做 可重定位目标程序(relocateable object program)的格式,并将结果保存在目标文件hello.o中。hello.o是一个二进制文件,它包含的17个字节是函数main的指令编码
链接阶段
helloc程序调用的printf函数,这个是C编译器提供的标准C库中的一个函数,printf函数存在于一个名为printf.o的单独的预编译好了的目标文件中,这个文件必须以某种方式合并到我们的hello.o程序中,链接器(ld)就负责处理这种合并 得到可执行文件hello
1.3、了解编译系统如何工作是大有益处的
优化程序性能
为了在C程序中做出好的编码选择,我们需要了解一些机器代码以及编译器将不同的C语言转化为机器代码的方式,比如:
一个switch语句是否总比一系列的if-else语句高效的多?一个函数调用的开销有多大?while循环比for循环更有效吗?指针引用比数组索引更有效吗?为什么将循环求和的结构放到一个本地变量中,会比将其放到一个通过引用传递过来的参数中运行起来快很多呢?为什么我们只是简单地重新排列一下算数表达式中的括号,能让函数运行得更快?
理解链接时出现的错误
一些最令人困扰的程序错误往往都与链接器操作有关,尤其是你试图构建大型的软件系统时。
链接器提示无法解析一个引用,这是什么意思静态变量和全局变量的区别是什么如果在不同的C文件中定义了名字相同的两个全局变量会发生什么静态库和动态库的区别是什么我们在命令行上排列库的顺序有什么影响为什么有些链接错误指导运行时才会出现
避免安全漏洞
缓冲区溢出错误是造成大多数网络和Interner服务器上安全漏洞的主要原因。
存在这种错误是因为很少有程序员能够理解需要限制从不受信任的源接受数据的数量和格式
学习安全编程的第一步就是理解数据和控制信息存储在程序栈上的方式会引起的后果。
1.4、处理器读取并解释存储在内存中的指令
1.4.1、系统的硬件组成
1、总线:
贯穿真个系统的一组电子管道,称作总线,携带信息字节并负责在各个部件间传递。
总线分为:地址总线,数据总线,控制总线
2、I/O设备:
I/O设备是系统与外部世界的联系通道,示例中包含四个I/O设备:
作为用户输入的鼠标和键盘
作为用户输出的显示器
长期存储数据和程序的磁盘
每个I/O设备都通过一个控制器或适配器与I/O总线相连
控制器 是I/O设备本身或系统的主板上的芯片组
适配器是一块插在主板插槽上的卡
3、主存:
主存是一个临时存储设备,在处理器执行程序时,用来存放程序和程序处理的数据。
4、处理器:
中央处理单元(CPU),简称处理器,是解释(或执行)存储在主存中指令的引擎。
CPU在指令的要求下可能会执行这些操作:
加载
从主存复制一个字节或者一个字到寄存器,覆盖寄存器原来的内容
存储
从寄存器复制一个字节或字到主存的某个位置,覆盖这个位置上原来的内容
操作
把两个寄存器的内容复制到ALU,ALU对这两个字做算数运算,并将结果存放到一个寄存器中,覆盖寄存器原来的内容
跳转
从指令本身抽取一个字,并将这个字复制到程序计数器中,覆盖PC中原来的值
我们将处理器的指令集架构和处理器的微体系结构区分开:
指令集:每条机器代码指令的效果
微体系结构:处理器实际上是如何实现的
1.4.2、运行hello程序
当我们运行示例程序时到底发生了什么?
当我们在键盘上键入字符串"./hello"后,shell程序将字符逐一读入寄存器,再把它存放到内存中
当我们在键盘上敲回车时,shell执行一系列指令来加载可执行的hello文件,这些指令将hello目录文件中的代码和数据从磁盘复制到主存。
利用直接存储器存取,数据可以不通过处理器而直接从磁盘到达主存,步骤如下:
一旦目标文件hello中的代码和数据被加载到主存,处理器就开始执行hello程序的main程序中的机器语言指令。
这些指令将“hello world\n”字符串中的字节从主存复制到寄存器文件,再从寄存器文件复制到显示设备,最终显示在屏幕上:
1.5、高速缓存至关重要
这个示例揭示了一个重要问题:系统花费了大量的时间把信息从一个地方挪到另一个地方
从程序员的角度来看,这些复制就是开销,减慢了程序“真正”的工作。因此,系统设计者的一个重要目录就是使这些复制操作尽可能快地完成。
根据机械原理,较大的存储设备要比较小的存储设备运行得慢
随着半导体技术的进步,处理器与主存之间的差距还在持续增大。加快处理器的运行速度比加快主存的运行速度要容易和便宜得多。
针对这种处理器与主存之间的差异,系统设计者采用了更小更快的存储设备,称为高速缓存存储器(cache memory,简称cache),作为暂时的集结区域,存放处理器近期可能会需要的信息。
L1和L2高速缓存是用一种叫做静态随机访问存储器(SRAM)的硬件技术实现的
L1:
Cache(一级缓存)是CPU第一层高速缓存,分为数据缓存和指令缓存。内置的L1高速缓存的容量和结构对CPU的性能影响较大,不过高速缓冲存储器均由静态RAM组成,结构较复杂,在CPU管芯面积不能太大的情况下,L1级高速缓存的容量不可能做得太大。一般服务器CPU的L1缓存的容量通常在32—256KB。
L2:
L2 Cache(二级缓存)是CPU的第二层高速缓存,分内部和外部两种芯片。内部的芯片二级缓存运行速度与主频相同,而外部的二级缓存则只有主频的一半。L2高速缓存容量也会影响CPU的性能,原则是越大越好,现在家庭用CPU容量最大的是4MB,而服务器和工作站上用CPU的L2高速缓存更高达2MB—4MB,有的高达8MB或者19MB。
L3:
cache(三级缓存),分为两种,早期的是外置,现在的都是内置的。而它的实际作用即是,L3缓存的应用可以进一步降低内存延迟,同时提升大数据量计算时处理器的性能。降低内存延迟和提升大数据量计算能力对游戏都很有帮助。而在服务器领域增加L3缓存在性能方面仍然有显著的提升。比方具有较大L3缓存的配置利用物理内存会更有效,故它比较慢的磁盘I/O子系统可以处理更多的数据请求。具有较大L3缓存的处理器提供更有效的文件系统缓存行为及较短消息和处理器队列长度。
其实最早的L3缓存被应用在AMD发布的K6-III处理器上,当时的L3缓存受限于制造工艺,并没有被集成进芯片内部,而是集成在主板上。在只能够和系统总线频率同步的L3缓存同主内存其实差不了多少。后来使用L3缓存的是英特尔为服务器市场所推出的Itanium处理器。接着就是P4EE和至强MP。Intel还打算推出一款9MB L3缓存的Itanium2处理器,和以后24MB L3缓存的双核心Itanium2处理器。
但基本上L3缓存对处理器的性能提高显得不是很重要,比方配备1MB L3缓存的Xeon MP处理器却仍然不是Opteron的对手,由此可见前端总线的增加,要比缓存增加带来更有效的性能提升。
1.6、存储设备形成层次结构
1.7、操作系统管理硬件
操作系统有两个基本功能:
防止硬件被失控的应用程序滥用
向应用程序提供简单一致的机制来控制复杂而又通常大不相同的低级硬件设备
操作系统通过几个基本的抽象概念:
进程、虚拟内存和文件
1.7.1、 进程
进程是操作系统对一个正在运行的程序的一种抽象。在一个系统上可以同时运行多个进程,而每个进程都好像在独占得使用硬件而并发运行,则是说一个进程的指令和另一个进程的指令是交错执行的。
操作系统保持跟踪进程运行所需的所有状态信息。这种状态,也就是上下文,包括许多信息,比如PC和寄存器文件的当前值,以及主存的内容。
当操作系统决定要把控制权从当前进程转移到某个新进程时,就会进行上下文切换,即保存当前进程的上下文、恢复新进程的上下文,然后将控制权传递到新进程。新进程就会从它上次停止的地方开始
1.7.2、线程
现代系统中,一个进程实际上可以由多个称为线程的执行单元组成,每个线程都运行在进程的上下文中,并共享同样的代码和全局数据。
1.7.3、虚拟内存
虚拟内存是一个抽象概念,它为每个进程提供了一个假象,即每个进程都在独占得使用主存。每个进程看到的内存都是一致的,称为虚拟内存空间
从最低的地址开始,逐步向上介绍:
程序代码和数据
对所以的进程来说,代码是从同一固定开始,紧接着的是和C全局变量相对应的数据位置。代码和数据区是直接按照可执行目标文件的内容初始化的,在示例中就是可执行文件hello。
堆
紧随着代码和数据区后的是运行时堆
共享库
地址空间的中间部分用来存放C标准库和数学库这样的共享库的代码和数据
栈
位于用户虚拟地址空间顶部的是用户栈
内核虚拟内存
地址空间顶部的区域是为内核保留的
虚拟内存运作的基本思想是把一个进程虚拟内存的内容存储在磁盘上,然后用主存作为磁盘的高速缓存
1.7.4、文件
文件就是字节序列,每个I/O设备都可以看做是文件
1.8、系统之间利用网络通信
现代系统经常通过网络和其他系统连到一起。从单独的系统来看,网络可视为一个I/O设备
随着Internet这样的全球网络的出现,从一台主机复制信息到另一台主机已经成为计算机系统最重要的用途之一。
1.9、重要主题
1.9.1、Amdahl定律
若系统执行某应用程序需要时间为 T o l d T_{old} Told。假设系统某部分所需执行时间与改时间的比例为 a a a,而该部分性能提升比例为 k k k。即该部分初始所需时间为 a T o l d aT_{old} aTold,现在所需时间为 ( a T o l d ) / k (aT_{old})/k (aTold)/k。因此,总的执行时间应为:
T n e w = ( 1 − a ) T o l d + ( a T o l d ) / k = T o l d [ ( 1 − a ) + a / k ] T_{new} = (1-a)T_{old} + (aT_{old})/k = T_{old}[(1-a)+a/k] Tnew=(1−a)Told+(aTold)/k=Told[(1−a)+a/k]
由此,可以计算加速比 S = T o l d / T n e w S=T_{old}/T_{new} S=Told/Tnew为
S = 1 ( 1 − a ) + a / k S = \frac{1}{(1-a)+a/k} S=(1−a)+a/k1
1.9.2、并发和并行
并发:
是一个通用的概念,指一个同时具有多个活动的系统;
并行:
用并发来使一个系统运行得更快。并行可以在计算机系统的多个抽象层次上的运用。
1、线程级并发
我们能够设计出同时又多个程序执行的系统,使用线程,我们能够在一个进程中执行多个控制流、
在以前,即使处理器必须在多个任务间切换,大多数实际的计算也都是由一个处理器来完成的。这种配置称为单处理器系统。当构建一个由单操作系统内核控制的多处理器组成的系统时,我们就得到了一个多处理器系统。
多核处理器是将多个CPU(称为"核")集成到一个集成电路芯片上。
超线程,有时称为同时多线程,是一项允许一个CPU执行多个控制流的技术。它涉及CPU某些硬件有多个备份,比如程序计数器和寄存器文件,而其他的硬件部分只有一份,比如执行浮点算数运算的单元。
常规的处理器需要大约20 000个时钟周期做不同线程间的转换,而超线程的处理器可以在单个周期的基础上决定要执行哪一个线程
2、指令级并行
在降低的抽象层次上,现代处理器可以同时执行多条指令的属性称为指令级并行。如果处理器可以达到比一个周期一条指令更快的执行速率,就称之为超标量处理器。
3、单指令、多数据并行
在最低层次上,许多现代处理器拥有特殊的硬件,允许一条指令产生多个可以并行执行的操作,这种方式称为单指令、多数据,即SIMD并行。
1.9.3、计算机系统中抽象的重要性
抽象的使用时计算机科学中最为重要的概念之一。例如,为一组函数规定一个简单的应用程序接口(API)就是一个很好的编程习惯,程序员无须了解它内部的工作便可以使用这些代码。
在处理器里,指令集架构提供了对实际处理器硬件的抽象:
文件是对I/O设备的抽象
虚拟内存是对程序存储器的抽象
进程是对一个正在运行的程序的抽象
虚拟机提供对整个计算机的抽象,它包括操作系统、处理器和程序。
1.10、小结
如果觉得《【深入理解计算机系统-学习笔记】第一章 计算机系统漫游》对你有帮助,请点赞、收藏,并留下你的观点哦!