【问题标题】:Efficiently Accessing a 3D Array Stored as a 1D Array高效访问存储为 1D 数组的 3D 数组
【发布时间】:2014-11-27 01:44:47
【问题描述】:

我有一个 3D 数组,它以列方式存储为 1D 数组。例如,

for( int k = 0; k < nk; k++ ) // Loop through the height.
    for( int j = 0; j < nj; j++ ) // Loop through the rows.
        for( int i = 0; i < ni; i++ ) // Loop through the columns.
        {
            ijk = i + ni * j + ni * nj * k;
            my3Darray[ ijk ] = 1.0;
        }

对于我的应用程序,我需要访问my3Darray 的所有行/列/高度。高度是指数组第三维中的向量。我需要这个,因为我想处理每个向量的 FFT 并返回结果向量。我会很感激在 stackoverflow 中有我朋友的想法,我如何有效地访问这些向量。当然,例如,对于高度向量,一种微不足道的可能性是:

for( int i = 0; i < ni; i++ ) // Loop through the columns.
    for( int j = 0; j < nj; j++ ) // Loop through the rows.
    {
        for( int k = 0; k < nk; k++ ) // Loop through the heights.
        {
            ijk = i + ni * j + ni * nj * k;
            myvec[ k ] = my3Darray[ ijk ];
            fft( myvec, myvec_processed );
        }

        // Store the results in a new array, which is storing myvec_processed in my3Darray_fft_values.
        for( int k = 0; k < nk; k++ ) // Loop through the heights.
        {
            ijk = i + ni * j + ni * nj * k;
            my3Darray_fft_values[ ijk ] = myvec_processed[ k ];
        }
    }

我的计算效率高吗?是否有可能将my3Darray 直接传递给处理向量FFT 的函数(而不是将向量复制到myvec)?

【问题讨论】:

  • 你不能让 k 成为最内部的变量,这样你就不会跳入ni * nj 步骤,而是跳1,使其缓存友好。您无能为力。
  • 我需要计算所有向量的 FFT:按行、按列和按高度。
  • 你说的身高……是什么让你觉得现在慢,更重要的是,它可以改进。您展示了最不友好的缓存示例(顺便说一下高度)。同样,IMO,除了为您显示的代码提高缓存友好性之外,您无能为力。好吧,希望我是错的。我实际上会尝试的一件事是,复制整个数组,重新索引它。也许两次跳跃的迭代会比跳跃大的迭代快,但这取决于 CPU 缓存预测器的智能程度。
  • 如果你计算stride并在循环外初始化ijk,你可以用ijk += stride;替换复杂的乘法行。但不幸的是,如果你不按顺序访问,你仍然会遇到缓存问题。

标签: c++ c arrays multidimensional-array fft


【解决方案1】:

您可以通过像这样预先计算步幅来减少乘法:

...
for( int j = 0; j < nj; j++ ) // Loop through the rows.
{
    int stride = ni * nj;
    ijk = i + ni * j;
    for( int k = 0; k < nk; k++ ) // Loop through the heights.
    {
        myvec[ k ] = my3Darray[ ijk ];
        fft( myvec, myvec_processed );
        ijk += stride;
    }
}

但这只会稍微加快速度。由于以非顺序方式访问my3Darray,您仍然会遇到缓存问题。

【讨论】:

    【解决方案2】:

    当一切都减少到最里面的位和字节时,您的 3 维数组当然会存储在一维内存中。因此,给定数组元素的三个维度,编译器生成的代码与您自己计算数组元素的位置几乎相同。惊喜!

    所以,换句话说,这几乎是一回事。

    对于显式的 3 维数组,唯一可能对编译器有利的事情是编译器知道所有内部维度的大小,并且如果最里面的维度切片的大小恰好是方便的,比如2 的幂,编译器可能会用等效的左移替换一些乘法,我想这会稍微快一些,然后是完整的乘法指令。但如果结果证明性能差异很大,我会感到惊讶。

    选择维度的相对顺序可能更重要,这样您的典型访问模式(对于您的转换)将更适合 CPU 缓存。

    【讨论】:

      猜你喜欢
      • 2020-04-22
      • 1970-01-01
      • 1970-01-01
      • 2013-12-19
      • 2011-10-13
      • 2022-01-16
      • 2013-01-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多