计算机系统:程序员视角(全球版)
深入探讨计算机系统如何执行程序和存储信息。本课程连接高级编程与底层硬件,涵盖机器级表示、处理器架构、内存层次结构以及并发编程。
课程概述
📚 内容概要
深入探讨计算机系统如何执行程序和存储信息。本课程弥合了高级编程与底层硬件之间的差距,涵盖机器级表示、处理器架构、内存层次结构以及并发编程。
通过理解软硬件接口,掌握系统编程的艺术。
作者: Randal E. Bryant, David R. O'Hallaron
致谢: 由卡内基梅隆大学15-213课程的学生和教师支持。致谢包括Manasa S.和Mohit Tahiliani的贡献。
🎯 学习目标
- 识别系统中如何使用位和上下文来表示信息。
- 追踪从源代码到可执行文件的编译系统的四个阶段。
- 描述硬件的组织结构以及存储设备的层次特性。
- 在十进制、二进制和十六进制之间进行转换,并解释机器级寻址(字节序)。
- 在C语言中执行位级和逻辑运算,并预测算术右移的结果。
- 分析整数编码以识别潜在的溢出漏洞和类型转换错误。
- 分析 C语言构造(循环、分支、函数)与x86-64汇编指令之间的映射关系。
- 剖析 运行时栈,解释参数传递方式、局部变量存储机制以及递归调用的管理方式。
- 评估 异构数据结构的内存布局,并应用对齐规则计算总存储需求。
- 定义Y86-64程序员可见状态,并将指令编码/解码为字节序列。
🔹 第1课:计算机系统导览
概述: 本课全面介绍计算机系统如何表示信息、翻译程序并借助复杂的软硬件交互执行指令。内容涵盖程序从源代码到执行的全过程,内存层次结构在克服处理器与内存速度差距中的关键作用,操作系统提供的抽象机制,以及决定系统性能和并行性的数学规律。
学习成果:
- 识别系统中如何使用位和上下文表示信息。
- 追踪从源代码到可执行文件的编译系统的四个阶段。
- 描述硬件的组织结构以及存储设备的层次特性。
🔹 第2课:信息的表示与操作
概述: 本课探讨数字计算机如何在位级别上表示和操作信息。内容涵盖从十六进制表示和机器级字长过渡到整数(无符号和补码)及浮点数(IEEE 754)的复杂编码。学生将分析计算机算术的数学特性,包括溢出的安全影响,以及有限精度系统中舍入的细微差别。
学习成果:
- 在十进制、二进制和十六进制之间进行转换,并解释机器级寻址(字节序)。
- 在C语言中执行位级和逻辑运算,并预测算术右移的结果。
- 分析整数编码以识别潜在的溢出漏洞和类型转换错误。
🔹 第3课:程序的机器级表示
概述: 本课深入探讨高级C程序如何转化为x86-64机器码。内容涵盖处理器的基本架构,包括寄存器和栈;控制流(条件语句、循环、开关)的实现;过程调用与递归的机制;数组、结构体和共用体等复杂数据结构的机器级表示。最后还涉及通过缓冲区溢出分析实现系统安全,以及用于浮点数运算的专用指令。
学习成果:
- 分析 C语言构造(循环、分支、函数)与x86-64汇编指令之间的映射关系。
- 剖析 运行时栈,解释参数传递方式、局部变量存储机制以及递归调用的管理方式。
- 评估 异构数据结构的内存布局,并应用对齐规则计算总存储需求。
🔹 第4课:处理器架构
概述: 本课探索处理器的基础架构,重点从顺序实现(SEQ)过渡到高性能流水线实现(PIPE),采用Y86-64指令集架构(ISA)。学生将分析指令如何编码,经过离散阶段(取指、译码、执行、访存、写回)处理,以及如何通过控制逻辑、停顿和前递来管理硬件冒险,以最大化吞吐量。
学习成果:
- 定义Y86-64程序员可见状态,并将指令编码/解码为字节序列。
- 使用硬件控制语言(HCL)实现组合和时序电路的硬件控制逻辑。
- 跟踪顺序处理器六个阶段的指令流,并识别时钟的影响。
🔹 第5课:优化程序性能
概述: 本课探讨通过理解高级代码、优化编译器和现代微处理器架构之间的相互作用,系统性地提升程序性能的方法。学生将学会识别“优化障碍”如内存别名,应用低级变换如循环展开和重结合,并利用GPROF等分析工具有效定位性能瓶颈。
学习成果:
- 识别并缓解优化障碍,包括内存别名和函数调用开销。
- 使用每元素周期数(CPE)度量程序性能。
- 应用循环展开、多累加器和重结合变换以利用指令级并行性。
🔹 第6课:内存层次结构
概述: 本课探讨内存层次结构的结构与功能设计,重点关注存储速度、成本与容量之间的权衡。内容详细介绍了现代系统所依赖的技术——从SRAM、DRAM到磁盘和固态硬盘(SSD),并解释了局部性原理(时间局部性和空间局部性)如何使小型快速缓存内存显著提升程序性能。学生将学习分析缓存映射(直接映射、组相联、全相联),并应用循环重排序和分块等优化技术编写缓存友好的代码。
学习成果:
- 区分SRAM、DRAM、ROM和闪存技术及其在层次结构中的角色。
- 基于几何和操作组件计算磁盘存储容量和总访问时间。
- 分析内存地址,确定不同映射策略下的缓存组索引、标签和块偏移。
🔹 第7课:链接
概述: 本课探讨链接这一关键的系统级过程,即将代码和数据聚合为一个可加载到内存并执行的单一文件。学生将从源代码过渡到可执行二进制文件,理解链接器如何解析符号引用、通过重定位合并段落,并管理静态库和动态库。课程最后介绍现代共享库中使用的高级技术,如库插桩和位置无关代码(PIC)。
学习成果:
- 跟踪源文件通过编译器驱动程序转变为最终可执行文件的过程。
- 分析ELF目标文件,识别符号类型和段组织。
- 应用符号解析规则管理重复名称和链接时依赖项。
🔹 第8课:异常控制流
概述: 本课探讨异常控制流(ECF),即计算机系统对外部状态变化的响应机制。我们研究ECF在系统各层面的实现,从硬件触发的异常,操作系统层面的上下文切换和进程控制(fork、wait、execve),到软件层面的信号和非局部跳转。学生将学习管理并发、处理系统错误,并编写健壮且信号安全的代码。
学习成果:
- 区分四类硬件级异常(中断、陷阱、故障、中止)及其处理机制。
- 使用系统调用管理进程生命周期(创建
fork、回收waitpid、执行execve)。 - 实现安全的信号处理程序,考虑并发性、非排队信号和异步信号安全。
🔹 第9课:虚拟内存
概述: 本课探讨虚拟内存(VM)作为一种基础抽象,为每个进程提供大容量、连续且私有的地址空间。我们讨论其三大核心作用:作为DRAM中高效缓存的工具,内存管理与保护的机制,以及内存映射的基础。此外,课程深入讲解地址转换(TLB)、动态内存分配(堆管理)和自动垃圾回收原理,并总结C编程中常见的内存相关陷阱。
学习成果:
- 区分物理地址与虚拟地址,并描述内存管理单元(MMU)的作用。
- 使用页表和转换查找缓冲区(TLB)执行虚拟地址到物理地址的转换。
- 分析并实现动态内存分配策略,包括隐式/显式链表和合并。
🔹 第10课:系统级I/O
概述: 本课探讨Linux操作系统与应用程序之间进行输入输出的基本接口。内容涵盖基本的Unix I/O系统调用、Linux文件系统中遇到的各种文件类型,以及用于管理它们的内核级数据结构。此外,还引入鲁棒I/O(RIO)包以处理“短读”问题,并提供在不同编程场景(如网络编程)中选择标准I/O与系统级I/O的指南。
学习成果:
- 实现 使用Unix I/O接口的基本文件操作(
open、close、read、write)。 - 区分 普通文件、目录和链接,并使用
stat查询文件元数据。 - 使用 RIO包执行鲁棒的、带缓冲和不带缓冲的I/O操作。
🔹 第11课:网络编程
概述: 本课探讨基于网络的应用程序的基本架构,核心是客户端-服务器编程模型和全球IP互联网。学生将学习导航套接字接口——系统级网络通信的主要API——并逐步实现一个功能完整的网页服务器(TINY),能够通过通用网关接口(CGI)交付静态文件和动态内容。
学习成果:
- 理解客户端-服务器模型的请求-响应周期,以及全球IP互联网的软硬件层级结构。
- 使用协议无关函数(如
getaddrinfo)操作和转换IP地址、域名和套接字结构。 - 实现一个健壮的迭代式网页服务器和使用进程控制与I/O重定向来服务动态内容的CGI程序。
🔹 第12课:并发编程
概述: 本课探讨并发的基本模型:进程、I/O多路复用和线程。深入讲解使用信号量解决竞争条件的同步机制,常见架构模式如生产者-消费者和预线程化服务器,以及用于评估并行性能的指标。最后还讨论了关键可靠性问题,包括线程安全、可重入性和死锁预防。
学习成果:
- 区分基于进程、I/O多路复用和线程的并发模型。
- 应用信号量操作(P和V)确保互斥并解决同步模式。
- 在不同扩展定律下计算并行性能指标,如加速比和效率。