计算机基础:CPU 与计算核心

理解数据单位(位与字节)、CPU 架构、五级流水线、缓存层级、分支预测、乱序执行、多核与 SMT、Intel vs AMD 差异,以及如何选购合适的处理器。

为什么 100 Mbps 宽带下载只有大约 12 MB/s?为什么"1 TB"硬盘在 Windows 里只显示 931 GB?为什么 32 位系统最多只能用约 3.2 GB 内存?当 CPU 真正开始执行你的代码时,每个时钟周期里到底发生了什么?

这是计算机基础系列的第一篇。我们从 bit 与 byte 出发,一路走进 CPU 内部:流水线、缓存、分支预测、乱序执行、多核与 SMT。读完之后,你应该能看懂 CPU 规格表上每一个数字代表的成本,也能看懂 perf profile 上每一行延迟的来历。

系列导航

计算机基础(共 6 篇):

  1. CPU 与计算核心 —— 当前位置
  2. 内存与缓存层级
  3. 存储系统(HDD、SSD、NVMe、RAID)
  4. 主板、显卡与扩展总线
  5. 网络、电源与散热
  6. 综合实战:把所有部件串起来

三个真实世界的疑问

疑问 1 —— 宽带"缩水"。 运营商卖的是"100 Mbps",浏览器下载峰值却只有 12 MB/s。被坑了吗?

疑问 2 —— 消失的 69 GB。 买了 1 TB 硬盘,Windows 显示 931 GB。坏盘?

疑问 3 —— 帧率反转。 朋友 14 核 i5-13600K 跑 CS2 大约 450 FPS,你的 16 核 R9 7950X 只有 420 FPS。核心更多,帧率更低 —— 为什么?

这三个答案都在文章里。

第一部分 —— 数据单位:计算机世界的度量衡

Bit 和 Byte

一个 bit 就是一位二进制:0 或 1。想象一个开关:关或开。8 个开关组合在一起能表示 2^8 = 256 种不同状态 —— 正好够编码原始 ASCII 表里的英文字母、数字和标点。这就是 byte = 8 bit 的由来。

“Mbps vs MB/s” 的陷阱:运营商按 bit 每秒(Mbps)卖带宽,浏览器按 byte 每秒(MB/s)显示。换算只需除以 8。

你看到的实际含义
100 Mbps每秒 1 亿 bit
12.5 MB/s(理论上限)每秒 1250 万 byte
10–11 MB/s(实测典型值)扣掉 TCP 开销和网络拥塞之后

所以 “100M” 宽带确实能跑到大约 12 MB/s 左右。没人在骗你 —— 单位不一样而已。

1024 vs 1000 的错位

计算机按 2 的幂计数;最接近 1000 的 2 的幂是 2^10 = 1024。所以在计算机内部,1 KB = 1024 B,1 MB = 1024 KB,依此类推。但硬盘厂商使用国际单位制(SI),1 KB = 1000 B。这一个差异,就是"1 TB 硬盘只显示 931 GB"的全部原因。

单位(二进制,操作系统)字节数单位(十进制,厂商)字节数
1 KiB1,0241 KB1,000
1 MiB1,048,5761 MB1,000,000
1 GiB1,073,741,8241 GB1,000,000,000
1 TiB1,099,511,627,7761 TB1,000,000,000,000

速算:实际容量 ≈ 标称容量 × 0.931

标称容量实际可用表观损失
256 GB238 GiB7.0%
1 TB931 GiB6.9%
2 TB1,863 GiB6.9%
4 TB3,726 GiB6.9%

内存条不会"缩水",因为内存模块从一开始就按二进制单位定容:8 GB 内存条恰好就是 8 × 2^30 字节。

第二部分 —— 走进一颗 CPU 核心

CPU 究竟在做什么

CPU 的工作说出来很简单,做起来极其复杂:取下一条指令,解码它,执行它,把结果写回,每秒重复几十亿次。所有别的东西 —— 流水线、缓存、分支预测器 —— 都是为了让这个循环跑得更快,又不改变程序的语义。

