进阶·2015·12 章

深入理解计算机系统

Computer Systems: A Programmer's Perspective

勿以浮沙筑高台

作者:Randal E. Bryant, David R. O'Hallaron·Pearson·ISBN: 978-0134092669

从程序员视角讲解计算机系统的经典教材。涵盖数据的机器级表示、汇编语言、处理器体系结构、存储器层次结构、链接、异常控制流、虚拟内存、系统级I/O、网络编程与并发编程。已被全球200多所大学用作教材。

为什么读这本书

理解程序在硬件上如何运行,是写出高性能代码的基础。这本书会告诉你:要想成为一名优秀的程序员,你必须理解哪些计算机底层原理。

章节导览

01

计算机系统漫游

190 次阅读· 已读 8分钟· 预计 17 分钟

勿以浮沙筑高台

本章是全书的导论,通过一个简单的hello程序展示了计算机系统的各个层次如何协同工作。从硬件到操作系统再到应用程序,你会看到一个完整的系统视图。

系统概览抽象层次Amdahl定律
关联层级:L1L2L3
02

信息的表示和处理

1 次阅读· 预计 16 分钟

我们生活在比特组成的世界

你可能会有疑惑:为什么作者要花那么多篇幅来介绍大家(仿佛)都已经理解的二进制系统呢?实际上第二章写得非常好,当你阅读之后会发现,你所谓的「懂」只是你的一厢情愿而已。数值系统远没有你想象的那么简单。

十六进制补码浮点数位运算
关联层级:L1L2
03

程序的机器级表示

5 次阅读· 预计 13 分钟

有时候你要学会像机器一样思考

某种程度上讲,本章是本课程的核心内容之一。今天我们还要花力气来学习机器级别的编程方式,因为它们是连接你所编写的高级语言代码和机器之间的纽带,是实实在在的基石。

x86-64汇编寻址模式栈帧过程调用
关联层级:L3L4
04

处理器体系结构

5 次阅读· 预计 15 分钟

万丈高楼平地起

本章从硬件角度理解处理器如何工作。通过Y86-64这个简化的指令集,你可以理解现代处理器的设计原理。

Y86-64流水线控制逻辑流水线冒险
关联层级:L2L3
05

优化程序性能

8 次阅读· 预计 22 分钟

我们可以做的更好

本章讲解如何写出高性能的代码。编译器很聪明,但程序员的理解同样重要。

编译器优化循环展开并行性存储器山
关联层级:L3L4
06

存储器层次结构

4 次阅读· 预计 25 分钟

万能的金字塔模型

存储器层次结构是理解程序性能的关键。从寄存器到磁盘,每一层都比下一层慢,但容量更大、更便宜。

SRAM/DRAM缓存局部性存储器山
关联层级:L2L3
07

链接

7 次阅读· 预计 16 分钟

欢迎来到灰色地带

链接是很多人忽视的环节,但它对理解程序如何组合在一起至关重要。

静态链接目标文件符号解析重定位
关联层级:L4L5
08

异常控制流

6 次阅读· 预计 12 分钟

操作系统:唯一的使命就是帮助程序运行

异常控制流是操作系统的基础。理解异常、中断、进程和信号,才能理解程序如何与系统交互。

异常进程系统调用信号
关联层级:L3L5
09

虚拟内存

5 次阅读· 预计 23 分钟

假装我们有用不完的物理内存

虚拟内存是操作系统最重要的抽象之一。它让每个进程都觉得自己独占整个内存空间。

虚拟地址页表TLB内存映射
关联层级:L3L5
10

系统级I/O

6 次阅读· 预计 16 分钟

务必搞清楚你自己正在和整个系统的哪一层打交道

Unix的I/O模型简单而强大。理解文件描述符和系统调用,才能写出正确的I/O代码。

文件描述符RIO包I/O重定向
关联层级:L5
11

网络编程

3 次阅读· 预计 20 分钟

实现古人天涯若比邻的梦想

现代应用都是网络应用。理解Socket编程和HTTP协议,才能构建分布式系统。

SocketTCP/IPHTTP客户端-服务器模型
关联层级:L6L7
12

并发编程

4 次阅读· 预计 18 分钟

并发与并行,傻傻分不清楚?

并发是现代编程的核心挑战。理解线程、同步和并发模型,才能写出正确的并发程序。

线程互斥锁信号量生产者-消费者
关联层级:L5L6

读书笔记

01

计算机系统漫游

勿以浮沙筑高台

重点内容

  • 程序的生命周期:从源代码到可执行文件再到运行
  • 存储层次结构:缓存、内存、磁盘的层次关系
  • 操作系统的作用:抽象硬件、管理资源
  • 网络的重要性:现代系统不是孤立的
  • 并发的挑战:多核时代的编程模型

延伸阅读

  • CMU 15-213 课程讲义
  • 《计算机组成与设计:硬件/软件接口》
02

信息的表示和处理

我们生活在比特组成的世界

重点内容

  • 为什么一个字节是8位?这源于IBM System/360的历史
  • 原码、反码、补码的演进:为什么补码成为主流
  • 浮点数的设计权衡:范围、精度、比较大小的权衡
  • 整型溢出的危险:阿丽亚娜5号火箭爆炸的教训
  • 字节序问题:大小端在网络编程中的重要性

