《深入理解计算机系统》第一章笔记

深入理解计算机系统

第一章 Hello World(计算机系统漫游)

#include<stdio.h>

int main()
{
    printf("hello world\n");
    return 0;
}

//通过跟踪hello程序的生命周期来开始对系统的学习

1.1 信息就是位+上下文

系统中所有的信息——包括磁盘文件、内存中的程序、内存中存放的用户数据以及网络上传送的数据,都是由一串**比特(位序列)**表示的。

区分不同数据对象的唯一方法是我们读到这些数据对象时的上下文。比如,在不同的上下文中,一个同样的字节序列可能表示一个整数、浮点数、字符串或者机器指令。

在这里插入图片描述

hello.c程序是以字节序列的方式储存在文件中的。每个字节都有一个整数值,对应某些字符。例如,第一个字节的整数值是35,它对应的就是字符“#”。第二个字节的整数值为105,它对应的字符是“i’,依此类推。注意,每个文本行都是以一个看不见的换行符\n来结束的,它所对应的整数值为10。

hello.c这样只由ASCII字符构成的文件称为文本文件,所有其他文件都称为二进制文件

1.2 程序被其他程序翻译成不同的格式(编译链接过程)

gcc -o hello hello.c
//将C形式的高级语言转化低级机器语言指令,打包成可执行目标程序的格式,然后以二进制磁盘文件的形式储存
编译系统

在这里插入图片描述

预处理—>编译—>汇编—>链接

  • 预处理

    a)删除所有的"#define",并且展开所有的宏定义;

    b)处理所有的条件预编译指令,#if,#ifdef,#endif等;

    c)处理"#include"预编译指令,将被包含的文件插入到该预编译指令的位置(直接复制);

    d)删除所有的注释;

    e)添加行号和文件名标识,以便于编译器产生调试用的符号信息及编译时产生编译错误和警告时显示行号;

    f)保留所有的#pragma编译器指令,因为编译器需要使用它们。

  • 编译

    词法分析,语法分析,语意分析,代码优化,汇总符号。

  • 汇编

    将汇编指令翻译成二进制格式,生成各个section,生成符号表。

  • 链接

    a)合并各个section,调整section的起始位置和段大小,合并符号表,进行符号解析,给符 号分配虚拟地址;

    b)符号重定位,即在使用符号的地方全部替换成符号的虚拟地址。

//预处理	cpp
hello.c--->hello.i
//编译	ccl
hello.i--->hello.s			//文本文件,包含一个汇编语言程序
//汇编	as
hello.s--->hello.o			//可重定位目标程序(二进制)
//链接	ld
hello.o+printf.o--->hello/hello.exe   //可执行目标程序(二进制)

1.4 处理器读并解释储存在内存中的指令

1.4.1 系统的硬件组成

