【发布时间】:2013-10-05 16:36:22
【问题描述】:
我正在尝试学习缓存的用法。从我通过一些示例实验程序看到的情况来看,如果我将数组大小增加到超过特定值,那么执行迭代数组并对元素进行一些操作所花费的时间会突然增加很多。谁能简单地解释一下术语缓存大小和数组大小如何影响数组上数学运算的性能?
【问题讨论】:
-
这有点取决于你在做什么类型的数学运算。你能说得具体点吗?
我正在尝试学习缓存的用法。从我通过一些示例实验程序看到的情况来看,如果我将数组大小增加到超过特定值,那么执行迭代数组并对元素进行一些操作所花费的时间会突然增加很多。谁能简单地解释一下术语缓存大小和数组大小如何影响数组上数学运算的性能?
【问题讨论】:
如果缓存无法累积数组,则对那些未累积元素的任何引用都将导致缓存未命中。您访问数组元素的方式也有所不同,因为每次未命中时,处理器都会将数据块放入缓存中,并认为可能很快就会需要这些数据,从而为避免未来的缓存未命中做好准备。
例子:
如果您对来自连续位置的元素进行操作,性能将会提高。因为根据缓存行的大小,处理器将在第一次缓存未命中时获取一块内存。
以矩阵乘法为例,我们按如下方式进行。
假设:矩阵太大而无法在缓存中累积。
for (i = 0; i < N; i = i + 1)
for (j = 0; j < N; j = j + 1)
A[i*N + j] = (double) random() / SOME_NUMBER;
for (i = 0; i < N; i = i + 1)
for (j = 0; j < N; j = j + 1)
B[i*N + j] = (double) random() / SOME_NUMBER;
for (i = 0; i < N; i = i + 1)
for (j = 0; j < N; j = j + 1)
for (k = 0; k < N; k = k + 1)
C[i*N + j] = C[i*N + j] + A[i*N + k]*B[k*N + j];
在这里,当每一行相乘时,我们继续访问第二个矩阵列。在B 中,第一列存储在B[0],[N-1],B[2N-1]....... 中,依此类推,它们不是连续的内存位置。因此会有很多缓存未命中。因此,如果我们可以塑造解决方案,以便我们处理连续的内存位置并可以获得一些性能提升。我们可以将第二个矩阵存储在“列主要形式”中,即转置形式,而不是将第二个矩阵存储在“行主要形式”中。所以现在所有的列元素都在连续的位置。
A 将按行访问,B 将按列访问,因此我们将它们所有的“各自的东西”放在连续的内存位置。
因此,当处理器遇到第一次未命中时,它将获取一块内存,因此将避免下一次未命中。在这里,我们利用了“空间局部性”和“缓存阻塞”。
现在,如果我们将代码更改如下,性能将得到显着提升
以转置形式存储 B:
B[j*N + i] = random() / SOME_NUMBER;
您还必须按该顺序访问转置数组:
C[i*N + j] = C[i*N + j] + A[i*N + k]*B[j*N + k];
【讨论】: