【问题标题】:What is the fastest do array padding of the image array图像数组的数组填充最快的是什么
【发布时间】:2013-10-26 10:24:04
【问题描述】:

所以我有一个一维图像数组:

a = {1,2,3,4,5,6,7,8,9}

用 zeo 包围它的数组填充的最快方法是什么:

0 0 0 0 0
0 1 2 3 0
0 4 5 6 0
0 7 8 9 0
0 0 0 0 0

我已经声明了b数组(这是a的填充数组):

float *b = calloc(((data_size_X + 2)*(data_size_Y +2)), sizeof(float));

【问题讨论】:

  • 你有理由相信在这里,一组简单的 for 循环不够快吗?
  • 但是图像数组可以大到百万像素...
  • 有没有试过naive版本,剖析一下,发现太慢了?考虑到处理器速度和 RAM,现在百万像素并不是很大,除非你在一个紧密的循环中这样做,否则如果它慢得令人难以置信,我会感到惊讶。
  • 唯一可能稍微快一点(由于内部优化)的方法是一次使用memcpy 一行。它利用硬件的体系结构在一次操作中复制更大的数据块(长整数而不是字节)。分析它,你会看到。

标签: c algorithm padding


【解决方案1】:

这是一些基准测试。我的预感是对的 - 使用 memcpy 比其他方法快得多:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>

int main(void) {
  char* original;
  char* padded;
  long int n, m, ii, jj, kk;
  time_t startT, stopT;

  char *p1, *o1; //  point to first element in row for padded, original

  // pick a reasonably sized image:
  n = 3000;
  m = 2000;

  // allocate memory:
  original = malloc(m * n * sizeof(char));
  padded = calloc((m+2)*(n+2), sizeof(char));

  // put some random values in it:
  for(ii = 0; ii < n*m; ii++) {
    original[ii] = rand()%256;
  }

  // first attempt: completely naive loop
  startT = clock();
  for(kk = 0; kk < 100; kk++) {
    for(ii = 0; ii < m; ii++) {
      for(jj = 0; jj < n; jj++) {
        padded[(ii + 1) * (n + 2) + jj + 1] = original[ ii * n + jj];
      }
    }
  }
  stopT = clock();
  printf("100 loops of 'really slow' took %.3f ms\n", (stopT - startT) * 1000.0 / CLOCKS_PER_SEC);

  // second attempt - pre-compute the index offset
  startT = clock();
  for(kk = 0; kk < 100; kk++) {
    for(ii = 0; ii < m; ii++) {
      p1 = padded + (ii + 1) * (n + 2) + 1;
      o1 = original + ii * n;
      for(jj = 0; jj < n; jj++) {
        p1[jj] = o1[jj];
      }
    }
  }
  stopT = clock();
  printf("100 loops of 'not so fast' took %.3f ms\n", (stopT - startT) * 1000.0 / CLOCKS_PER_SEC);

  // third attempt: use memcpy to speed up the process    
  startT = clock();
  for(kk = 0; kk < 100; kk++) {
    for(ii = 0; ii < m; ii++) {
      p1 = padded + (ii + 1) * (n + 2) + 1;
      o1 = original + ii * n;
      memcpy(p1, o1, n);
    }
   }
  stopT = clock();
  printf("100 loops of 'fast' took %.3f ms\n", (stopT - startT) * 1000.0 / CLOCKS_PER_SEC);

  free(original);
  free(padded);
  return 0;
}

这是结果输出:

100 loops of 'really slow' took 3020.585 ms
100 loops of 'not so fast' took 3725.056 ms
100 loops of 'fast' took 332.298 ms

当我用-O3开启编译器优化时,时序变化如下:

100 loops of 'really slow' took 2727.442 ms
100 loops of 'not so fast' took 488.244 ms
100 loops of 'fast' took 326.998 ms

很明显,编译器“发现”了更清晰的复制循环并尝试对其进行一些优化——但它仍然没有memcpy 做得好。在 memcpy 中几乎没有什么可以优化的了。

【讨论】:

  • 复制数组的时候我也实现了blocksize,这样会快一点
【解决方案2】:

如果您已经按照您的描述分配了b,则以下内容可能比嵌套的for循环更快:

int aIndex;
int maxA = data_size_X * data_size_Y;
float * pb = b + data_size_X + 3;
memset(b, 0, (data_size_X + 2) * (data_size_Y + 2) * sizeof(float));
for (aIndex = 0; aIndex < maxA;  aIndex += data_sizeX) {
    memcpy(pb, a + aIndex, data_size_X);
    pb += (data_size_X + 2);
}

【讨论】:

  • @Floris 哇。你也是一个比我快得多的编码员!好答案 - 已升级。
  • 只是澄清一下,做member 不如做calloc 快,对吧?因为当我们调用 calloc 时,我们也会将整个数组归零,并使该数组成为本地数组。
猜你喜欢
  • 2021-05-20
  • 2011-05-06
  • 1970-01-01
  • 1970-01-01
  • 2013-08-05
  • 1970-01-01
  • 1970-01-01
  • 2013-11-18
相关资源
最近更新 更多