在这里插入图片描述

  • 总线

    数据传输流,连接系统各个部分。

    贯穿整个系统的是一组电子管道,称作总线,它携带信息字节并负责在各个部件间传递。通常总线被设计成传送定长的字节块,也就是字(word)。字中的字节数(即字长)是一个基本的系统参数,各个系统中都不尽相同。现在的大多数机器字长要么是4个字节(32位),要么是8个字节(64位)。

  • I/O设备

    I/O(输入/输出)设备,连接系统与外部世界,例如:键盘、鼠标、显示器、磁盘。每个I/O设备都通过一个控制器或适配器与I/O总线相连。控制器和适配器之间的区别主要在于它们的封装方式。控制器是I/O设备本身或者系统的主印制电路板(通常称作主板)上的芯片组。而适配器则是一块插在主板插槽上的。无论如何,它们的功能都是在I/O总线和I/O设备之间传递信息。

  • 主存(内存)

    主存是一个临时存储设备,在处理器执行程序时,用来存放程序和程序处理的数据。

    物理:主存是由一组动态随机存取存储器(DRAM)芯片组成的。

    逻辑:存储器是一个线性的字节数组每个字节都有其唯一的地址(数组索引),这些地址是从零开始的。

  • 处理器(CPU)

    中央处理单元,简称处理器,是解释(或执行)存储在主存中指令的引擎。处器的核心是一个大小为一个字(通常为 32 位或 64 位)的存储设备(或奇存器),称为程序计数器(PC)。在任何时刻,PC都指向主存中的某条机器语言指令(即含有该条指令的地址)。

    从系统通电开始,直到系统断电,处理器一直在不断地执行程序计数器指向的指令,再更新程序计数器,使其指向下一条指令。处理器看上去是按照一个非常简单的指令执行模型来操作的,这个模型是由指令集架构决定的。

    在这个模型中,指令按照严格的顺序执行,而执行一条指令包含执行一系列的步骤。处理器从程序计数器指向的内存处读取指令,解释指令中的位,执行该指令指示的简单操作,然后更新PC,使其指向下一条指令,然而这条指令并不一定和在内存中刚刚执行的指令相邻。

    CPU在指令的要求下可能会执行这些操作:
    加载:从主存复制一个字节或者一个字到寄存器,以覆盖寄存器原来的内容。

    存储:从寄存器复制一个字节或者一个字到主存的某个位置,以覆盖这个位置上原来的内容。

    操作:把两个寄存器的内容复制到ALU,ALU对这两个字做算术运算,并将结果存放到一个寄存器中,以覆盖该寄存器中原来的内容。

    跳转:从指令本身中抽取一个字,并将这个字复制到程序计数器(PC)中,以覆盖PC中原来的值。

    计算机操作系统中的一个字,通常指的是计算机处理器(CPU)能够一次性处理的二进制数据单元的大小。一个字可以包含多个二进制位,具体的位数取决于处理器的架构和设计。x86架构的处理器中,一个字被定义为32位,而x86-64架构的处理器中,一个字被定义为64
1.4.2 运行hello程序

shell—>控制台,接收操作指令(操作者输入的指令用来明确需要执行的程序,也需要调入内存中执行);shell明确目标程序之后,将目标程序从磁盘中复制到内存中,再复制到CPU的寄存器中通过PC逐步执行,最后将结果输出到输出设备。全部过程通过总线系统实现。

  1. shell程序逐一读入从键盘(输入设备)中写入的指令到寄存器中,再把指令放到内存中。
  2. 回车代表命令输入完毕,shell接下来执行一系列指令将hello目标文件中的代码和数据从磁盘复制到内存中(利用直接存储器存取DMA技术,数据可以不通过处理器而直接从磁盘到达内存)。
  3. 当目标文件hello中的代码和数据被加载到内存中,处理器则开始执行hello程序的main程序中的机器语言指令。这些指令将“hello world\n”字符串中的字节从内存存复制到寄存器文件,再从寄存器文件中复制到显示设备(输出设备),最终显示在屏幕上。

1.5 高速缓存

问题与需求

当一个程序运行时,此程序的机器指令可能会被复制多次到不同地方(磁盘–>内存–>CPU中的寄存器–>内存–>输出设备等等)。而磁盘、内存(较大储存设备)对于数据的读取和处理速度要远远慢于CPU中的寄存器(较小储存设备)。

处理器与内存之间对于数据的处理速度差距较大,则会产生“瓶颈效应”,即系统的性能被限制在较慢的组件上。会导致CPU在处理数据时需要等待内存读取数据,从而降低整个系统的性能和响应速度。

解决

解决的方法是利用局部性原理,即在处理器和内存之间提供一个容量小而速度快的存储器,称做高速缓存存储器(cachememory,简称为cache或高速缓存),作为暂时的集结区域,存放处理器近期可能会需要的信息。

系统可以获得一个很大的存储器,同时访问速度也很快,原因是利用了高速缓存的局部性原理,即程序具有访问局部区域里的数据和代码的趋势。通过让高速缓存里存放可能经常访问的数据,大部分的内存操作都能在快速的高速缓存中完成。

