CSAPP 读书笔记-第一章计算机系统漫游

第一章是对整书后续章节内容的高度概括。全书以经典的 Hello World 程序开篇,概括了从源码到可执行文件的编译过程;然后深入硬件底层,描述了一台计算机典型的物理构成;最后,抛出抽象的概念,说明是如何通过操作系统、进程、虚拟内存、文件这些抽象概念管理底层硬件的。

1.2 程序被其他程序翻译成不同的格式

1
gcc -o hello hello.c

用此例揭示了编译的四个步骤:

  • 预处理阶段(cpp),hello.c -> hello.i
  • 编译阶段(ccl),hello.i -> hello.s
  • 汇编阶段(as),hello.s -> hello.o
  • 链接阶段(ld),printf.o + hello.o -> hello

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

以 1.2 产出的 hello 文件为例,解释了程序执行时数据是如何在硬件中流转的。

1.4.1 系统的硬件组成

一个典型系统的硬件组织:

1) 总线。负责在各个部件间传递一组字节,一组字节的大小为一个字,x64 系统上一个字是 8 字节。
总线又有 I/O 总线(连接 I/O 设备、I/O 桥)、内存总线(连接内存和 I/O 桥)、系统总线(连接 CPU 和 I/O 桥)。

2) I/O 设备。键盘、鼠标、显示器、磁盘驱动器等等。每个 I/O 设备都通过一个控制器或适配器与 I/O 总线相连。

3) 主存。也就是内存,在处理器执行程序时,用来存放程序和程序处理的数据。物理上,内存是一组 DRAM 芯片;逻辑上,内存是一个线性的字节数组。

4) 处理器。是解释(或执行)存储在内存中指令的引擎。CPU 的核心是程序计数器(PC 寄存器),大小为一个字,PC 总是指向存储在内存中的下一条要执行的指令。
PC 配合内存、其它寄存器、ALU(算数/逻辑单元),循环往复地执行指令。

CPU 涉及两个重要概念:指令集架构和微体系结构。指令集架构是一种通用标准,描述的是每条机器代码指令的效果;微体系结构描述的是厂商的具体实现。比如我用的 AMD R7 5700X,指令集架构是 X86-64,而微体系结构是 Zen3。

1.4.2 运行 hello 程序

继续以 hello 为示例,介绍了程序运行时各种硬件的分工。

引出 DMA(直接存储器存取)技术,可以把数据不通过 CPU 直接从磁盘到达内存。

1.5 高速缓存至关重要

总结 hello 程序的执行过程,“系统花费了大量的时间把信息从一个地方挪到另一个地方”,“这些复制就是开销,减慢了程序真正的工作”,“处理器从寄存器文件中读数据比从主存中读取几乎快 100 倍”。说明了 Cache 的重要性。

简单介绍了典型的 L1、L2、L3 三层缓存结构:

  • L1 性能最高,访问速度几乎和访问寄存器文件一样快,但是容量最小。
  • L2 容量更大,但是其访问速度要比 L1 慢 5 倍——但是仍然比访问内存快 5~10 倍。

L1 和 L2 高速缓存是用一种叫做静态随机访问存储器(SRAM)的硬件技术实现的。

Cache 的理论支撑:局部性原理,即程序具有访问局部区域里的数据和代码的趋势。通过让高速缓存里存放可能经常访问的数据,大部分的内存操作都能在快速的高速缓存中完成。

本书得出的重要结论之一就是,意识到高速缓存存储器存在的应用程序员能够利用高速缓存将程序的性能提高一个数量级。

1.7 操作系统管理硬件

1.7.1 进程

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

操作系统通过上下文切换实现多个进程的交错执行。

上下文切换是由操作系统内核管理的,内核是操作系统代码常驻主存的部分。

1.7.2 线程

一个进程可以由多个称为线程的执行单元组成,这些线程共享同样的代码和全局数据。

多线程之间比多进程之间更容易共享数据,线程一般来说比进程更高效。

1.7.3 虚拟内存

每个进程看到的内存都是一致的,即虚拟地址空间。一个 Linux 进程的虚拟地址空间的作用域从低地址到高地址是这样分布的:

  • 程序代码和数据。从可执行文件加载而来
  • 运行时堆。运行时 malloc 而来
  • 共享库的内存映射区域。比如 hello 程序中用到的 printf
  • 用户栈。
  • 内核虚拟内存。

1.8 系统之间利用网络通信

在 1.4.1 节展示的计算机硬件组成的基础上,添加了网络适配器这一 I/O 设备。

1.9 重要主题

1.9.2 并发和并行

“术语并发是一个通用的概念,指一个同时具有多个活动的系统;而术语并行指的是用并发来使一个系统运行得更快”。

这句话有点难以理解,又好像跟通俗意义里的并发并行不符。

由高到低三个层次上的并行:

1) 线程级并发

多核处理器是将多个 CPU 集成到一个集成电路芯片上。一个典型的微处理器芯片有多个 CPU 核,每个核有自己的 L1、L2 Cache,L1 又分为两部分——数据缓存和指令缓存。

超线程允许一个 CPU 执行多个控制流。每个核有多套 PC 寄存器和其它寄存器,但是只有一套 ALU。

2) 指令级并行

现代处理器通过使用流水线技术来同时处理多达 100 条指令。

如果处理器可以达到比一个周期一条指令更快的执行速率,就称之为超标量(super scalar)处理器。

3) 单指令、多数据并行

虽然有些编译器会试图从 C 程序中自动抽取 SIMD 并行性,但是更可靠的方法是用编译器支持的特殊的向量数据类型来写程序。

评论