4.3.1. 使用 TLB 的预警
TLB 是个处理器核的全域(global)资源。所有执行在处理器核的执行绪与行程都使用相同的 TLB。由于虚拟到实体地址的转译是看设置的是哪一个分页表树而定的,因此若是分页表被更改了,CPU 就不能盲目地重复使用cache的项目。每个行程有个不同的分页表树(但同个行程中的执行绪并非如此)。假如有的话,系统核心与 VMM(虚拟机器监视器)亦是如此。一个行程的定址空间布局也是可能改变的。有两种处理这个问题的方式:
- 每当分页表树被更改都冲出 TLB。
- 扩充 TLB 项目的标籤,以额外且唯一地识别它们所指涉到的分页表树。
在第一种情况中,每当情境切换(context switch)都会冲出 TLB。由于 –– 在大多操作系统中 –– 从一个执行绪/行程切换到另一个时,需要执行一些系统核心的程序码,TLB 冲出会被限制在离开(有时候是进入)系统核心定址空间时。在虚拟化的系统上,当系统核心必须呼叫 VMM、并在返回的途中时,这也会发生。若是系统核心和/或 VMM 不必使用虚拟地址、或是能够重复使用与发出系统/VMM 呼叫的行程或系统核心相同的虚拟地址(即,定址空间被重叠了),TLB 只须在 –– 离开系统核心或 VMM 后 –– 处理器恢复一个不同的行程或系统核心的执行时冲出。
冲出 TLB 有效但昂贵。举例来说,在执行一个系统呼叫时,系统核心程序可能会被限制在数千行触及 –– 或许 –– 少数的新分页(或者一个大分页,如同在某些架构上的 Linux 的情况)的指令。这个操作仅会取代与被触及的分页一样多的 TLB 项目。以 Intel 的 Core2 架构、附加它的 128 ITLB 与 256 DTLB 的项目而言,一次完整的冲出可能意味著被不必要地冲出的项目(分别)会超过 100 与 200 个。当系统呼叫返回(return)到相同的行程时,所有那些被冲出的 TLB 项目都能够被再次用到,但它们将会被丢掉。对于在系统核心或 VMM 中经常用到的程序码亦是如此。尽管系统核心以及 VMM 的分页表通常不会改变,因此 TLB 项目 –– 理论上 –– 能够被保存相当长的一段时间,但在每次进入系统核心时,TLB 也必须从零开始填入。这也解释了为何现今处理器中的 TLB cache并没有更大的原因:程序的执行时间非常可能不会长到足以填入这所有的项目。
这个事实 –– 当然 –– 不会逃出 CPU 架构师的掌心。最佳化cache冲出的一个可能性是,单独令 TLB 项目失效。举例来说,若是系统核心与资料落在一个特殊的地址范围,那么仅有落在这个地址范围的分页必须从 TLB 逐出。这只需要比对标籤,因而不怎么昂贵。这个方法在定址空间的一部分 –– 例如,透过一次 munmap 呼叫 –– 被更改的情况下也是有用的。
一个好得多的解法是扩充用来 TLB 存取的标籤。若是 –– 除了虚拟地址的部分以外 –– 为每个分页表树(即,一个行程的定址空间)加上一个唯一的识别子(identifier),TLB 根本就不必完全冲出。系统核心、VMM、以及独立的行程全都能够拥有唯一的识别子。采用这个方案的唯一议题是,可用于 TLB 标籤的位元数量会被严重地限制,而定址空间的数量则否。这表示是有必要重复使用某些识别子的。当这种情况发生时,TLB 必须被部分冲出(如果可能的话)。所有带著被重复使用的识别子的项目都必须被冲出,但这 –– 但愿如此 –– 是个非常小的集合。
当多个行程执行在系统中时,这种扩充的 TLB 标记在虚拟化的范围之外是有优势的。假如每个可执行行程的memory使用(是故 TLB 项目的使用)受限了,有个好机会是,当一个行程再次被排程时,它最近使用的 TLB 项目仍然在 TLB 中。但还有两个额外的优点:
- 特殊的定址空间 –– 像是那些被系统核心或 VMM 所用到的 –– 通常只会被进入一段很短的时间;后续的控制经常是返回到启动这次进入的定址空间。没有标籤的话,便会执行一或两次 TLB 冲出。有标籤的话,呼叫定址空间的cache转译会被保留,而且 –– 由于系统核心与 VMM 定址空间根本不常更改 TLB 项目 –– 来自前一次系统呼叫的转译等仍然可以被使用。
- 当在两条相同行程的执行绪之间切换时,根本不需要 TLB 冲出。不过,没有扩充的 TLB 标籤的话,进入系统核心就会销毁第一条执行绪的项目。
某些处理器已经 –– 一段时间了 –– 实作了这些扩充标籤。AMD 以 Pacifica 虚拟化扩充引入了一种 1 位元的标籤扩充。这个 1 位元定址空间 ID(Address Space ID,ASID)是 –– 在虚拟化的情境中 –– 用以从客户域(guest domain)的定址空间区别出 VMM 的定址空间。这使得操作系统得以避免在每次进入 VMM(举例来说,处理一个分页错误〔page fault〕)时冲出客户端的 TLB 项目、或者在返回客户端时冲出 VMM 的 TLB 项目。这个架构未来将会允许使用更多的位元。其它主流处理器可能也会遵循这套方法并支援这个功能。