高速缓存试图使访问速度接近现有最快的存储器,同时保持价格便宜的大存储容量(以较为便宜的半导体存储器技术实现)。

在这里插入图片描述

图中有一个相对容量大而速度比较慢的内存和一个容量较小且速度较快的高速缓存,高速缓存包含一部分内存数据的副本。**当处理器试图读取存储器中的一个字节或字时,要进行一次检查以确定这个字节或字是否在高速缓存中。如果在,该字节或字从高速缓存传递给处理器;如果不在,则由固定数目的字节组成的一块内存数据先被读入高速缓存,然后该字节或字从高速缓存传递给处理器。**由于访问局部性现象的存在,当一块数据被取入高速缓存以满足一次存储器访问时,很可能紧接着的多次访问的数据是该块中的其他字节。

数据从内存到高速缓冲区中的暂存机制

下图描述了高速缓存/内存的系统结构。

在这里插入图片描述

内存由2^n个可寻址的字组成,每个字有一个唯一的n位地址。为便于映射,此存储器可以看做是由一些固定大小的块组成,每块包含K个字,也就是说,一共有M-2^n/K个块。高速缓存中有C个存储槽,每个槽有K个字,槽的数目远远小于存储器中块的数目(C<<M)。内存中块的某些子集驻留在高速缓存的槽中,如果读存储器中某一个块的某一个字,而这个块又不在槽中,则这个块被转移到一个槽中。由于块的数目比槽多,一个槽不可能唯一或永久对应于一个块。因此,每个槽中有一个标签,用以标识当前存储的是哪一个块。标签通常是地址中较高的若干位,表示以这些位开始的所有地址。

数据在内存中有若干块,将常用的数据块“插入”到高速缓冲区中有限的槽中并标记标签。CPU寄存器——高速缓冲槽——内存块。

在这里插入图片描述

1.6 存储设备形成结构层次

存储器层次结构的主要思想是上一层的存储器作为低一层存储器的高速缓存。

在这里插入图片描述

寄存器文件就是L1的高速缓存,LI是L2的高速缓存,L2是L3的高速缓存,L3是主存的高速缓存,而主存又是磁盘的高速缓存。在某些具有分布式文件系统的网络系统中,本地磁盘就是存储在其他系统中磁盘上的数据的高速缓存。

1.7 操作系统管理硬件

操作系统可以看作应用程序和计算机硬件之间的一个软件,所有应用程序对于硬件的操作尝试都必须通过操作系统。

操作系统的功能:

  • 防止硬件被是空的应用程序滥用。
  • 向应用程序提供简单一致的机制来控制复杂而又通常大不相同的低级硬件设备。

操作系统通过进程、虚拟内存、文件这些抽象概念来实现这两个功能。

在这里插入图片描述

1.7.1 进程

进程是操作系统对一个正在运行的程序的一种抽象

并发运行,一个进程的指令和另一个进程的指令是交错执行的。传统系统在一个时刻只能执行一个程序,而多核处理器能同时执行多个程序。

上下文

操作系统保持跟踪进程运行时所需的所有状态信息——上下文,比如PC寄存器文件的当前值内存的内容

上下文切换:CPU在进程之间进行切换,实现并发的执行多个进程。

在任何一个时刻,单处理器系统都只能执行一个进程的代码。当操作系统决定要把控制权从当前进程转移到某个新进程时,就会进行上下文切换,即保存当前进程的上下文、恢复新进程的上下文,然后将控制权传递到新进程。新进程就会从它上次停止的地方开始。

hello程序进程运行

场景中有两个并发的进程:shell进程和hello进程。

  • 最开始,只有shell进程在运行,即等待命令行上的输入。
  • 当我们让它运行hello程序时,shell通过调用一个专门的函数,即系统调用,来执行我们的请求,系统调用会将控制权传递给操作系统
  • 操作系统保存shell进程的上下文,创建一个新的hello进程及其上下文,然后将控制权传给新的hello进程。
  • hello进程终止后,操作系统恢复shell进程的上下文,并将控制权传回给它,shell进程会继续等待下一个命令行输入。

