【问题标题】:Optimizing a double loop优化双循环
【发布时间】:2018-12-16 14:56:25
【问题描述】:

在 X86 平台上优化以下双循环的最佳方法是什么? 该代码是将像素数据复制到锁定的 Direct3D 纹理中的例程。

由于我的目标平台及其限制,我使用的是 2003 年的编译器。如果我用汇编语言编写这段代码,那么旧的编译器是否能够与我获得的速度相匹配?还是有一些技巧可以用来加速 C 代码?也许使用memcpy() 会更快。

  int x, y;
  byte *srcdata = (byte *)compatablePixels;
  byte *dstdata = (byte *)lockedRectSubImg.pBits;

  for (y = yoffset; y < (yoffset + height); y++)
  {
     for (x = xoffset; x < (xoffset + width); x++)
     {
        dstdata[lockedRectSubImg.Pitch * y + bytes * x ] = srcdata[0];
        dstdata[lockedRectSubImg.Pitch * y + bytes * x + 1] = srcdata[1];
        dstdata[lockedRectSubImg.Pitch * y + bytes * x + 2] = srcdata[2];
        dstdata[lockedRectSubImg.Pitch * y + bytes * x + 3] = srcdata[3];

        srcdata += bytes;
     }
  }

【问题讨论】:

  • “也许使用 memcpy 会更快?” 那么,如果您确定源数据和目标数据共享相同的内存布局,为什么不呢?
  • 什么是bytes - 它是否总是等于4
  • 一个好的编译器会注意到你正在计算 lockedRectSubImg.Pitch * y + bytes * x 四次,结果相同,然后用一次计算替换它;但你可能想帮忙。
  • 假设你 15 岁的编译器无法优化,我注意到循环中有一些重复的计算。 dstdata[lockedRectSubImg.Pitch * ybytes * x。同样在两个循环结束条件下,但xoffset + width 在迭代过程中会发生变化吗? @AlexP 在我打字时发表了评论。
  • memcpy 已高度优化,因此它可能一次复制最多 CPU 的寄存器大小字节,而不是仅复制单个字节,具体取决于数据对齐是否匹配。因此,memcpy 有可能更快。

标签: c loops optimization direct3d


【解决方案1】:

编译器无论如何都不会朝这个方向优化,但是我们可以通过添加适当的范围而不是仅仅递增来节省一些乘法,并且我们可以通过在循环之外设置初始起点来节省一些加法;另外,使用指针算法,我们只需要一半的加法(x[y] 等价于 *(x + y)!):

byte* srcdata = (byte*)compatablePixels;
// moving out of loop as many operations as possible:
byte* dstdata = (byte*)lockedRectSubImg.pBits
              + lockedRectSubImg.Pitch * yoffset + xoffset;

byte* end = dstdata + height * lockedRectSubImg.Pitch;
int xrange = width * bytes;
int step = lockedRectSubImg.Pitch - width * bytes;
// += step: avoid multiplications inside loop!
for (; dstdata < end; dstdata += step)
{
    for (x = xrange; x != 0; x--)
    // on some platforms, comparing against 0 is faster; at least, it is never slower...
    {
        dstdata++ = srcdata++;
    }
}

使用 memcpy:

byte* end = dstdata + height * lockedRectSubImg.Pitch;
int xrange = width * bytes;
for (; dstdata < end; dstdata += lockedRectSubImg.Pitch, srcdata += xrange)
{
    memcpy(dstdata, srcdata, xrange);
}

不过,未经测试的代码,如果你发现了一个错误,那就找一只青蛙喂它吧……

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-24
    • 2016-07-14
    • 1970-01-01
    • 2021-01-27
    • 2016-12-08
    • 1970-01-01
    • 2017-07-20
    相关资源
    最近更新 更多