1

我正在尝试构建一个总面积表,以供以后在自适应阈值例程中使用。由于此代码将用于时间关键型软件,因此我试图从中挤出尽可能多的周期。

出于性能考虑,该表是每个像素的无符号整数。

当我附加我的分析器时,我表明我最大的性能瓶颈发生在执行 x-pass 时。

计算的简单数学表达式是:

sat_[y * width + x] = sat_[y * width + x - 1] + buff_[y * width + x]
where the running sum resets at every new y position.

在这种情况下,sat_是表示 SAT 的无符号整数的一维指针,并且buff_是 8 位无符号单色缓冲区。

我的实现如下所示:

uint *pSat = sat_;
char *pBuff = buff_;

for (size_t y = 0; y < height; ++y, pSat += width, pBuff += width)
{
    uint curr = 0;
    for (uint x = 0; x < width; x += 4)
    {
        pSat[x + 0] = curr += pBuff[x + 0];
        pSat[x + 1] = curr += pBuff[x + 1];
        pSat[x + 2] = curr += pBuff[x + 2];
        pSat[x + 3] = curr += pBuff[x + 3];
    }
}

循环是手动展开的,因为我的编译器 (VC11) 没有为我做这件事。我遇到的问题是整个分段例程花费大量时间来运行该循环,我想知道是否有人对什么可以加快它有任何想法。我可以访问所有 SSE 的集合,以及运行该例程的任何机器的 AVX,所以如果那里有什么东西,那将非常有用。

此外,一旦我挤出最后一个周期,我就计划将其扩展到多核,但我希望在使模型更复杂之前让单线程计算尽可能紧凑。

4

2 回答 2

2

你有一个依赖链沿着每一行运行;每个结果都取决于前一个结果。所以你不能在那个方向矢量化/并行化。

但是,听起来每一行都独立于所有其他行,因此您可以通过同时计算多行来进行矢量化/并行化。您需要转置数组,以允许向量指令访问内存中的相邻元素。*

但是,这会产生一个问题。从缓存的角度来看,沿着行走现在绝对是可怕的(每次迭代都是缓存未命中)。解决这个问题的方法是交换循环顺序。

但请注意,每个元素都被精确读取一次。而且您对每个元素的计算量很少。因此,在达到 100% CPU 使用率之前,您基本上会受到主内存带宽的限制。


* 这个限制可能会在 AVX2 中解除,我不确定...

于 2013-03-06T23:15:53.850 回答
1

从算法上讲,我认为您无法做任何事情来进一步优化它。尽管您在描述中没有使用术语 OLAP 多维数据集,但您基本上只是在构建一个 OLAP 多维数据集。您拥有的代码是构建 OLAP 多维数据集的标准方法。

如果您提供有关您正在使用的硬件的详细信息,则可能有一些可用的优化。例如,有一种 GPU 编程方法可能会更快,也可能不会。注意:该线程上的另一篇文章提到并行化是不可能的。这不一定是真的......您的算法不能并行实现,但有些算法可以保持数据级并行性,可以通过 GPU 方法加以利用。

于 2013-03-07T01:29:53.390 回答