SICI · 天机门 · 第九章

存储天梯

速度与容量的博弈 · 筑基三层

没有局部性,就没有层次;没有层次,就没有速度。代价不是惩罚,是这架天梯存在的物理前提。

门楣刻字:「每一级之间,隔着十倍、百倍、千倍」
序章

天梯悬空

CPU 与主存之间,差多少倍?

天梯从黑暗中生长出来。不是横着的路,是一架直插云霄的梯。每一级台阶都发着不同颜色的光——顶端白得刺眼,越往下越暗,到底部只剩一团铁锈色的闷红。

存储天梯自微光中生长,七级台阶从寄存器到磁盘逐级延展

诺依曼老祖站在梯脚下,手边悬着七块铭牌:寄存器、L1、L2、L3、主存、SSD、磁盘。

诺依曼老祖 诺依曼老祖

「你脚下的这片梯,每一级之间隔着十倍、百倍、千倍的速度差。你以为从顶到底不过是一步路。」

未命中之罚 未命中之罚

「梯的深处有什么东西在呼吸。很慢。很沉。猜猜,CPU 和主存之间差多少倍?」

存储层次倍率预测挑战器

先下注猜倍率 → 拖拽铭牌排梯 → 拨动局部性拨杆验证。👆 猜对 1000 倍才能排梯

深渊:「CPU 寄存器和主存之间差多少倍?」
详解 · K09-01 局部性原理

局部性分两种:时间局部性——刚用过的数据很可能很快再用(循环变量、热点代码);空间局部性——访问某地址后,邻近地址也很可能被访问(数组遍历、顺序取指)。正是局部性让「小而快 + 大而慢」的层次结构成立:绝大多数访问落在高层,慢层只在少数时刻被触碰。若访问完全随机,cache 命中率将趋近于容量占比,整架天梯即刻失效。

第一幕 · 自信

器灵殿 · SRAM 与 DRAM

快的技术贵,便宜的技术慢——六比一的交易

器灵殿里没有梯,只有两座台。左台上悬着一枚六边形的晶体阵列——六个晶体管咬合成环。右台上躺着一枚孤零零的单管——旁边附着一个微不可见的电容。

诺依曼老祖 诺依曼老祖

「半导体册教过你观其形——六管阵、单管阵。但你可知它们为何一座快、一座慢?为何快的那座做不大、慢的那座必须刷新?」

SRAM 六管阵 / DRAM 单管阵 拆解 + 电子天平

点击点亮晶体管 → 拨字线读出 → 拖上天平对比面积/密度

SRAM 六管阵(点击点亮 M1-M6)
DRAM 单管+电容(点击拨字线)

电子天平 · 面积/密度/速度三维对比

详解 · K09-02 存储器分类

按易失性与用途分层:SRAM 做 cache(片上、最快最贵)、DRAM 做主存、Flash 与磁盘做持久存储。沿「寄存器→SRAM→DRAM→Flash→磁盘」下行,容量逐级放大,速度逐级放缓——相邻两级之间差 2~5 个数量级。

详解 · K09-03 SRAM 单元结构

6T 单元:两个交叉耦合的反相器(4 管)构成双稳态锁存器,外加 2 个存取管接位线。双稳态意味着只要供电,数据就一直在——无需刷新,读写都快;代价是 6 个管子存 1 位,面积大、成本高,只配做 cache。

详解 · K09-04 DRAM 单元与刷新

1T1C 单元:1 个管子 + 1 个电容,靠电容上的电荷表示 0/1。电容会漏电,必须在 ~64ms 内把全片刷新一遍;而且读是破坏性的,读完要回写。换来的是密度——同样面积下 DRAM 容量约为 SRAM 的 6~8 倍,所以主存非它不可。

第一幕 · 以为懂了

命中台 · AMAT 公式

5% 的缺失,换来六倍于理想值的访问时间

命中台是一面巨大的石壁,上面刻着三个词:命中率、缺失代价、命中时间。老祖递给你一支笔:「把这三个数填进去。命中时间 L1 约 1 纳秒,缺失代价主存约 100 纳秒,命中率……你自己定。」你写下 95%。

未命中之罚 未命中之罚

「95%?挺好。记下了。延迟账本第二页。该清账的时候,我会叫你。」

AMAT 公式拼装器

拖数值进槽 → 拼运算符 → 看石壁翻转对比

详解 · K09-05 命中率 · 缺失代价 · 命中时间

三个基本概念:命中率 H——访问落在 cache 的比例;命中时间 T_hit——命中时的访问延迟(含命中判定);缺失代价 T_miss——缺失后从下一级取块的额外开销。cache 设计的全部艺术,就是在硅面积预算内把 H 推高、把 T_hit 和 T_miss 压低。