一颗现代核心里有四类硬件:

  • 前端(控制):取指、解码、分支预测器。
  • 执行(计算):整数 ALU、浮点和 SIMD 单元、Load/Store 单元。
  • 寄存器堆:极小但极快的暂存(x86-64 有 16 个通用寄存器,再加上 AVX-512 向量寄存器)。
  • 缓存:L1 指令 + L1 数据(每核心私有)、L2(每核心私有)、L3(核间共享)。

图 1. CPU 核心结构:前端、执行、寄存器、缓存层级

前端准备工作;执行单元完成工作;寄存器堆保存执行单元要读的操作数;缓存把工作集压在足够近的地方,让整条流水线满速运转。

五级流水线

教科书上的经典流水线分五级:

  1. IF —— 取指(从 L1I 读下一条指令)
  2. ID —— 解码(搞清楚是什么指令,读寄存器操作数)
  3. EX —— 执行(跑 ALU)
  4. MEM —— 访存(Load / Store)
  5. WB —— 写回(把结果提交到寄存器)

如果不重叠,每条指令要 5 个周期,5 条指令就是 25 个周期。引入流水线之后,每个周期一条指令进入 IF,前一条移到 ID,依此类推。预热 4 个周期之后流水线被填满,每个周期完成一条指令 —— 理想 IPC(每周期指令数)= 1.0

图 2. 五条指令在 9 个周期里重叠完成,而不是串行的 25 个周期

真实的 x86 核心,比如 Intel Golden Cove 或者 AMD Zen 4,要宽得多 —— 每周期解码 6 到 8 条指令,流水线深度 10 级以上 —— 但思路完全一样:让每一级、每一个周期都不空转。任何制造气泡(让某一级闲下来)的事件都会损失吞吐。下面四节,全都是在讲怎么避免或者掩盖这些气泡。

内存层级

如果主存和寄存器一样快,所有缓存机制就没必要存在。但事实并非如此。从寄存器到机械硬盘,延迟差大概八个数量级

图 3. 内存层级:访问延迟(纳秒,对数坐标)

层级延迟容量实现工艺
寄存器~0.3 ns几十字节核心内的触发器
L1 缓存~1 ns32–64 KBSRAM,每比特 6 个晶体管
L2 缓存~4 ns256 KB–1 MBSRAM(更密、更慢)
L3 缓存~15 ns8–64 MBSRAM(多核共享)
DRAM(DDR4/5)~90 ns8–128 GB1 个晶体管 + 1 个电容 / 比特
SSD(NVMe)~100 µs0.5–8 TBNAND 闪存
HDD~10 ms1–20 TB旋转磁盘

一个好用的心理模型。 把 CPU 时钟周期放大成"人脑思考 1 秒"(大约 1 ns → 1 s):

  • L1 命中:瞬间,“我记得”。
  • L3 命中:15 秒,走到隔壁工位。
  • DRAM:90 秒,走到隔壁房间。
  • SSD:一天半。
  • HDD:4 个月。

这就是为什么一次 L3 miss 要浪费几十个周期,也是为什么一段对缓存友好的内层循环,可以比一段对缓存不友好的循环快 10 倍 —— 即使两段做的算术完全相同。

缓存的三种 miss

缓存不是魔法,它会以三种不同的方式失败。知道是哪一种 miss,才知道怎么修。

图 4. 3C 分类:强制(cold)、容量、冲突

  • 强制 miss(cold):这块数据第一次被访问,缓存里从来没见过。第一次必然 miss;可以靠预取(prefetch)把延迟掩盖掉。
  • 容量 miss:工作集比缓存大。即使是一个完全相联、调度完美的缓存,仍然会 miss。修复办法:缩小工作集(blocking / tiling),或者用更大的缓存层。
  • 冲突 miss:低相联度的缓存里,多个热点块抢同一个 set。两个数组,地址恰好相差一整个 set 的字节数,会反复把对方踢出去。修复办法:调整数据布局、做 padding,或者依赖更高相联度的缓存。

现代 L1 缓存普遍是 8-way 相联,L2/L3 更高,所以纯粹的冲突 miss 比早期处理器上少见 —— 但在按 2 的幂步长扫数组的紧密循环里依然会出现。

分支预测

