让我们考虑替代方案 {Index, Tag, Offset}。每个字段的用法和大小保持不变,例如索引用于在缓存中定位 block ,其位长仍然由缓存 block 的数量决定。唯一的区别是我们现在使用 MSB 位作为索引,中间部分作为标记,最后部分作为偏移量。
您认为这个方案的缺点是什么?
最佳答案
这会起作用 - 如果缓存是完全关联的,这并不重要(因为没有索引,它是所有标签),但如果关联性受到限制,它将(远远)降低缓存内存的有效使用。为什么?
考虑一个足够大以跨越缓存 block 边界的对象。
访问对象时,某些字段的地址与其他字段的地址不会位于同一缓存 block 中。缓存将如何表现?
当索引
位于中间时,缓存 block /行索引将发生变化,允许缓存存储不同的附近实体,即使关联性有限。
当索引
位于开头(最高有效字节)时,这两个地址之间的标记将发生变化,但索引将相同 - 因此,在索引,它将使用集合关联性的一种方式。如果缓存是直接映射的(即单向集关联),则在重复访问同一对象时可能会严重崩溃。
假设我们有 12 位地址空间,索引、标记和偏移量均为 4 位。
让我们考虑一个包含四个 32 位整数字段的对象,该对象位于位置 0x248,因此两个整数字段 a、b 位于 0x248 和 0x24c,另外两个整数字段 c、d 位于0x250 和 0x254。
考虑一下当我们访问 a 或 b,然后访问 c 或 d,然后再次访问 a 或 b 时会发生什么。
如果标记是高位十六进制数字,则缓存索引(中间)从 4
到 5
,这意味着即使在直接映射缓存中a&b字段和c&d字段可以同时在缓存中。
对于相同的访问模式,如果标签是中间的十六进制数字,索引是高的十六进制数字,那么缓存索引不会改变 - 它保持在2
。因此,在单向组关联缓存上,访问字段 a 或 b,然后访问字段 c 或 d 将逐出 a 和 b 字段,如果/当稍后访问 a 或 b 时,这将导致未命中。
因此,这实际上取决于访问模式,但使缓存真正有效的一件事是当程序访问之前访问过的内容或与之前访问过的同一 block 中的内容时。当我们操作单个对象时,当我们分配最终相邻的对象时,以及当我们重复访问数组时(例如,对数组进行第二次循环),就会发生这种情况。
如果索引
位于中间,当我们使用内存的某个 block 或 block 或区域内的不同地址时,我们会得到更多变化 - 在我们的 12 位地址空间示例中,索引会发生变化每16字节,相邻的16字节 block 可以存储在缓存中。
但是,如果索引
位于开头,我们需要消耗更多内存,然后才能到达不同的索引
- 索引仅每256字节更改一次,因此两个相邻的16 字节 block 经常会发生冲突。
我们的程序和编译器通常是在假设缓存有利于局部性的情况下编写的 - 这意味着索引应该位于中间,标记位于高位置。
两种标签/索引位置选项都为同一 block 中的地址提供了良好的局部性,但其中一种比另一种更倾向于不同 block 中的相邻地址。
关于caching - 索引和标签切换位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64483279/