详解 · K09-15 AMAT 的计算

AMAT = T_hit + (1 − H) × T_miss。例:T_hit = 1ns、T_miss = 100ns,H = 95% 时 AMAT = 1 + 0.05×100 = 6ns;H 提到 99% → 2ns;降到 90% → 11ns。多级展开:AMAT = T_L1 + (1−H_L1) × (T_L2 + (1−H_L2) × T_mem),注意每级用的是局部缺失率。1 + 0.05×(5 + 0.5×100) ≈ 3.75ns——层次越深,摊得越薄。

第一幕 · 崩塌

AMAT 之罚 · 悬崖曲线

你以为直线下坠,实际是悬崖

石壁翻转后露出一面更大的算盘——上面挂着一排可拖动的命中率刻度,从 99.9% 到 50%。你拖到 99%——AMAT=2ns。拖到 95%——6ns。拖到 90%——11ns。曲线画出来,不是一条直线,是一条越掉越快的悬崖。

未命中之罚 未命中之罚

「你以为直线下坠,实际是悬崖。第二笔。95%。六倍。记下了。」

AMAT 悬崖曲线追踪器

拖动命中率 99%→50%,AMAT 实时计算描点画曲线。必须拖到 90% 以下

AMAT = T_hit + (1-H) × T_miss = 2.00 ns

三大性能指标(随 H 同步变化)

详解 · K09-14 延迟 · 带宽 · 吞吐量

三个性能指标别混淆:延迟——完成一次访问要多久(纳秒);带宽——单位时间能搬多少数据(GB/s);吞吐量——单位时间完成多少请求(IOPS)。悬崖曲线揭示的是延迟维度的敏感性:当 T_miss / T_hit = 100 时,缺失率每涨 1 个百分点,AMAT 就多吃 1ns——命中率在小数点后两位上的较量,直接决定系统快慢。

第二幕 · 挣扎

映射阵 · 一位之困

直接映射最简单——但两个地址撞同一 Index 就驱逐

映射阵是一面巨大的地址墙,墙上刻着 32 个格子。老祖指着墙下三座阵盘:「直接映射——一个地址只去一个位置。全相联——哪都能去。组相联——去一组里的任意位置。你先试直接映射。最简单。」

诺依曼老祖 诺依曼老祖

「你先试直接映射。最简单。但简单是有代价的——你省下的硬件,全部变成了 miss。」

地址拆解 + 三阵盘切换 + 冲突演示

拖地址位进 Tag/Index/Offset 三槽 → 切换三阵盘 → 喂冲突地址

32 位地址拆解(cache 4KB / 块 32B / 直接映射 128 行)
详解 · K09-06 映射三方式

直接映射:每个主存块只有唯一可放位置,只需 1 个比较器,最快最省,但冲突最多。全相联:任何块可放任何位置,零冲突,但比较器数量 = 行数,贵且慢。n 路组相联:组内 n 个位置任选,n 个比较器——现代 CPU 的 L1 常用 4~8 路,是硬件成本与缺失率的标准折中。

详解 · K09-07 地址分解:Tag | Index | Offset

物理地址被切成三段:Offset 选块内字节(32B 块 → 5 位),Index 选 cache 组/行(128 行 → 7 位),剩下高位是 Tag(32 − 5 − 7 = 20 位),用来确认「这一行里住的是不是我要的那块」。Tag 比对由比较器完成——比较器个数,正是映射方式的核心成本。

第二幕 · 再崩塌

冲突之祸 · 3C 缺失分类

100% 缺失率——你设计的 cache 比没有 cache 还慢

阵盘上跑起了一段程序:for (i=0; i<256; i++) sum += A[i] + B[i]; A 从地址 0 开始,B 从 4096 开始。直接映射,128 行,32 字节一块。A[0] 和 B[0] 的 Index 都是 0——同一个位置。A[0] 进来,B[0] 把 A[0] 踢走。每一次访问都是缺失。命中率:0%。

未命中之罚 未命中之罚

「延迟账本第二页。你选了最省硬件的方案。省下的比较器,全变成了 miss。」

3C 缺失分类相图探索器

跑程序看 hit/miss → 切组相联看冲突归零 → 拖容量/路数看相图

缺失分类统计

详解 · K09-16 缺失分类(3C)

强制缺失(Compulsory):冷启动,块第一次被访问必缺——预取可缓解。容量缺失(Capacity):工作集超过 cache 总容量,再相联也没用——只能增大容量或优化程序的数据复用。冲突缺失(Conflict):容量够但相联度不够,多个热块抢同一组——增大路数专治。判别口诀:无限容量仍缺是强制;同容量全相联不缺而组相联缺,差额就是冲突。

