硬件地图
点一个框看它是什么、在哪篇讲过;选一条路径,一步一步看指令和数据怎么走。蓝字可以直接点开对应的文章。
English
速查页
静态图
一次 load 走到内存
一次 store
分支猜错
指令从哪来
看原尺寸
硬件地图:一次访存会经过哪些层
蓝字 = 在哪里讲过(#N = 交易系统笔记 #N,MESI = 专题,速查 N.N = 速查页的小节)。数字都是量级。
实线箭头 = 指令和数据怎么走;红色虚线 = 分支猜错后冲刷、重新取指;灰色虚线 = 核与核之间的一致性消息。
CPU 插槽 0(socket)= 一个 NUMA 节点
#1 绑核 / 隔离 · NUMA
核心 0(core)
2 个硬件线程共用这个核(SMT,超线程,#1)
前端(front end):取指令
后端(back end):乱序执行
访存(memory):load / store
分支预测器(BPU)
BTB · RAS · 方向预测器
猜下一条指令在哪
#7 分支预测
取指(fetch)
按预测的地址从 L1I 取指令
猜错的路径上取的全部作废
#7 推测执行
译码(decode)
指令 → 微操作(µop)
L1I 32 KiB(指令缓存)
存指令,不存数据
#6 函数分组
重命名 + ROB
ROB(reorder buffer,重排序缓冲)
记着还没退休的指令
速查 2.3 ROB 与 MLP
· #16 PAUSE
调度 → 执行单元
ALU 算数 · AGU 算地址
分支在这里算出真假
#2 依赖链 · 多累加器
· #12 除法器
退休(retire)
按程序顺序提交结果
寄存器(register file)
#2 寄存器溢出
#6 存储类别
dTLB(数据 TLB,地址翻译)
没命中:从 CR3 指的根往下走 4 级
#6 2 MiB 大页
· #3 TLB shootdown
速查 2.1 TLB 覆盖范围
Store buffer
存储缓冲
写先在这排队,
按顺序写进 L1D
#2 store buffer
#2 store-to-load
转发
Invalidate queue
失效队列
别的核发来的
invalidate 请求先排队
#2 invalidate queue
#2 acquire
L1D 32 KiB · 8 路(数据缓存)
LFB(line fill buffer,行填充缓冲)
#6 对齐 / 跨行 · 组相联
速查 2.3 LFB
L2 512 KiB · 8 路(本核私有,指令和数据共用)
#6 关键步长 64 KiB
· #2 L1/L2 私有
缓存和内存之间按 64 B 一整条“缓存行”搬运
#2
· #6 一次访问碰几条行
µop
提交
store
核心 1 … 核心 5(结构和核心 0 相同)
核心 1
前端
后端
L1I · L1D
L2
核心 2
前端
后端
L1I · L1D
L2
核心 3
前端
后端
L1I · L1D
L2
核心 4
前端
后端
L1I · L1D
L2
核心 5
前端
后端
L1I · L1D
L2
MESI:单写者 / 多读者
同一条缓存行可以在多个核的 L1/L2 里各有一份副本。
谁要写,就得先让别人的副本作废(发 invalidate 请求)。
MESI 专题
#2 伪共享(两个核抢同一行)
#4 缓存游标
· #5 读者越多写越贵
#6 alignas(64) 让对象独占一行
#16 自旋锁:TTAS、排队锁、umwait
每个核各有自己的 L1、L2
(TLB、store buffer 也各有一份)
别的核要写某一行:发 invalidate 请求,排进核心 0 的 invalidate queue
一致性
L3 16 MiB · 16 路(全部核共享)
#2 L3 共享
· #6 高位哈希选组
内存控制器:把连续地址轮流分到各个通道(交织)
#6 多通道均衡(行数和通道数互质)
内存条(DRAM)
#6
通道 0
DIMM → rank → 多个 bank
一个 bank = 行 × 列的表
行缓冲:当前打开的那一行
命中已打开的行 ~15 ns
换一行(行冲突)~40 ns
刷新:每 ~7.8 µs 一次,
卡 300–500 ns → P99 毛刺
通道 1
结构同通道 0
各通道能同时工作,
带宽 ≈ 通道数 × 单通道
通道 2 …
结构同通道 0
页表(每个进程一份)
4 级的树,CR3 指着根那一页
和普通数据一样散在各通道里
页表项会被缓存进 L1/L2/L3,
TLB 没命中多半不用真来这里
进程线程 4.2
· #3 TLB shootdown
CPU 插槽 1
自己的核、L3、内存控制器和内存
访问另一个插槽的内存要过互连,更慢
#1 NUMA:线程和内存放同一节点
速查 2.1 first-touch 放置
插槽间互连
网卡 → 中断 → 某个核
#1 中断绑到非热路径的核
(操作系统层,不是缓存层)
一个地址的各段(4 KiB 页,L1D 32 KiB 8 路,64 B 行)
虚拟页号(bit 12 以上)→ TLB 翻译
大页:页号变少,TLB 装得下
组号 bit 6–11
#6 相差 4 KiB 倍数 → 同一组
行内偏移 bit 0–5
#6 对齐 = 这几位为 0
页内偏移 bit 0–11:翻译前后不变,所以 L1 能一边翻译一边选组(VIPT)
→ L1 的“组数 × 行大小”被卡在 4 KiB,做大只能加路数
访问延迟量级
周期按约 4 GHz 折算。每往下一层,大约慢 3–10 倍。
访问时间
容量
谁来管理
~1 周期(< 1 ns)
约 1 KB
编译器
寄存器
4–5 周期(~1 ns)
32–48 KiB / 核
硬件
L1D 缓存
~12–20 周期(~3–5 ns)
0.5–2 MiB / 核
硬件
L2 缓存
~40–120 周期(~10–30 ns)
约 10–500 MiB,全部核共享
硬件
L3 缓存
~300–500 周期(~70–120 ns)
约 16 GB 到 4 TB
操作系统(页表)
本地内存
~500–800 周期(~120–200 ns)
另一个插槽的内存
操作系统 + 你绑的位置
远端 NUMA 内存
10–100 µs
TB 级
操作系统(文件系统)
NVMe SSD
核内
芯片内
芯片外
外部设备
数字都是帮助理解的量级,不对应哪台机器。
图随文章更新:后续文章讲到新的硬件层时再往上补标注。