3D阵列的空间位置?

时间:2016-11-19 11:24:36

标签: c++ c optimization memory-management multidimensional-array

为什么A [k] [i] [j]对于3D阵列中的空间局部性更好? (其中i,j,k是行,col,深度)CMU lecture 55min

Check image for Question

2 个答案:

答案 0 :(得分:1)

实际上,该示例是完全错误的。当等级0从0..M-1开始时,该循环正在迭代0..N-1。除非M==N,否则您将读取错误的元素。

目标是让您的循环通过操纵循环的顺序来迭代地访问内存中物理上相邻的位置。

每当您的程序读取一个值时,CPU就会从缓存控制器中请求它。如果不在缓存中,则会从内存中检索该值-及其附近的值-并将其存储在缓存中。

如果您随后读取下一个元素,则它通常应该已经在高速缓存中,因此不会缓慢地往返于下一个高速缓存或主机RAM。

如果您的循环遍历整个地方,而不是利用空间局部性,那么您就有遭受更多高速缓存未命中的风险,这会使事情变慢。

简而言之:从缓存中获取内容的速度很快,从RAM中获取内容的速度很慢,对循环进行排序以使其接触相邻位置有助于保持缓存的快乐。

在图形中,我们通常这样做:

int a[M*N*N];

for(int offset=0; offset < M*N*N; ++offset)
{
  //int y = offset / cols;
  //int x = offset % rows;
  sum += a[offset];  
}

如果您需要一个X,Y元素,只需

 offset = Y * cols + X;
 int val = a[offset];

或用于3D

offset = Z*N*N + Y*N + X

offset = Z * rows * cols + Y * cols + X;

...,并跳过所有多维数组无聊。

我个人就是这样做:

int *p = &a[0][0][0]; // could probably just do int* p=a, but for clarity...

//... array gets populated somehow
for(int i=0;i<M*N*N;++i)
{
  sum += p[i];
}

...但是假定该数组是规则的正方形数组,而不是指针数组或指针数组。

答案 1 :(得分:0)

我认为OP的问题

  

为什么A [k] [i] [j]对于3D数组中的空间局部性更好? (其中i,j,k是行,列,深度)

来自对作为空间局部性示例的练习的误解,在该示例中要求读者

  

置换循环,以使函数...具有良好的空间局部性

给出此代码:

int sum_array_3d(int a[M][N][N]) 
{
    int i, j, k, sum = 0;

    for (i = 0; i < M; i++)
        for (j = 0; j < N; j++)
            for (k = 0; k < N; k++)
                sum += a[k][i][j];

    return sum;
} 

我对此任务的解释是要求学生将内部语句重写为sum += a[i][j][k];或更改循环顺序:

int sum_array_3d(int a[M][N][N]) 
{
    int i, j, k, sum = 0;

    for (k = 0; k < M; k++)            // <-- those are reordered
        for (i = 0; i < N; i++)
            for (j = 0; j < N; j++)
                sum += a[k][i][j];     // <-- this is mantained, verbatim

    return sum;
}