第二幕 · 喘息

替换殿 · LRU 的代价

LRU 是理论最优——但它的代价随路数阶乘爆炸

替换殿里悬着四把钥匙:LRU、FIFO、随机、伪 LRU。老祖说:「组满了,踢谁?你选。」你选 LRU。系统喂入 A B C D A B E——E 进来时组满了。LRU 踢掉 C。但面板弹出一行数字:「4 路 LRU 需记录 4!=24 种顺序,至少 5 位。8 路?8!=40320,15 位。128 路全相联呢?」老祖笑了。

诺依曼老祖 诺依曼老祖

「LRU 是理论最优。但它的代价随路数阶乘爆炸。伪 LRU 用一棵树、n−1 个位,近似了 LRU 95% 的效果。」

四种替换策略对比 + 硬件代价曲线

同一序列 A B C D A B E 在 4 路组上跑四种策略 → 看代价曲线

访问序列:A B C D A B E(4 路组相联)

硬件代价 · 位宽 vs 路数

四种策略命中率对比

详解 · K09-08 替换策略:LRU / FIFO / 随机 / 伪 LRU

精确 LRU 要记录 n 个块的全序,共 n! 种排列 → 需要 ⌈log₂(n!)⌉ 位:4 路 5 位、8 路 15 位,随路数阶乘爆炸。FIFO 简单但会踢走常驻热块;随机替换 实现最简,实测性能并不差太多;伪 LRU(PLRU) 用一棵二叉树、n−1 个位记录「哪半边更久没用」,逼近 LRU 效果而代价可承受——工程主流。

第二幕 · 收束

写阵与多级塔 · 脏位的代价

写回换来了吞吐量,代价是脏块驱逐时的翻倍缺失

写阵的墙上挂着四块牌:写直达、写回、写分配、非写分配。老祖指着一块悬空的塔模型:「L1、L2、L3——三级塔。L1 私有最快,L3 共享最慢。每一级都是一座更慢但更大的桥。」你挂了写回——写只动 cache,标记脏位,驱逐时才写回。但塔模型底部亮起一行字:「脏块被驱逐时:先写回 L2 → 再从 L2 读入新块。缺失代价翻倍。」

未命中之罚 未命中之罚

「你以为延迟没有代价?延迟的账,迟早要还。」

写策略挂牌 + 多级塔模型 + 多级 AMAT

挂写策略组合 → 拖程序跑多级塔 → 算多级 AMAT

写策略组合(写直达/写回 × 写分配/非写分配)

多级塔 · L1/L2/L3/主存

详解 · K09-09 写策略四组合

两个正交决策配成四种组合。写命中:写直达(WT)——同时写 cache 和下一级,简单、永远一致,但写流量大;写回(WB)——只写 cache 并置脏位,驱逐时才回写,省带宽但一致性复杂。写缺失:写分配——先把块取进 cache 再写;非写分配——绕过 cache 直接写下级。主流搭配:WB + 写分配(读多写少的程序最优)、WT + 非写分配。

详解 · K09-10 多级 Cache:L1/L2/L3 的权衡

L1 求快:最小(32~64KB)、分指令/数据两cache、贴着流水线;L2 求均衡:几百 KB,兜住 L1 的缺失;L3 求大:几 MB~几十 MB、多核共享,把主存访问压到最低。注意多级 AMAT 中每级用局部缺失率(落到该级的访问里有多大比例再缺),而全局缺失率 = 各级局部缺失率之积——这就是为什么 L3 缺失率看起来很高却依然值得。

第三幕 · 顿悟

虚境 · 地址翻译

虚拟内存是存储层次的终极延伸——主存是磁盘的 cache

虚境里没有梯,只有一面镜墙。左边是虚拟地址——48 位,你的程序以为它拥有一整片 256 TB 的连续空间。右边是物理地址——52 位,实际主存只有几十 GB。老祖说:「左边的地址是假的。右边的才是真的。中间这面镜子,叫页表。但你不能每次访问都查镜子——太慢。所以你在镜子旁边放了一个小本子,记最近查过的翻译。那个小本子,叫 TLB。」

诺依曼老祖 诺依曼老祖

「没有 TLB,每次翻译等于四次访存。400 纳秒——比 cache miss 还慢 4 倍。」

虚拟地址翻译流水线动画器

拆 48 位虚拟地址 → 单步走四级页表 → 看 TLB 加速 → 看层次对照镜

48 位虚拟地址 → 4 级 VPN(9+9+9+9)+ 12 位 Offset(4KB 页)
详解 · K09-11 虚拟内存:VA → PA

