从硬件看程序
源代码经过编译、链接等步骤,最终可以形成 CPU 能执行的机器指令。程序运行时,CPU 读取指令和数据,执行计算,并通过内存和设备交换结果。
可以先把计算机看成运算器、控制器、存储器、输入设备和输出设备的协作系统。CPU 中的 ALU 负责算术和逻辑运算,控制逻辑协调执行,寄存器保存当前正在处理的少量数据。
指令执行的基本过程
一种教学上的划分是取指、译码、执行、访存、写回。不是所有指令都需要每个阶段,也不是所有处理器都严格使用这五级结构。
以从内存取数、加一、写回为例,伪汇编可以写成:
LOAD R1, [address]
ADD R1, R1, 1
STORE [address], R1
第一条把数据放入寄存器,第二条计算结果,第三条写回内存。这只是说明执行思路,具体语法和行为由指令集决定。
程序计数器 PC 跟踪指令位置,跳转和分支会改变后续取指位置。指令集规定程序能够使用哪些指令、寄存器和寻址规则;微体系结构决定某个处理器怎样具体实现它们。同一种指令集,可以有性能和功耗差异很大的处理器。
二进制、补码与字节序
一个字节通常是 8 位。n 位无符号整数的范围是 0 到 。采用补码表示时,n 位有符号整数的范围是 到 。
例如 8 位补码中,00000101 表示 5,11111011 表示 -5。位宽有限,所以运算可能溢出;语言对溢出的规定并不完全相同,不能仅靠硬件直觉推断所有语言的结果。
多字节数据还涉及字节序。对于 0x12345678,小端方式在低地址放 78,大端方式在低地址放 12。字节序讨论的是字节排列,不是把每个字节内部的位倒过来。
性能为什么不能只看主频
常见的分析公式是:
其中指令数是程序动态执行的数量,CPI 是平均每条指令所需周期数,时钟周期等于主频的倒数。假设执行一亿条指令,平均 CPI 为 2,主频为 2 GHz,则 CPU 时间为 0.1 秒。
这个公式用于解释 CPU 执行时间。程序的实际耗时还可能包含等待网络、磁盘和调度的时间,因此主频翻倍不代表网页请求一定快一倍。
流水线提高什么
流水线让多条指令的不同阶段重叠执行,提高吞吐量。它不保证单条指令的延迟缩短,额外的阶段寄存器等因素还可能增加延迟。
常见阻碍包括争用同一硬件资源、后一条指令依赖前一条的结果,以及分支导致下一条指令位置不确定。处理器可以采用转发、暂停、预测等办法处理这些问题。入门可参考 Cornell CS 3410 的流水线讲义。
存储层次与局部性
寄存器、各级缓存、主存和持久存储在容量、成本与访问速度之间做不同取舍。缓存利用两种常见现象:最近使用的数据可能再次使用,附近的数据可能很快被访问。
因此,顺序遍历连续数组常常比到处追踪指针更有利于缓存。缓存通常以缓存行为单位搬运数据;命中率之外,命中耗时和未命中代价也影响结果。基本模型可以写成:
这里的 AMAT 是平均访问时间,未命中代价应与命中时间分开计算。多级缓存需要按层次进一步展开。更多例子见 Cornell CS 3410 的缓存讲义。
中断、DMA 与 I/O
CPU 不必一直轮询每个设备。设备可以通过中断通知处理器某个事件;处理器保存必要的执行状态,再执行相应处理逻辑。
DMA 让设备或控制器在完成配置后直接参与内存数据传输,减少 CPU 逐个搬运数据的工作。CPU 仍要负责准备、协调和处理完成事件,DMA 不意味着整个 I/O 过程完全不需要 CPU。
练习:把几个概念连起来
假设某缓存命中时间为 1 ns,未命中率为 5%,额外未命中代价为 80 ns,平均访问时间是多少?代入公式得到 5 ns。然后思考:若只把主频提高一倍,而内存访问仍然很慢,程序为什么未必快一倍?
继续学习时,可以按“数据表示 → 指令集 → CPU 数据通路 → 流水线 → 缓存 → I/O”的顺序。再回到操作系统基础,看页表、线程调度与设备管理怎样使用这些硬件能力。