我正在尝试构建一个求和区域表,以便以后在自适应阈值程序中使用。由于此代码将用于时间关键型软件,我试图从中挤出尽可能多的周期。
为了提高性能,表格是每个像素的无符号整数。
当我附上我的探查器时,我发现执行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的无符号整数的1-D指针,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,所以如果有什么东西,这将是非常有用的。
此外,一旦我挤出最后一个循环,我就会计划将其扩展到多核,但我希望在使模型更复杂之前尽可能地使单线程计算更紧密。
答案 0 :(得分:2)
每行都有一个依赖关系链;每个结果取决于前一个。所以你无法在那个方向上进行矢量化/并行化。
但是,听起来每行都独立于所有其他行,因此您可以通过同时计算多行来进行矢量化/并行化。您需要转置数组,以便允许向量指令访问内存中的相邻元素。 *
但是,这会产生问题。从缓存的角度来看,沿着行走现在是非常糟糕的(每次迭代都是缓存未命中)。解决这个问题的方法是交换循环顺序。
但请注意,每个元素只能精确读取一次。而且你每个元素的计算量很少。因此,在达到100%的CPU使用率之前,你基本上会受到主内存带宽的限制。
<小时/> *此限制可能会在AVX2中解除,我不确定......
答案 1 :(得分:1)
从算法上讲,我认为你无法做进一步的优化。即使您没有在描述中使用术语OLAP多维数据集,您基本上只是构建一个OLAP多维数据集。您拥有的代码是构建OLAP多维数据集的标准方法。
如果您提供有关您正在使用的硬件的详细信息,则可能会进行一些优化。例如,有一种GPU编程方法,可能会更快,也可能不会更快。注意:此主题上的另一篇文章提到并行化是不可能的。这不一定是真的......你的算法不能并行实现,但有些算法可以维持数据级并行性,可以用GPU方法来利用它。