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



如果执行以下代码:

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 是否也可以缓存阵列,或者它是否只假设它存在于"向前"方向。

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

假设您在通用的 x86 体系结构上,则缓存将包含的内容始终是缓存行大小的倍数,其中包含您访问的第一个导致缓存未命中的地址;对于正向访问也是如此。

根据内存访问预测的

复杂程度,还可以预取向后访问;谁来预测取决于你的 CPU 体系结构、实际的 CPU 实现和编译器。编译器"知道"哪些内存访问模式适用于给定的 CPU 代并确保内存访问按该顺序发生的情况并不少见。

对于您的算术情况,甚至可以自动检测正在访问的四个连续对齐的地址,并使用 CPU 支持的 SIMD 指令进行自动矢量化。这也会影响与访问的RAM的对齐,这可能会进一步影响缓存行为。

此外,由于您似乎关心速度,因此通常会允许编译器进行优化。在很多情况下,这会导致此类循环变得"反转",甚至 SIMD'ed。

请注意,对于其他体系结构,这可能以不同的方式工作:例如,90年代中期有一个臭名昭著的摩托罗拉DSP系列,它们有一个相对简单的地址生成单元,如果你(或你的C编译器(知道如何告诉它向后工作,那么向后访问内存是可能的;然后,可以选择将内存负载或存储与任何其他CPU指令"融合", 因此,在这里,您的整个缓存实际上将由您手动指定内存访问模式的方式主导。

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

CPU 缓存以缓存行为单位(例如 32 个字或字节(。看到这里。访问阵列的顺序(增加或减少地址(并不重要。对缓存行的第一次访问将是一些缓存未命中(在向前和向后 scenarii 中(,但不是下一个。

编译器可能会优化并展开循环,和/或发出PREFETCH机器指令。您可能会小心地(使用 GCC(使用它__builtin_prefetch(请参阅此处(,但如果您错误地使用它,甚至可能会减慢您的代码速度。

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

缓存适用于第 32 行或第 64 行等...(取决于硬件(字节。并且可能具有内存粒度,因此首先将任何字节加载满(n字节(内存块加载到缓存行中

最新更新