如果执行以下代码:
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是否也可以缓存数组,或者它是否只假设它存在于“向前”方向。
答案 0 :(得分:3)
那里有太多的CPU来对此做出一般性假设,但是:
如果您在一个常见的x86体系结构上说,那么缓存将包含的内容总是缓存行大小的倍数,包含您访问的第一个导致缓存未命中的地址;对于前向访问,这是相同的。
根据内存访问预测的复杂程度,也可以预取后向访问;做预测的人取决于您的CPU架构,实际的CPU实现和编译器。对于编译器来说,知道&#34;并不常见。哪种内存访问模式适用于给定的CPU生成,并确保按顺序进行内存访问。
对于你的算术案例,甚至可能有例如自动检测正在访问的四个连续对齐地址,并使用CPU支持的SIMD指令自动进行矢量化。这也会影响与RAM的对齐,这可能会进一步影响缓存行为。
此外,由于您似乎关心速度,因此您通常允许编译器进行优化。在很多情况下,这会导致这样的循环变为“反转”,甚至是“SIMD”。
请注意,对于其他体系结构,这可能会有所不同:例如,90年代中期的一个臭名昭着的摩托罗拉DSP系列具有相对简单的地址生成单元,并且可以向后访问内存如果您(或您的C编译器)知道如何告诉它向后工作,请快速;然后,有选择&#34;融合&#34;内存加载或存储与任何其他CPU指令,所以这里你的整个缓存将有效地由你手动指定内存访问模式的方式支配。
答案 1 :(得分:1)
我想知道CPU是否也可以缓存数组,或者只是假设它存在于&#34; forward&#34;方向。
CPU cache以高速缓存行为单位工作(例如32个字或字节)。见this。访问阵列的顺序(增加或减少地址)并不重要。第一次访问高速缓存行将是一些高速缓存未命中(在前向和后向场景中),但不是下一个。
编译器可能会优化并展开循环,和/或发出Binding pageMarginBinding = new Binding
{
Source = PageMarginTextBox,
Path = new PropertyPath("Text"),
};
newPage.SetBinding(ContentControl.PaddingProperty, pageMarginBinding);
//PageMarginTextBox.Text determines the Padding of newPage
机器指令。您可能会使用 (GCC)PREFETCH
(请参阅this),但如果您错误地使用它,甚至可能会降低代码速度。
答案 2 :(得分:0)
是的,数组将被缓存。数据被作为缓存行大小的倍数缓存。因此,例如,如果高速缓存行大小为8字节,那么当您第一次访问内存位置时,无论您是尝试访问字节0还是字节7,所有0-8的内存位置都将被带入高速缓存。
答案 3 :(得分:0)
使用第32或64行等缓存工作...(取决于硬件)字节。并且可能具有内存粒度,因此首先允许任何字节加载完整(n字节)内存块进入缓存行