计算机系统概论
计算机系统概论
复习定位
计算机系统从用户的角度看是"运行软件"——但从组成原理角度看是"执行指令的硬件"。理解系统层次的划分(用户→应用程序→操作系统→ISA→微体系结构→硬件)有助于定位问题的归属——一个性能问题是OS调度导致的还是Cache未命中导致的还是磁盘IO上限造成的。
计算机系统的层次结构
计算机系统从上到下可以划分为若干抽象层,每一层向上一层隐藏实现细节:
- 应用层:用户直接与浏览器、游戏、数据库交互。开发者使用高级语言编程。
- 高级语言层:用C/C++/Python等语言写的程序——经过编译或解释转换为更低层的表示。这层的对象是变量、函数、对象的抽象——不需要关心寄存器分配或堆栈布局。
- 汇编语言层:助记符表示的机器指令——与ISA一一对应。程序员通过
moveax, [rbx+rcx*4]等工作。 - ISA层(指令集体系结构):这是软硬件之间的契约。操作系统和编译器只知道自己面对的是x86或ARM的指令集——不关心CPU内部的微架构(流水线深度、Cache是8路还是16路等)。
- 微体系结构层:CPU内部实现ISA的具体方式——流水线、Cache、乱序执行、分支预测。同一种ISA可以用完全不同的微体系结构实现(Intel的Skylake和Raptor Lake都是x86-64但微架构差距巨大)。
- 寄存器传输层(RTL):CPU内部的寄存器、ALU、总线之间的操作和周期级行为。数字电路设计人员在寄存器传输级别通过硬件描述语言(Verilog/VHDL)描述CPU的行为。
- 逻辑门层:构成CPU的基本元件——与或非门、锁存器、触发器等数字电路基础元件。半导体工艺决定了晶体管的开关速度和能耗。
- 物理层:半导体材料中的载流子运动、光子(光刻)的衍射极限。
指令集(ISA)是分界点——OS向上兼容应用(只要ISA不变、x86应用持续在未来的x86机器上执行)而ISA以下由硬件实现(从微架构到物理层快速迭代且对上层透明)。
计算机体系结构演化的两大驱动力
性能提升——处理器体系结构从单周期到多周期到流水线到超标量乱序执行——每步追求更高的指令吞吐。内存从SDRAM到DDR5和HBM——总线从并行PCI到串行PCIe。每阶段都在填补前一代的瓶颈。分支预测、L3共享Cache、超线程等更深入的优化也在逐步加入。
功耗约束——早期CPU设计几乎不考虑功耗——直到Pentium 4到达130W的TDP(热设计功耗)极限——Intel抛弃NetBurst架构转向Core架构(更宽的流水线+更低的频率每瓦性能最大化)。Dennard缩放失效后——单纯的频率提升将使芯片迅速因为漏电流发热而超出散热能力——因此转向多核(更多并行但保持每个核在低电压低频率)。
系统设计的定量原则
局部性原理——程序在短时间内倾向于访问集中的一小组数据或指令。时间局部性——一个当前被访问的项目在不久的将来很可能会被再次访问(循环中的迭代变量)。空间局部性——访问一个地址后邻近的数据也会被访问(数组的连续索引遍历)。这一原理解释了Cache的合理性并且支撑着存储器层次结构的设计大部分。
Amdahl定律——对系统某个部分进行加速后——整体性能提升上限由"该部分在原执行时间中占的比例"决定。如果CPU的浮点运算耗时占总时间的30%——就算将浮点运算加速到无限快——整体加速比上限只有1/(0.7+0.3/∞)=1.43倍。这一公式阻止了把全部优化精力放在非瓶颈部分。
复习检查
一个C语言编写的程序——未经修改从x86平台迁移到ARM芯片——能否直接运行?从软件层次的角度解释各层需要改变哪些部分?
ISA上层的软件是否感知CPU微架构的变化——同一个x86程序在宽流水线CPU和窄流水线CPU上执行的二进制码相同但性能差异巨大——解释为什么。
Dennard缩放失效后CPU厂商转向多核的原因——核心电压与频率的关系在缩小工艺后如何导致了功耗平方性增长?
Amdahl定律中串行部分占20%——使用100个核心执行——与使用200个核心执行的加速倍率分别是多少——200核带来的额外收益在去掉边际后为什么比100核小那么多?
局部性原理在数据库缓冲池设计中的应用——一个查询反复访问同一个表的不同行的热度集中在索引叶子块——预取会加载哪些额外的行?
指令集体系结构(ISA)的原理
ISA定义了硬件和软件之间的契约:CPU可执行的指令集、寄存器的数量和用途、存储器的寻址模型、中断和异常的处理方式。x86-64的通用寄存器有16个(x64模式仅支持16个用户通用寄存器)而ARM有31个(X0-X30)和一个PC——一个纯粹的ISA差异——因为寄存器数量的不同——同算法下ARM可能需要在函数调用帧中保存/恢复的寄存器数量更少——可减少函数调用和异常返回时的栈刷新开销。
ISA的设计有两个主流方向:CISC——指令数量多、功能复杂、长度可变——x86的代表;RISC——指令精简、长度固定、只load/store访问内存——ARM和RISC-V代表。RISC在服务器和移动设备占据主导——x86在PC和服务器领域仍占主流。
ISA的向后兼容是x86最成功的设计决策之一——1978年的8086指令至今仍在最新的Core i9上运行。这种兼容性意味着操作系统和软件可以持续升级而不必重写——但也意味着CPU必须包含大量从初始设计就留下的冗余访存复杂度(如A20地址线的历史遗留和段寄存器在64位模式下的法律效应减弱的电路仍然存在)。
处理器性能公式的再讨论
单核CPU执行一个程序的CPU时间 = 指令数 × CPI × 时钟周期。三个因素的关系:
$$CPU时间 = \frac{指令数 \times CPI}{频率}$$
指令数——受编译器质量和指令集设计的支配——同样C代码在x86上生成指令数量通常少于ARM(因为一条x86指令可以完成内存操作+算术,而ARM需要load+算两个指令)。CPI——平均每指令周期数——受微架构(流水线、Cache命中率、分支预测准确率)影响。频率——受工艺技术和电压控制。三个因子之间互相关联——试图减少指令数就经常使用那条占更多周期的复杂指令(CISC的长处)从而影响CPI;提高频率必然会增加深度流水线的分支预测惩罚CPI的代价。
计算机系统的核心组件互连
现代PC的CPU通过加速器与高速外设交互:
- CPU-PCIe桥(Uncore/IO die):CPU通过集成PCIe控制器接管显卡和NVMe SSD。这些设备在每个CPU本地有自己的内存地址映射区间并且可以通过MMIO访问配置寄存器。
- 内存控制器:现已集成在CPU内部(IMC)——每一块DDR内存条直接连接到CPU的内存通道上而不通过北桥。目前的消费级CPU通常提供2通道(AMD)或者4通道(Intel高端平台)的内存控制器——多通道配置提供了更大的总内存带宽(近似为单通道带宽的通道数倍)并且交织分配命中延迟的波动较小。
- DMI(直接媒体接口):连接CPU和PCH(南桥)的专用总线——负责USB、SATA、低配网卡以及其他较慢速外设的数据流。
这一架构的变迁(从北桥/南桥的芯片组分立到CPU集成内存控制器)大大降低了CPU到内存的延迟——IMC可以直接在一个时钟域内发起读请求而无需通过外部北桥芯片去跨芯片桥接。
冯诺依曼结构的意义
冯诺依曼结构的核心"存储程序"——程序和数据以二进制形式存放在同一存储器中——是现代计算机的基础。取指执行变得连续且灵活。因为它将程序视为可读写在RAM中的特殊数据模式——所以同一台硬件可以通过加载不同的程序改变行为、JIT编译器可以在运行时生成机器码(JavaScript引擎的JIT就是这一设计的产物)。
存储程序概念的副作用——指令和数据共享同一条总线——这就是"冯诺依曼瓶颈"的根源。CPU不能同时取指令和访问数据——除非用分离的指令和数据Cache。在极端情况下——一条同时需要取指令(取指总线)和读数据(访存总线)的指令会彼此延迟——尤其在数据量极大的多媒体处理、密码学运算中非常明显。