在这里插入图片描述

如图1-12所示,从一个进程到另一个进程的转换是由操作系统内核(kernel)管理的。内核是操作系统代码常驻主存的部分。当应用程序需要操作系统的某些操作时,比如读写文件,它就执行一条特殊的系统调用(systemcalI)指令,将控制权传递给内核。然后内核执行被请求的操作并返回应用程序。

内核不是一个独立的进程。相反,它是系统管理全部进程所用代码和数据结构的集合。

1.7.2 线程

一个进程实际上可以由多个成为线程的执行单元组成,每个线程都运行在进程的上下文中,并共享同样的代码和全局数据。

多线程之间比多进程之间更容易共享数据,且更高效。

1.7.3 虚拟内存

每个进程看到地内存都是一致的,称为虚拟地址空间。虚拟内存是一个抽象概念,为每个进程提供了一个假象,即每个进程都在独占地使用主存。

Linux进程的虚拟地址空间

在这里插入图片描述

图中的地址是从下往上增大的。

地址空间最上面的区域是保留给操作系统中的代码和数据的,这对所有进程来说都是一样。

地址空间的底部区域存放用户进程定义的代码和数据。

  • 程序代码和数据。对所有的进程来说,代码是从同一固定地址开始,紧接着的是和C全局变量相对应的数据位置。代码和数据区是直接按照可执行目标文件的内容初始化的,在示例中就是可执行文件hello。(第7章)
  • 。代码和数据区后紧随着的是运行时堆。代码和数据区在进程一开始运行时就被指定了大小,与此不同,当调用像malloc和free这样的C标准库函数时,堆可以在运行时动态地扩展和收缩。(第9章)
  • 共享库。大约在地址空间的中间部分是一块用来存放像C标准库和数学库这样的共享库的代码和数据的区域。共享库的概念非常强大,也相当难懂。(第7章)
  • 。位于用户虚拟地址空间顶部的是用户栈,编译器用它来实现函数调用。和堆一样,用户栈在程序执行期间可以动态地扩展和收缩。特别地,每次我们调用一个函数时,栈就会增长;从一个函数返回时,栈就会收缩。(第3章)
  • 内核虚拟内存。地址空间顶部的区域是为内核保留的。不允许应用程序读写这个区域的内容或者直接调用内核代码定义的函数。相反,它们必须调用内核来执行这些操作。
1.7.4 文件

文件就是字节序列。每个I/O设备,包括磁盘、键盘、显示器、甚至网络都可以看成是文件。

系统中的所有输人输出都是通过使用一小组称为UnixI/O的系统函数调用读写文件来实现的。

文件这个简单而精致的概念是非常强大的,因为它向应用程序提供了一个统一的视图,来看待系统中可能含有的所有各式各样的I/O设备。

1.8 系统之间利用网络通信

从一个单独的系统来看,网络可视为一个I/O设备。

当系统从主存复制一串字节到网络适配器时,数据流经过网络到达另一台机器,而不是比如说到达本地磁盘驱动器。相似地,系统可以读取从其他机器发送来的数据,并把数据复制到自己的主存。

补充:Telent协议

Telnet是一种网络协议,用于在互联网上或局域网中远程登录主机。它允许用户通过使用终端或终端仿真程序连接到远程计算机,并以类似于本地用户的方式操作该计算机。 Telnet是一种基于文本的协议,它使用明文传输数据,因此安全性较低。在现代网络环境中,Telnet已经被SSH协议所取代。

利用SSH在一个远程主机上运行hello程序

在这里插入图片描述

1.9 重要主题

系统是硬件和系统软件互相交织的集合体,它们必须共同协作以达到运行应用程序的最终目的。

1.9.1 Amdahl定律

