csapp 深入理解计算机系统(一)

286 阅读8分钟

计算机系统漫游

Hello程序的生命周期

1.PNG

  1. Hello Program

hello.c

#include <stdio.h>
int main() 
{
    printf("hello, world\n");
    return 0;
}
  1. 编译

生成可执行文件hello

linux> gcc -o hello hello.c

新建 Microsoft PowerPoint 演示文稿.png

为什么要理解编译系统的运行?

  • Optimizing program performance (优化程序性能)
  • Understanding link-time errors (理解链接时出现的错误)
  • Avoiding security holes (避免安全漏洞)
  1. 运行

目前,hello程序已经放入了磁盘。在linux系统上运行可执行程序。

打开shell程序,在shell程序中输入文件名。

linux> ./hello

注:shell是一个命令解释程序,它输出一个提示符 > 来等待一个命令行的输入,然后执行这个命令。如果命令行的第一个单词不是内置的 shell 命令,那么 shell 就会假设这是一个可执行文件的名字,对这个文件进行加载并运行。

在这个例子中,shell加载并且运行 hello 程序,屏幕上显示 hello, world内容。hello程序运行结束并退出。shell 继续等待下一个命令的输入。

在介绍 hello 程序运行之前,先看一下计算机系统的硬件组成。

2.PNG

中央处理单元(Central Processing Unit, CPU),也称处理器。

PC(program count),实质上是一个大小为一个字的存储区域。(一个字是多大呢?对于32位的机器,一个字是4个字节。对于64位的机器,一个字就是8个字节)。里面存放的是某一条指令的地址。处理器在不断地执行PC指向的指令,然后更新PC,使其指向下一条要执行的指令。(这个下一条指令与刚刚执行的指令不一定是相邻的)。

寄存器文件,它就是CPU内部的一个存储设备。寄存器文件是由一些单字长的寄存器构成,每个寄存器都有自己唯一的名字。寄存器可以理解为一个临时存放数据的空间。

ALU(Arithmatic/logic Unit)。

主存,也称为内存。处理器在执行程序时,内存主要存放程序指令以及数据。从物理上将,内存是由随机动态存储器芯片组成。从逻辑上讲,内存可以看成一个从零开始的大数组。每个字节都有相应的地址。

总线,内存和处理器之间通过总线来进行数据传递。它负责将信息从一个部件传递到另外一个部件,通常总线被设计成传送固定长度的字节块,也就是字(word)。至于这个字到底是多少字节,各个系统中是不一样的。

输入/输出设备。

接下来,看看hello程序执行时,到底发生了什么。

首先,通过键盘输入"./hello"的字符串,shell 程序会将输入的字符逐一读入寄存器,处理器会把 hello 这个字符放入内存中。输入完成后,按下回车键时,shell 程序就知道我们已经完成了命令的输入。然后执行一系列指令来加载可执行文件 hello ,这些指令将 hello 中的数据和代码从磁盘复制到内存,数据就是我们要显示输出的"hello, world\n"。这个复制的过程将利用 DMA (Direct Memory Access) 技术,即数据可以不经过处理器,从磁盘直接到达内存。当可执行文件 hello 中的代码和数据被加载到内存中,处理器就开始执行 main 函数中的代码。CPU 会将"hello, world\n"这个字符串从内存复制到寄存器文件,然后再从寄存器文件复制到显示设备。最终 hello, world 显示在屏幕上。

存储

从 hello 程序执行的过程来看,系统即使执行如此简单的程序,数据信息仍旧需要在磁盘、内存、处理器以及 IO 设备之间进行搬运。数据从一个地方搬运到另外一个地方需要花费时间,系统设计人员的一个主要任务就是缩短信息搬运所花费的时间。

通常情况下,大容量的存储设备的存取速度要比小容量的慢。运行速度更快的设备的价格相对于低俗设备要更贵。

3.PNG

整个计算机系统的信息存储可以用一个层次结构来表示。从这个层次结构来看,从上到下,设备的访问速度越来越慢,容量越来越大,每字节的造价也越来越便宜。这个层次结构的主要思想是,上一层存储设备是下一层存储设备的高速缓存。程序员理解计算机中的高速缓存,可以利用存储器的层次结构板来提升程序的性能。

操作系统

无论是 shell 程序还是 hello 程序都没有直接访问键盘、显示器、磁盘这些硬件设备。真正操纵硬件的是操作系统,其可以看成是程序和硬件之间的中间层,所有应用程序对硬件的操作必须通过操作系统来完成。

