土法炼钢兴趣小组的算法知识备份

【操作系统百科】TLB 工程

文章导航

分类入口
os
标签入口
#tlb#shootdown#invlpgb#tlbi#huge-page

目录

TLB(Translation Lookaside Buffer)是 MMU 的页表缓存。一条 TLB 项让 VA→PA 翻译从 “4 次内存读” 降到 “1 cycle”。但 TLB 容量几十到几千条,任何一次修改全局映射都可能要全核同步:TLB shootdown。

一、先看图

flowchart LR
    CPU0[CPU0 mm->pgd 改] -->|写 PTE| PTE[页表]
    CPU0 -->|调用 flush_tlb_mm/range| IPI{广播}
    IPI -.发 IPI.-> CPU1
    IPI -.发 IPI.-> CPU2
    IPI -.发 IPI.-> CPU3
    CPU1 --> INV1[本地 invlpg/TLBI]
    CPU2 --> INV2[本地 invlpg/TLBI]
    CPU3 --> INV3[本地 invlpg/TLBI]
    INV1 --> ACK[ack 等回复]
    INV2 --> ACK
    INV3 --> ACK
    ACK --> DONE[CPU0 继续]
    classDef sw fill:#388bfd22,stroke:#388bfd,color:#adbac7;
    classDef sync fill:#f0883e22,stroke:#f0883e,color:#adbac7;
    class CPU0,PTE sw
    class IPI,ACK sync

二、TLB 为什么贵

TLB miss 成本:

4 级 page walk 全 miss:100-400ns。相比 L1 cache 1 cycle,差 3 个数量级。

Huge page 把一条 TLB 项覆盖 512x 或 256x 地址,显著降低 miss 率。

三、TLB shootdown:多核的锅

场景:CPU0 改了一条 PTE(munmap、mprotect、swap-out、COW 等)。CPU1-N 的 TLB 可能还缓存旧翻译。必须让其他核作废对应条目

x86 没有广播 TLB 指令(直到最近的 INVLPGB)——只能:

  1. CPU0 发 IPI
  2. 每核进入 IPI handler,本地 invlpg
  3. ack 回 CPU0
  4. CPU0 这时才能真正复用物理页

瓶颈:核数越多,shootdown 的 O(N) 通信越贵;成百上千核的系统一次 munmap 可能卡几十 μs。

四、Linux 的优化

4.1 批量

一次操作多个页 → 合并一次 IPI,一次广播多条 invlpg。

4.2 范围 vs 全量

4.3 Deferred / mm_tlb_flush_pending

tlb_gather_mmu / tlb_finish_mmu 把多次 munmap 的刷合并到一次批处理。

4.4 Lazy TLB

内核线程没自己的 mm,借用上一个进程的 mm(active_mm)。这段期间若物主进程 exit 了但 lazy CPU 还”用”着,会推迟 mm 释放。Linux 6.x 有 lazy_tlb_mm_refcount 改造降低开销。

五、INVLPGB(AMD)

Zen 3+ 提供 INVLPGB 指令:广播无效化,不走 IPI,硬件级完成。

Linux 6.5+ 有针对性优化,在 AMD 支持的机器上自动切换到 INVLPGB 路径。效果:多核 TLB shootdown 延迟数量级下降。

Intel 没对等指令;2024 后有 “Remote Action Request”(RAR)硬件 hint 提案,尚未广泛。

六、arm64 TLBI

ARM 原生有广播 TLB 指令:

TLBI VAE1IS, x0        // by VA, EL1, Inner Shareable 广播
TLBI ASIDE1IS, x0      // by ASID
TLBI VMALLE1IS         // 全部 EL1

IS 表示 Inner Shareable,硬件自动广播到所有共享域内的核。不需要 IPI。

这是 ARM 多核扩展性的先天优势——但也意味着软件要小心别过度 TLBI。

七、huge page 对 TLB 的放大

对 DB/JVM 大堆,打开 HugeTLB 或 THP,TLB miss 率可能掉 70-90%。但 fragmentation 和 compaction 开销要考虑,详见 D-40。

八、观察 TLB 行为

8.1 硬件计数器

perf stat -e dTLB-loads,dTLB-load-misses,\
  dTLB-stores,dTLB-store-misses,\
  iTLB-loads,iTLB-load-misses \
  ./app

8.2 TLB shootdown 计数

grep TLB /proc/interrupts    # x86 的 IPI-TLB 行

8.3 walk duration

perf stat -e dtlb_load_misses.walk_active,\
  dtlb_load_misses.walk_completed ./app

Intel 上这两个事件能看出 TLB miss 占 CPU 多少周期。

九、典型 TLB 踩坑

A:频繁 mmap/munmap 小对象用 mmap 直接申请 → 持续 shootdown。用 malloc(arena 复用)或 madvise(MADV_DONTNEED) 代替 munmap(后者只释放物理页,不拆 VMA)。

B:大量 mprotect 切换 JIT 把代码页不断 RW/RX 切换导致刷 TLB。近代做法:memfd_secret 或双 map(一份 RW 一份 RX)。

C:THP 撕裂抖动 THP split 发生时多核同步刷,带来延迟毛刺。数据库类关 THP(never 或 madvise)。

D:NUMA 跨节点 shootdown 跨节点 IPI 贵;把任务/内存绑到同 NUMA。

十、设计建议

十一、小结


参考文献

工具


上一篇ARMv8 VMSA 页表 下一篇mm_struct 与 VMA

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-05-01 · os

【操作系统百科】HugeTLB 与 THP

大页能让一条 TLB 覆盖 2MB 乃至 1GB,但 THP 为什么在数据库里默认关掉?本文讲 HugeTLB 预留池、THP 的 khugepaged、defrag stall、madvise 模式、file-backed THP、以及工程上的取舍。

2026-04-27 · os

【操作系统百科】内存回收

Linux 内存回收是 VM 最复杂的子系统之一。本文讲 active/inactive LRU、kswapd 与 direct reclaim、watermark 三线、swappiness 的真实含义、MGLRU 改造、memcg 回收与 PSI。

2026-04-28 · os

【操作系统百科】交换

swap 还值得开吗?本文讲 swap area 基础、swap cache、zram 压缩内存、zswap 前端压缩池、swappiness 的真实含义、容器里的 swap 策略,以及为什么现代 Android 全靠 zram 不靠磁盘。

2026-05-03 · os

【操作系统百科】Slab/SLUB 分配器

buddy 只管页粒度(4K+),内核大多数对象只有几十到几百字节。slab/SLUB 在 buddy 之上做对象级缓存。本文讲 slab 历史、SLUB 接手、SLOB 退场、kmem_cache、per-CPU cache、KASAN 集成。


By .