tlb-thrashing — perf 分析指南
用
perf stat和perf record定量测量 TLB 行为,观察不同步长 D 下dTLB-load-misses的变化规律。
准备工作
bash
cd demos/tlb-thrashing
make # -O0 -g核心事件:dTLB-loads / dTLB-load-misses
| 事件 | 含义 |
|---|---|
dTLB-loads | 数据 TLB 查询总次数 |
dTLB-load-misses | 数据 TLB 未命中次数(需 page walk) |
dTLB-load-misses / dTLB-loads | D-TLB miss 率 |
一次 TLB miss 的代价:需要硬件 page walk 遍历 4 级页表 = 4 次内存访问,约 50~200 cycles。
实验 1: 不同步长的 TLB miss 率变化
tlb-thrashing 的核心实验原理:固定迭代次数 N=8192,增大步长 D,观察页工作集随 D 增大的过程。
| 步长 D | 页工作集 8D | 预期行为 |
|---|---|---|
| 1~4 | 8~32 页(32~128KB) | < L1 dTLB 容量,miss 率极低 |
| 8~32 | 64~256 页 | 接近或超过 L1 dTLB,miss 率开始上升 |
| 64~128 | 512~1024 页 | 超过 L1 dTLB 但 < L2 STLB,L1 miss 但 STLB 兜住 |
| 256+ | 2048+ 页 | 超过 L2 STLB,每次回来都被挤光,miss 率飙升 |
bash
# 一键对比
for d in 4 8 16 32 64 128 256 512 1024; do
echo "=== D=$d (页工作集=$((8*$d))) ==="
perf stat -e cycles,instructions,dTLB-loads,dTLB-load-misses \
./tlb_thrashing $d 2>&1 | grep -E '^\s|TLB'
done预期结果
bash
D=4 (32页): dTLB-load-misses ~0 — L1 dTLB 全覆盖
D=16 (128页): dTLB-miss 率 <5% — L1 接近边缘
D=64 (512页): dTLB-miss 率 ~10~20% — 越过 L1,STLB 兜住
D=256 (2048页): dTLB-miss 率 ~50~80% — STLB 也被挤爆
D=1024(8192页): dTLB-miss 率 >90% — 全面 thrashing关键洞察:自增次数一样(都是 8192 次),吞吐下降了不是计算变慢了,而是每次访问前多了一个 50~200 cycles 的"翻译过路费"。
实验 2: 精确定位拐点
bash
# 全量扫表 D=1→1024,程序自动检测 L1 和 L2 拐点
./tlb_thrashing输出:
bash
D | 数组(KB) | 页工作集 | 吞吐(10⁹/s) | 相对(%)
------+----------+----------+-------------+--------
1 │ 32 │ 8 │ 12.345 │ 100%
...
32 │ 1024 │ 256 │ 8.234 │ 67% ← L1 拐点
...
256 │ 8192 │ 2048 │ 2.345 │ 19% ← L2 拐点 (thrashing)实验 3: perf record 采样 TLB miss
bash
# 用 -e 指定采样 dTLB-load-misses 事件
perf record -e dTLB-load-misses -g ./tlb_thrashing 512
# 看哪些代码在触发 TLB miss
perf report --stdio预期:热点在 bench_strided 的内层循环 a[i*stride]++ ——这正是跨页访问的地方。
实验 4: IPC 随 D 增大的变化
TLB miss 直接影响 IPC(因为每条访存指令都要等 page walk 完成):
bash
for d in 4 16 64 256 512 1024; do
echo "=== D=$d ==="
perf stat -e cycles,instructions ./tlb_thrashing $d 2>&1 |
grep -E 'cycles|instructions|insn'
done| D | IPC | 说明 |
|---|---|---|
| 4 | ~1.0 | 无 TLB 开销 |
| 64 | ~0.7 | 开始受影响 |
| 256 | ~0.3 | STLB 被挤爆 |
| 1024 | ~0.15 | 几乎每次访问都在 walk |
dTLB vs iTLB
如果不仅要看数据 TLB,还要看指令 TLB(代码段碎片化场景):
bash
perf stat -e dTLB-loads,dTLB-load-misses,iTLB-loads,iTLB-load-misses \
./tlb_thrashing 64tlb-thrashing 的代码很短(< 1 页),所以 iTLB-load-misses 应接近 0。
关联文档
- tlb——TLB 原理深度文档
- perf——perf 工具主文档,§六.1.5 TLB 事件
- perf-demos-architecture——perf 12 场景学习架构导读
一句话:TLB miss 率随数据集的页工作集呈阶梯式上升——关键拐点对应 L1 dTLB 和 L2 STLB 的物理容量,用
perf stat -e dTLB-load-misses精确测量。
总结
TLB thrashing 证明吞吐下降不是计算变慢、而是每笔跨页访问多付 50~200 cycles 的 page walk“过路费”:固定迭代次数、增大步长使页工作集扩张,miss 率呈阶梯式上升,两个拐点分别对应 L1 dTLB 和 L2 STLB 的物理容量,越过 STLB 后 miss 率超 90%、IPC 从约 1.0 跌到 0.15。