条件分支是流水线的噩梦:当 if (x > 0) 在 EX 阶段真正知道结果时,后面三四条指令早就已经按某条路径取进来了。如果猜错了,所有飞行中的工作都得作废重新取 —— 现代核心一次分支预测错误的代价是 15–20 个周期

经典做法是双比特饱和计数器,预测表里每个分支配一个:

图 5. 双比特预测器状态机;不同代次预测器的准确率

这个状态机有个很妙的性质:单次反常的结果不会立刻翻转预测,必须连续两次错才会切换。光这一招,在常见工作负载上就能拿到约 93% 的准确率。现代预测器(TAGE、感知机型)通过同时观察最近一段分支历史,把准确率推到 98% 以上 —— 历史能捕捉到诸如"外层循环走了真分支,内层循环也通常走真分支"这类相关性。

如果你在 C++20 代码里见过 [[likely]] / [[unlikely]],或者 GCC 的 __builtin_expect,那是你在帮编译器帮预测器。

乱序执行

就算分支预测做得很好,流水线还是会因为数据等待而停摆:一次 DRAM Load 大约要 90 ns(3 GHz 下约 300 个周期)才能把数据送到,任何这个值的指令都要等。顺序执行的核心跟着一起等;后面所有指令也跟着一起等。

**乱序执行(OoO)**核心做的事更聪明:把已经解码的几十甚至几百条指令缓冲在重排序缓冲区(ROB)里,只要操作数就绪,就调度执行 —— 不管它在程序里排在第几位。只要对外可见的结果(架构寄存器状态、内存)和顺序执行一致,硬件爱怎么调度都行。

图 6. 同一段五条指令的执行序列:顺序 vs 乱序

例子里 I3 和 I4 都不依赖那次 LOAD。顺序核心把它们卡在 I2 后面;乱序核心把它们塞进 LOAD 还在飞行的那几个周期里。结果:6 个周期而不是 8 个 —— 这只是一个玩具例子。在真实负载上,配合大窗口(据报道苹果 M3 的 ROB 容量约 600 条 micro-op),收益又大又完全自动,程序员不用操任何心。

乱序执行也是为什么微基准测试经常说谎:如果你的循环体里指令彼此独立,CPU 会把它们并行起来,你测到的其实是瓶颈单元的吞吐,而不是任何单条指令的延迟

多核与 SMT(超线程)

要在不让单核更快的前提下加并行度,有两条路:

  1. 多核。 把所有东西都复制一份:前端、ALU、寄存器、L1、L2。只有 L3 和内存控制器共享。
  2. SMT(Intel 叫 Hyperthreading)。在一个物理核心内,保留两套架构寄存器,让两个软件线程共享同一套执行单元。

图 7. 多核结构(左);SMT 如何填补空闲执行槽(右)

SMT 的关键直觉: 当一个线程停摆(缓存 miss、分支预测错误)时,它的执行单元就闲着。SMT 让另一个线程立刻把那些槽位用起来。混合负载下典型收益是 +20–30% 吞吐不是 2 倍 —— 因为两个线程共享同一套 ALU、同一个 L1 缓存、同一组发射端口。在已经把执行单元跑满的纯计算密集型代码上(比如紧凑的矩阵乘法),SMT 甚至会拖慢你 —— 因为它给缓存增加了压力。这也是 HPC 工作负载经常关掉超线程的原因。

这正好回答了开篇的疑问 3。CS2 在 450 FPS 上,瓶颈不是核心数 —— 在那个帧率下,引擎主线程才是长杆。i5-13600K 的单线程性能高于 R9 7950X(更新的 P-core、更高的睿频、每核更大的 L2)。7950X 多出来的核心闲在那里。只有当工作能拆成更多并行线程时,更多核心才有用

第三部分 —— 选购 CPU

当下的 Intel vs AMD

当前一代的核心权衡:

维度Intel(13/14 代酷睿)AMD(Ryzen 7000 / 9000)
单线程峰值很高(P-core 睿频接近 6 GHz)很高(Zen 4/5 IPC)
多线程吞吐E-core 提供宽多线程高核心数,全部对称
工艺节点Intel 7 / Intel 4TSMC 5 nm / 4 nm
平台寿命LGA 1700(12/13/14 代)AM5(承诺至少到 2027 年)
能效高端略弱总体更好
最适合游戏、混合负载内容创作、大型编译