4.PNG

目的:

  • 防止硬件被失控的应用程序滥用;
  • 提供统一的机制来控制这些复杂的底层硬件。

5.PNG

进程

进程切换

假设示例场景中只有两个并发的进程,shell 进程和 hello 进程。

最开始,只有 shell 进程在运行,即 shell 在等待命令行的输入,当我们通过 shell 进程加载 hello 进程时,shell 进程通过系统调用来执行我们的请求。系统调用会将控制权从 shell 进程传递给操作系统,操作系统保存 shell 进程的上下文,然后创建一个 hello 进程及其上下文,将控制权交给新的 hello 进程。Hello 进程执行完之后,操作系统会恢复 shell 进程的上下文,并将控制权交给 shell 进程。

6.PNG

注:上下文,操作系统会跟踪进程运行中所需要的所有状态信息。例如,当前PC和寄存器的值,以及内存中的内容等等。

线程

现代操作系统中,一个进程实际上由多个线程组成。每个线程都运行在进程的上下文中,共享代码和数据。

虚拟内存

它为每个进程提供了一个假象,就是每个进程都在独自占用整个内存空间。每个进程看到的内存都是一样的,称之为虚拟地址空间。

7.png

文件

8.PNG

网络

使用 ssh 运行 hello 程序

9.png

阿姆达尔定律

S=ToldTnew=1(1α)+α/kS = \frac{T_{old}}{T_{new}} = \frac{1}{(1-\alpha) + \alpha/k}

当我们对系统的某一部分进行加速时,被加速部分的重要性和加速程度是影响整个系统性能的关键因素。

在加速前,假设一个应用程序的执行所需要的全部时间用来表示ToldT_{old}。为了方便描述,我们可以笼统的将这个程序分为两部分。一部分是不可加速的,另一部分是可加速的。其中可以加速的部分执行花费的时间为αTold\alpha * T_{old},不可加速部分的执行时间为ToldαToldT_{old} - \alpha * T_{old}。程序经过优化后,可加速部分性能提升比例为K。那么经过加速后,这个可加速部分所花费的时间就是(aTold)/k(a * T_{old})/k。即:

Tnew=(1α)Told+(αTold)/k=Told[(1α)+α/k]S=Told/Tnew=1(1α)+α/kT_{new} = (1 - \alpha)T_{old} + (\alpha T_{old})/k = T_{old}[(1-\alpha) + \alpha/k] \\ S = T_{old}/T_{new} = \frac{1}{(1-\alpha) + \alpha/k}

α=0.6,k=3\alpha = 0.6, k = 3时,S=1(10.6)+0.63=1.67S=\frac{1}{(1-0.6) + \frac{0.6}{3}} = 1.67。当k趋于无穷大时,S=11α=2.5S=\frac{1}{1-\alpha} = 2.5

因此,我们需要把系统的性能提高2倍或者更多,只有通过优化大部分的组件才能获得。

如何获得更高的计算能力呢?可以通过三种途径。

  • Thread-Level Concurrency (线程级并发)
  • Instruction-Level Parallelism (指令级并行)
  • Single-Instruction Multiple-Data Parallelism (单指令多数据并行)
Multi-core Processor Organization

10.png

超线程(hyperthreading)

超线程,也称为同时多线程。如果每个CPU核心可以执行两个线程,那么四个核心就可以并行执行8个线程。在CPU内部,像程序计数器和寄存器文件这样的硬件部件有多个备份,而像浮点运算部件这样的硬件还是只有一份,常规单线程处理器在做线程切换时,大概需要20000个时钟周期。而超线程处理器可以在单周期的基础上决定执行哪一个线程,这样一来,CPU可以更好地利用它的处理资源,当一个线程因为读取数据而进入等待状态时,CPU可以去执行另外一个线程,其中线程之间的切换只需要极少的时间代价。

指令级并行

现代处理器可以同时执行多个指令的属性称为指令级并行,每条指令从开始到结束大概需要20个时钟周期或者更多,但是处理器采用了非常多的技巧可以同时处理多达100条指令。因此,近几年的处理器可以保持每个周期2~4条指令的执行速率。

单指令多数据

现代处理器拥有特殊的硬件部件,允许一条指令产生多个并行的操作,这种方式称为单指令多数据。SIMD的指令多是为了提高处理视频、以及声音这类数据的执行速度。比较新的Intel以及AMD的处理器都是支持SIMD指令加速。

计算机系统中的抽象

11.PNG