Amdahl定律是一种用于计算并行计算系统加速比的方法,它指出了在优化计算系统时所面临的限制。该定律表明,在优化计算系统时,最终的加速比受到计算任务中可并行化部分所占比例的影响。如果我们试图提高可并行化部分的速度,最终的加速比将受到非可并行化部分的限制。

Amdahl定律的主要观点一一要想显著加速整个系统,必须提升全系统中相当大的部分的速度

1.9.2 并发和并行

**并发(concurrency)**是一个通用的概念,指一个同时具有多个活动的系统;(更多操作)

**并行(parallelism)**指的是用并发来使一个系统运行得更快。(更快速度)

并发、并行在系统层次结构中的应用

并行可以在计算机系统的多个抽象层次上运用。下面按照系统层次结构中由高到低的顺序罗列三个层次:

  • 线程级并发

    使用线程可以在一个进程中执行多个控制流。在传统单核处理器之下,这种并发执行只是模拟出来的(就像杂耍艺人保持多个球在空中飞舞),此时单核处理器必须在多个任务间切换。

    构建一个单操作系统内核控制的多处理器系统(在多核处理器和超线程出现后)。首先,减少了在执行多个任务时模拟并发的需要;其次,可以使应用程序运行得更快。这必须要求程序是以多线程方式书写的

在这里插入图片描述

  • 指令级并行

    在较低的抽象层次上,现代处理器可以同时执行多条指令的属性称为指令级并行。早期的微处理器,如1978年的Intel8086,需要多个(通常是3~10个)时钟周期来执行一条指令。最近的处理器可以保持每个时钟周期2~4条指令的执行速率。

    每条指令从开始到结束需要长得多的时间,大约20个或者更多周期,但是处理器使用了非常多的聪明技巧来同时处理多达100条指令。

    **流水线(pipelining)**的使用——第四章。在流水线中,将执行一条指令所需要的活动划分成不同的步骤,将处理器的硬件组织成一系列的阶段,每个阶段执行一个步骤。这些阶段可以并行地操作,用来处理不同指令的不同部分。

    我们会看到一个相当简单的硬件设计,它能够达到接近于一个时钟周期一条指令的执行速率。如果处理器可以达到比一个周期一条指令更快的执行速率,就称之为超标量(super-scalar)处理器。大多数现代处理器都支持超标量操作。第5章中,我们将描述超标量处理器的高级模型。应用程序员可以用这个模型来理解程序的性能。然后,他们就能写出拥有更高程度的指令级并行性的程序代码,因而也运行得更快。

  • 单指令、多数据并行

    SIMD并行(单指令、多数据并行),在现代处理器,允许一条指令产生多个可以并行的操作。目的是为了提高处理影像、声音、视频数据应用的执行速度。有些编译器会试图从C程序中自动抽取SIMD并行性,但是更可靠的方法是用编译器的特殊的向量数据类型来写程序。

1.9.3 计算机系统中抽象的重要性

在这里插入图片描述

**在处理器里,指令集架构提供了对实际处理器硬件的抽象。**使用这个抽象,机器代码程序表现得就好像运行在一个一次只执行一条指令的处理器上。

  • 文件是对I/O设备的抽象
  • 虚拟内存是对程序存储器的抽象
  • 而进程是对一个正在运行的程序的抽象
  • 虚拟机,它提供对整个计算机的抽象,包括操作系统、处理器和程序。

1.10 小结

  • 编译系统:预处理–编译–汇编–链接。
  • 系统硬件组成:总线,I/O设备,主存(内存),CPU。
  • 一个hello程序运行的过程(1.4.2)。shell—>控制台,接收操作指令(操作者输入的指令用来明确需要执行的程序,也需要调入内存中执行);shell明确目标程序之后,将目标程序从磁盘中复制到内存中,再复制到CPU的寄存器中通过PC逐步执行,最后将结果输出到输出设备。全部过程通过总线系统实现。
  • 高速缓存,存储设备的“金字塔”结构层次。
  • 进程,线程,虚拟地址,文件。
  • 网络通信。
  • 计算机的抽象表现方式。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值