按场景选:

  • 游戏:最看重单线程。中端 Intel i5/i7 或者高睿频的 Ryzen 7 是甜点。
  • 视频剪辑、3D 渲染、大型代码编译:核多者胜。Ryzen 9 或 Threadripper。
  • 办公、网页、轻度开发:任何一颗现代 4–6 核 CPU 都绰绰有余。
  • 服务器:AMD EPYC(最多 96+ 核、12 通道 DDR5、更多 PCIe 通道)目前在密度和性价比上领先;Intel Xeon 在某些带加速器的负载(AMX、QAT)上仍占优。

32 位 vs 64 位 与 4 GB 天花板

32 位地址总线能寻址 2^32 = 4 GiB 个内存位置。但 32 位操作系统必须把内存内存映射 I/O(显存窗口、BIOS、PCIe 设备寄存器)一起塞进这 4 GiB。最高约 0.5–1 GiB 留给 MMIO,真正能给 RAM 用的就是约 3.0–3.5 GiB —— 这就是"装了 4 GB,Windows 显示 3.25 GB"的真相。唯一真正的解药是换 64 位操作系统,2^64 ≈ 16 EiB 的地址空间彻底结束这个话题。

ECC、多路与服务器主频为什么更低

服务器 CPU 的取舍不一样,因为它要跑的负载不一样:

  • ECC 内存能检测并纠正单比特错误。在服务器规模(成千上万根 DIMM、24/7 运行)下,比特翻转发生得足够频繁;在金融、科学计算和任何关安全的场景里,ECC 是底线。
  • **多路(multi-socket)**让两路或四路 CPU 共享一份相干的内存映像,适合超大数据库和虚拟化主机。
  • 更多 PCIe 通道(64–128 vs 桌面端约 20)能挂更多 GPU、NVMe 盘和 100 GbE 网卡。
  • 更低的时钟(全核约 3 GHz,而不是单核冲到 5.8 GHz)牺牲峰值频率,换来在持续高负载下显著更好的能效和可靠性。桌面 CPU 是短跑选手;服务器 CPU 是马拉松选手。

速查清单

  • 带宽按 bit,文件按 byte —— 除以 8。
  • 硬盘按 1000 进制,操作系统按 1024 进制 —— 标称 TB 乘 0.931 就是实际 GiB。
  • 流水线的理想是每周期一条指令;缓存、分支预测、乱序执行,全都在保卫这个理想。
  • 内存延迟跨越八个数量级。缓存局部性通常是单一最大的性能杠杆。
  • 一次错误预测约 15–20 个周期。一次 DRAM miss 约 300 个周期。预测器和缓存就是用来掩盖这些代价的。
  • SMT 一般给你 +20–30%,不是 2 倍。
  • 更多核心只对能并行的工作有用,游戏通常不在内。

下期预告

第二篇 —— 内存与缓存层级 —— 会更深入:

  • DDR2 到 DDR5 各代到底快在哪?
  • 双通道、四通道:真实跑出来的基准。
  • 缓存相联度、替换策略,以及怎么用 perf 量缓存 miss。
  • 内存故障排查:黑屏、蓝屏、MemTest86。

留个思考题: 如果 CPU 已经有 L1/L2/L3 缓存,为什么还需要 DRAM?(提示:每美元容量、SRAM 的硅成本。)

延伸阅读

  • Hennessy & Patterson, Computer Architecture: A Quantitative Approach —— 计算机体系结构经典。
  • Bryant & O’Hallaron, Computer Systems: A Programmer’s Perspective(CSAPP)—— 本科经典教材。
  • Agner Fog 的优化手册 —— 实用的 x86 微架构细节。
  • Intel ® 64 and IA-32 Architectures Software Developer’s Manual。
  • AMD64 Architecture Programmer’s Manual。
  • WikiChip —— 几乎所有现代微架构都有简洁、准确的 die 图。

Liked this piece?

Follow on GitHub for the next one — usually one a week.

GitHub