TLB 是否在多个内核之间共享?
Is the TLB shared between multiple cores?
我听说 TLB 是由 MMU 维护的,而不是 CPU 缓存。
那么 CPU 上是否存在一个 TLB 并在所有处理器之间共享,或者每个处理器都有自己的 TLB 缓存?
谁能解释一下MMU和L1、L2 Cache的关系?
TLB 缓存页面 table 中列出的翻译。每个 CPU 核心都可以 运行 在不同的上下文中,具有不同的页面 table。这就是您所说的 MMU,如果它是一个单独的 "unit",那么每个内核都有自己的 MMU。任何共享缓存总是物理索引/物理标记,因此它们基于 post-MMU 物理地址进行缓存。
TLB 是(PTE 的)缓存,因此从技术上讲,它只是一个实现细节,可能因微体系结构而异(在 x86 体系结构 的不同实现之间)。
实际上,真正不同的只是大小。 2 级 TLB 现在很常见,为了将完整 TLB 未命中率保持在最低水平,但仍然足够快,允许每个时钟周期进行 3 次转换。
重新遍历页面 tables(在本地 L1 数据或 L2 缓存中可能很热)重建 TLB 条目比尝试共享 TLB 要快得多 这是避免 TLB 未命中的极端情况的下限,这与数据缓存不同,数据缓存是您必须离开核心到共享 L3 之前的最后一道防线高速缓存,或在 L3 未命中时片外到 DRAM。
例如,Skylake 添加了第二个页面遍历单元(每个核心)。对于核心无法有效共享 TLB 条目(来自不同进程的线程,或不接触许多共享虚拟页面的线程)的工作负载,良好的页面遍历是必不可少的。
共享 TLB 意味着当您 做 更改页面时 invlpg
使缓存的翻译无效 table 总是必须离开核心。 (尽管在实践中 OS 需要确保其他核心 运行 多线程进程的其他线程在 munmap
之类的过程中具有其私有 TLB 条目 "shot down",使用软件内核间通信的方法,如 IPI(处理器间中断)。)
但是对于私有 TLB,上下文切换到新进程只需设置新的 CR3(顶级页面目录指针)并使该核心的整个 TLB 无效,而无需打扰其他核心或全局跟踪任何内容。
有一个 PCID(进程上下文 ID)功能可以让 TLB 条目被标记为 16 个左右的 ID 之一,这样来自不同进程页面 tables 的条目可以在 TLB 中很热,而不需要在上下文切换时被刷新。对于共享 TLB,您需要加强这一点。
另一个复杂的问题是 TLB 条目需要跟踪 PTE 中的 "dirty" 和 "accessed" 位。它们必然只是 PTE 的只读缓存。
有关各个部分如何在真实中组合在一起的示例 CPU,see David Kanter's writeup of Intel's Sandybridge design。请注意,图表适用于单个 SnB 内核。 大多数 CPU 中唯一的内核间共享缓存是最后一级数据缓存。
英特尔的 SnB 系列设计都在环形总线上使用每核 2MiB 模块化 L3 缓存。因此,添加更多内核会向总池中添加更多 L3,并添加新内核(每个内核都有自己的 L2/L1D/L1I/uop-cache 和两级 TLB。)
我听说 TLB 是由 MMU 维护的,而不是 CPU 缓存。
那么 CPU 上是否存在一个 TLB 并在所有处理器之间共享,或者每个处理器都有自己的 TLB 缓存?
谁能解释一下MMU和L1、L2 Cache的关系?
TLB 缓存页面 table 中列出的翻译。每个 CPU 核心都可以 运行 在不同的上下文中,具有不同的页面 table。这就是您所说的 MMU,如果它是一个单独的 "unit",那么每个内核都有自己的 MMU。任何共享缓存总是物理索引/物理标记,因此它们基于 post-MMU 物理地址进行缓存。
TLB 是(PTE 的)缓存,因此从技术上讲,它只是一个实现细节,可能因微体系结构而异(在 x86 体系结构 的不同实现之间)。
实际上,真正不同的只是大小。 2 级 TLB 现在很常见,为了将完整 TLB 未命中率保持在最低水平,但仍然足够快,允许每个时钟周期进行 3 次转换。
重新遍历页面 tables(在本地 L1 数据或 L2 缓存中可能很热)重建 TLB 条目比尝试共享 TLB 要快得多 这是避免 TLB 未命中的极端情况的下限,这与数据缓存不同,数据缓存是您必须离开核心到共享 L3 之前的最后一道防线高速缓存,或在 L3 未命中时片外到 DRAM。
例如,Skylake 添加了第二个页面遍历单元(每个核心)。对于核心无法有效共享 TLB 条目(来自不同进程的线程,或不接触许多共享虚拟页面的线程)的工作负载,良好的页面遍历是必不可少的。
共享 TLB 意味着当您 做 更改页面时 invlpg
使缓存的翻译无效 table 总是必须离开核心。 (尽管在实践中 OS 需要确保其他核心 运行 多线程进程的其他线程在 munmap
之类的过程中具有其私有 TLB 条目 "shot down",使用软件内核间通信的方法,如 IPI(处理器间中断)。)
但是对于私有 TLB,上下文切换到新进程只需设置新的 CR3(顶级页面目录指针)并使该核心的整个 TLB 无效,而无需打扰其他核心或全局跟踪任何内容。
有一个 PCID(进程上下文 ID)功能可以让 TLB 条目被标记为 16 个左右的 ID 之一,这样来自不同进程页面 tables 的条目可以在 TLB 中很热,而不需要在上下文切换时被刷新。对于共享 TLB,您需要加强这一点。
另一个复杂的问题是 TLB 条目需要跟踪 PTE 中的 "dirty" 和 "accessed" 位。它们必然只是 PTE 的只读缓存。
有关各个部分如何在真实中组合在一起的示例 CPU,see David Kanter's writeup of Intel's Sandybridge design。请注意,图表适用于单个 SnB 内核。 大多数 CPU 中唯一的内核间共享缓存是最后一级数据缓存。
英特尔的 SnB 系列设计都在环形总线上使用每核 2MiB 模块化 L3 缓存。因此,添加更多内核会向总池中添加更多 L3,并添加新内核(每个内核都有自己的 L2/L1D/L1I/uop-cache 和两级 TLB。)