代码示例

// 带符号数产生意外结果的例子
int n = 10, i; 
for (i = n - 1 ; i - sizeof(char) >= 0; i--)
    printf("i: 0x%x\n",i);
// sizeof返回unsigned,导致无限循环
// 浮点数不满足结合律
(3.14+1e10)-1e10 = 0
3.14+(1e10-1e10) = 3.14
// 编译器优化时需要注意这一点

实验解读

Data Lab:理解C语言数据类型的位级表示形式。要求只用位运算实现各种功能,让你站在「比特级」来理解二进制数值系统。

延伸阅读

  • 香农的硕士论文《继电器与开关电路的符号分析》
  • IEEE-754浮点数标准
  • 位运算的奇技淫巧:Bit Twiddling Hacks
03

程序的机器级表示

有时候你要学会像机器一样思考

重点内容

  • ISA是软硬件之间的「合同」
  • 编译过程:源代码 → 编译 → 汇编 → 链接 → 可执行文件
  • 程序就是一系列字节序列(冯诺依曼结构)
  • 条件码(CF、ZF、SF、OF)的作用
  • 函数调用过程:控制权转移、参数传递、栈管理
  • 缓冲区溢出的安全问题

代码示例

// 逆向工程:从汇编理解C代码
// 使用 objdump -d 或 gdb 查看反汇编
// 理解编译器如何优化你的代码

实验解读

Bomb Lab:通过逆向工程拆除炸弹,理解汇编语言和GDB调试。Attack Lab:学习代码注入攻击和ROP攻击,理解如何预防安全漏洞。

延伸阅读

  • Intel 64 and IA-32 Architectures Software Developer's Manuals
  • 《C专家编程》关于指针的深入讨论
04

处理器体系结构

万丈高楼平地起

重点内容

  • 单周期处理器:简单但慢
  • 流水线设计:提高吞吐量的关键
  • 流水线冒险:数据冒险、控制冒险、结构冒险
  • 分支预测的重要性
  • 乱序执行的原理

延伸阅读

  • 《计算机体系结构:量化研究方法》
05

优化程序性能

我们可以做的更好

重点内容

  • 消除循环的低效率:代码移动
  • 减少过程调用
  • 减少内存引用
  • 理解现代处理器:超标量、流水线
  • 存储器山:缓存的时间局部性和空间局部性
  • 循环展开和多次迭代并行

代码示例

// 代码移动:将循环不变量移出循环
for (i = 0; i < n; i++) {
    // 不好:每次循环都调用函数
    // x = a[i] * getMultiplier();
    
    // 好:移到循环外
    int mult = getMultiplier();
    for (i = 0; i < n; i++) {
        x = a[i] * mult;
    }
}
06

存储器层次结构

万能的金字塔模型

重点内容

  • 存储技术:SRAM、DRAM、磁盘、SSD
  • 局部性原理:时间局部性和空间局部性
  • 缓存的组织方式:直接映射、组相联、全相联
  • 缓存写入策略:写回 vs 写穿
  • 存储器山:理解性能的关键模型

实验解读

Cache Lab:实现一个缓存模拟器,然后优化矩阵转置的缓存命中率。

07

链接

欢迎来到灰色地带

重点内容

  • 编译器驱动程序的作用
  • 静态链接的过程
  • 目标文件的格式(ELF)
  • 符号解析规则
  • 重定位的过程
  • 静态库和动态库的区别
08

异常控制流

操作系统:唯一的使命就是帮助程序运行

重点内容

  • 异常的分类:中断、陷阱、故障、终止
  • 进程的概念:独立的逻辑控制流
  • 系统调用的机制
  • 信号的处理
  • 非本地跳转:setjmp和longjmp

实验解读

Shell Lab:实现一个简单的Unix shell,理解进程控制和信号处理。

09

虚拟内存

假装我们有用不完的物理内存

重点内容

  • 虚拟内存的作用:隔离、共享、高效
  • 地址翻译的过程
  • 页表的设计:多级页表
  • TLB的作用:加速地址翻译
  • 内存映射文件
  • 动态内存分配:malloc的实现

实验解读

Malloc Lab:实现自己的malloc和free,理解内存分配器的设计。

10

系统级I/O

务必搞清楚你自己正在和整个系统的哪一层打交道

重点内容

  • Unix I/O模型:一切皆文件
  • 文件描述符的概念
  • read和write系统调用
  • RIO(Robust I/O)包的设计
  • I/O重定向和管道
11

网络编程

实现古人天涯若比邻的梦想

重点内容

  • 客户端-服务器模型
  • Socket接口
  • TCP vs UDP
  • HTTP协议基础
  • 并发服务器的设计

实验解读

Proxy Lab:实现一个简单的Web代理服务器,理解网络编程和并发。

12

并发编程

并发与并行,傻傻分不清楚?

重点内容

  • 基于进程的并发
  • 基于I/O多路复用的并发
  • 基于线程的并发
  • 多线程编程的挑战
  • 同步原语:互斥锁、信号量
  • 生产者-消费者模型
  • 线程安全

配套实验

1Data Lab
2Bomb Lab
3Attack Lab
4Arch Lab
5Cache Lab
6Shell Lab
7Malloc Lab
8Proxy Lab

标签

系统编程底层原理性能优化CSAPP