每个进程都活在独立的虚拟地址空间里,由硬件(MMU)+ 操作系统合作翻译成物理地址。三大收益:隔离——进程互相看不见也踩不坏;按需调页——程序可以比物理内存大;简化——链接、加载、共享库全都因此变简单。代价就是翻译本身的开销。

详解 · K09-12 页表与 TLB 加速

x86-64 的 48 位虚拟地址切成 9+9+9+9+12:四级页表(PML4→PDPT→PD→PT)各用 9 位索引 512 项,页内偏移 12 位对应 4KB 页。一次完整 Page Walk 要 4 次访存 ≈ 400ns——不可接受,于是有了 TLB:一块缓存 VPN→PFN 翻译的小 SRAM,命中率 99%+ 时翻译只要 ~0.3ns,提速超千倍。TLB 本质上就是「页表的 cache」。

第三幕 · 见深渊

缺页深渊 · 万倍之罚

缺页是存储层次的终极代价——十万倍于 cache miss

你走到页表的最后一级。PTE 的有效位 = 0。老祖说:「这页不在主存里。它在磁盘上。」镜墙碎了。你看见一条裂缝——从主存直通磁盘,深不见底。裂缝壁上刻着延迟数字:cache miss ~100ns,缺页 ~10,000,000ns。十万倍。深渊里的声音变成了一声叹息:「你终于走到这里了。缺页——这是我收的最大一笔税。」

未命中之罚 未命中之罚

「缺页需要 OS 介入 + 磁盘 I/O,硬件无法独立处理。延迟账本最后一页。」

渊账累计 0 笔 · 三问全对后清零

详解 · K09-13 缺页异常处理流程

七步走完一次缺页:①访存时 TLB 未命中且 PTE 有效位=0,CPU 触发缺页异常;②保存现场、切换到内核态;③OS 查页表确认这次访问合法(非法 → segfault);④找空闲页框,必要时执行页面置换;⑤启动磁盘 I/O 把页读进来(进程在此让出 CPU);⑥更新 PTE 与 TLB;⑦恢复现场,重新执行那条访存指令。全程 ~10ms——约等于 cache miss 的十万倍,所以 OS 会用预读、页缓存、置换算法拼命躲开它。

第三幕 · 最高潮

Boss 战 · 未命中之罚

三问对决 · 排除刻痕收网 · 侧信道意外之刃

天梯在你脚下裂开。裂缝中升起一个身影——没有面孔,只有一道裂缝形状的裂缝。它手中悬着一本账簿,封面刻着四个字:延迟账本。「你在天梯上走了十级台阶。每一级,你都在低估我。」翻开第一页:「S2。你说 5% 缺失不算什么。」翻开第二页:「S5。你选了最省硬件的直接映射。」翻开第三页:「S7。你以为写回没有代价。」

未命中之罚 未命中之罚

「现在,回答我三个问题。答错,从 S3 重走。但你的刻痕不会消失——它们是你的弹药。」

未命中之罚排除法收网器

排除刻痕 · 四道收网

详解 · K09-17 存储技术趋势:HBM / 3D 堆叠 / NVM

三条突围路线:HBM——把 DRAM 垂直堆叠并用超宽接口直连 GPU,用堆叠换带宽(AI 芯片的命脉);3D NAND——闪存单元向天上盖楼,200+ 层量产,用层数换密度;NVM 新型非易失存储(PCM、RRAM、MRAM)——试图在 DRAM 与闪存之间插上「又快又不丢」的一层,缝合主存—存储之间最后的裂缝。

详解 · K09-18 Cache 侧信道:Flush+Reload 与防御

Flush+Reload 三步:攻击者用 clflush 把目标行逐出 cache → 等受害者执行 → 重新加载并计时。快(命中)= 受害者刚访问过这行——时间差泄露了访问模式,进而能推出密钥。防御三板斧:恒定时间代码(执行路径不随秘密变化)、Cache 分区(如 Intel CAT,隔离共享观察面)、禁用共享内存页(抽掉 clflush 的前提)。安全与性能,又是一场交易。

本章复盘 · 存储天梯全景

局部性撑起整架天梯;AMAT 把每个百分点的缺失放大百倍;映射、替换、写策略是硬件与 miss 之间的三笔交易;虚拟内存与 TLB 是同一套层次思想在磁盘尺度上的重演;缺页是十万倍的终极之税;而 miss 的代价不止时间——还有被侧信道偷走的信息。记住这句话:代价不是惩罚,是前提。

交互实验

存储层次延迟

拖动工作集大小,观察访问延迟在 L1/L2/L3/内存间的阶梯跃迁。