CPU 缓存是否也从以前的内存位置加载信息?

Does the CPU cache also load information from previous memory locations?

如果执行以下代码:

int *array = new int[1000];
for (int i = 0; i < 1000; i++)
    array[i] = i * 2;

CPU 将数组存储在缓存中。但是,如果执行以下代码:

int *array = new int[1000];
for (int i = 1000-1; i >= 0; i--)
    array[i] = i * 2;

我想知道 CPU 是否也可以缓存数组,或者它是否只假设它存在于 "forward" 方向。

有太多 CPU 可以对此做出一般性假设,但是:

如果你,比方说,在一个普通的 x86 架构上,那么缓存将包含的内容总是缓存行大小的倍数,包含你访问的导致缓存未命中的第一个地址;那是前向访问相同。

根据内存访问预测的复杂程度,反向访问也可能被预取;谁做出预测取决于您的 CPU 体系结构、您的实际 CPU 实现以及您的编译器。编译器 "know" 哪些内存访问模式适用于给定的 CPU 代并确保内存访问按此顺序发生的情况并不少见。

对于您的算术案例,甚至可能有例如自动检测四个连续的、对齐的地址被访问,并使用您 CPU 支持的 SIMD 指令自动矢量化。这也会影响与访问 RAM 的对齐,这可能会对缓存行为产生进一步影响..

此外,由于您似乎很在意速度,因此您通常会允许编译器进行优化。在很多情况下,这会导致此类循环变成 "reversed",甚至是 SIMD。

请注意,对于其他架构,这可能会有所不同:例如,90 年代中期有一个声名狼藉的摩托罗拉 DSP 系列,它们具有相对简单的地址生成单元,并且如果可以快速地向后访问内存之类的事情是可能的您(或您的 C 编译器)知道如何告诉它向后工作;然后,可以选择 "fuse" 内存加载或存储任何其他 CPU 指令,因此在这里您的整个缓存将有效地由您手动指定内存访问模式的方式控制。

是的,数组将被缓存。将数据作为缓存行大小的倍数进行缓存。因此,例如,如果缓存行大小为 8 字节,那么当您第一次访问内存位置时,无论您是尝试访问字节 0 还是字节 7,从 0-8 的所有内存位置都将被放入缓存中。

I'm wondering if the CPU can also cache the array, or if it only assumes it exists in the "forward" direction.

CPU cache works in unit of cache lines (e.g. 32 words or bytes). See this。您访问数组的顺序(增加或减少地址)并不重要。对缓存行的第一次访问将是一些缓存未命中(在您的前向和后向场景中),但不会是下一个。

编译器可能会优化并展开循环,and/or 发出 PREFETCH 机器指令。您可能会小心地使用 (使用 GCC) its __builtin_prefetch (see this),但如果使用不当甚至可能会减慢您的代码速度。

缓存与第 32 或 64 行等...(取决于硬件)字节一起工作。并且可能具有内存粒度,因此首先访问任何字节加载完整(n 字节)内存块到缓存行