3.3.5. 其它细节
到目前为止,我们已经讨论过由三个部分 –– 标籤、集合索引、以及cache行偏移量 –– 组成的地址。但实际使用的地址是什么呢?所有有关的处理器现今都是将虚拟定址空间提供给行程,这代表有两种不同的地址:虚拟的以及实体的。
虚拟memory的问题是,它们不是唯一的。虚拟memory能够 –– 随著时间 –– 指涉到不同的实体memory地址。在不同行程中的相同地址也可能会指涉到不同的实体地址。所以使用实体memory地址永远比较好,对吧?
这里的问题是,在执行期间使用的虚拟memory必须在memory管理单元(Memory Management Unit,MMU)的帮助下转译成实体地址。这是个不单纯的操作。在执行一个指令的管线中,实体地址可能只有在之后的阶段才能取得。这表示cache逻辑必须非常快速地判定这个memory位置是否被cache了。若是能够使用虚拟地址,cache查询就能够早点在管线中进行,并且在cache命中的情况下,就能够取得memory内容了。结果是,管线能够隐藏更多memory存取的成本。
处理器设计者目前是使用虚拟地址来标记第一层级的cache。这些cache非常地小,而且清除也不会太费力。若是一个行程的分页表树(page table tree)改变了,至少必须局部地清理cache。假如处理器拥有能够指定被改变的虚拟地址范围的指令,就有可能避免一次完整的冲出。考虑到 L1i 与 L1d cache的等待时间很短(~3 周期),使用虚拟地址几乎是强迫性的。
对于大一点的cache,包含 L2、L3、... cache,是需要实体地址标记的。这些cache有比较长的等待时间,而虚拟→实体地址转译能够在时间内完成。因为这些cache比较大(即,当它们被冲出时,会损失大量的资讯),并且因为主memory存取的等待时间,重新填入它们会花上很久的时间,因此冲出它们的代价经常不小。
一般来说,应该没必要知道在那些cache中的地址管理的细节。它们无法改变,而且所有会影响效能的因子通常是应该避免、或者是与高成本相关联的东西。塞满cache容量是很糟的,而且若是多数被使用的cache行都落在同一组集合中,所有cache都会很快地碰到问题。后者能够以虚拟定址的cache来避免,但对于使用者层级的行程来说,要避免使用实体地址定址的cache是不可能的。或许唯一应该记住的细节是,可能的话,别在同个行程里将同个实体memory位置映射到两个以上的虚拟地址。
另一个对程序开发者来说满无趣的cache细节是cache的替换策略。大多cache会先逐出近期最少使用的(Least Recently Used,LRU)元素。以较大的关联度(由于增加更多的处理器核,关联度可能会在接下来几年内进一步地增长)维持 LRU 清单会变得越来越昂贵,我们可能会看到被采用的不同策略。
至于cache的替换,一介程序开发者能做的不多。若是cache是使用实体地址的标籤,就没有任何办法能找出虚拟地址与cache集之间的关联。所有逻辑分页的cache行可能都映射到相同的cache集,留著大量的cache不用。如果是这样的话,不让这太常发生就是操作系统的工作了。
随著虚拟化(virtualization)的出现,事情变得更加复杂。现在甚至不是操作系统拥有对实体memory指派的控制。而是虚拟机器监视器(Virtual Machine Monitor,VMM,又称 Hypervisor)有指派实体memory的职责。
一介程序开发者能做的最多就是 a) 完全使用逻辑memory分页 b) 使用尽可能大的分页大小,以尽可能地多样化实体地址。较大的分页大小也有其它好处,但这是另一个主题(见第四节)。