2014-07-23 60 views
2

我想优化自适应滤波代码使用AVX的滤波器内核可能是随机的每个像素(说0到991)。使用AVX指令集的自适应滤波器的优化

它相应的C代码在下面给出:

/* filter function */ 
    void filter() 
{ 
    int size = width *height; // image size 
    float w[992][11];   // filter kernel array 
    float x[size + 10], y[size], filterindex[size]; // input , output , filter index 

    for (i = 0; i < size; i++) 
    { 
    int l; 
    /* pick filter: */ 
    l = filterindex[i]; 

    /* apply filter */ 
    for (k = -5, a = 0.; k <= 5; k++) 
     a += x[i+k] * w[l][5+k]; 
     y[i] = (float)a; 
    } 
} 

其中

  1. filterindex是保持每个像素滤波器索引(0到991)一个输入缓冲器[没有关于这些无图案周围像素之间的索引]
  2. x被输入并且y被输出
  3. w是大小w[992][2*N_filt + 1]的过滤器内核,每个索引初始化设置992

任何一个可以帮助我如何使用AVX优化上面的代码?如果AVX是不可能的,那么请建议任何其他方式来优化3x的目标。

+0

只是AVX,还是AVX2可用? –

+0

我认为在这种情况下,使用SIMD可以获得3倍的提升。没有太多的并行性可以得到;滤波器内核本身太短而不能通过并行计算卷积碎片而获得很多好处,并且内核在每个像素基础上不同的事实使并行计算多个像素变得复杂。您可能会略微改进一些,我认为这是一个提升级别并搜索算法变更以提高速度的例子,这将是您最好的选择。 –

+0

第二个for循环可能不会像你期望的那样工作,因为'y [i] =(float)a;'在循环之外 –

回答

1

对于每个输入像素,您可以在两个AVX寄存器(第二个填充5个零)中加载11个滤波器系数,并以类似方式加载像素:_mm256_load_ps。

将两个值相乘并将其相加,给出8个2种产品的总和:_mm256_mul_ps,_mm256_fmadd_ps。

接下来,您需要使用一系列水平添加来浓缩为单个值,从而生成4,8和16个产品的总和:_mm_hadd_ps。

总数:每个输出像素9条指令。

+1

由于以下两个操作1,此方法不会给出更好的增益。>要压缩为单个值。>请用零填充 – vijayky88

+0

填充是什么意思?像素/系数还是稍后浓缩?在第一种情况下,如果滤波器系数存储在用零填充的[911] [16]阵列中(这会使无关像素消失),则不需要明确填充。 –

1

由于每个像素的权重不同,您可能无法获得巨大的加速,因为您必须对滤镜权重进行收集加载,所以尝试使用AVX一次过滤多个像素。使用相干加载的另一种方法是采用内部循环并行执行8次乘法,因为您要从内存中连续加载x中的像素,并在内存中连续地从w中过滤权重。由于您有11个权重,因此无法理想地映射到AVX寄存器宽度,但您仍应看到加速。然后您可以使用_mm_hadd_ps来总结结果。您可能想要将循环展开到多个像素以隐藏添加的一些延迟。或者,您可以尝试使用_mm_dp_ps点积指令将乘法和加法放在一起,但可能会更快,但延迟更高,因此您需要更多地展开循环。

此循环也是非常可并行化的,因此可能值得考虑将工作分解到多个线程。

+2

@mathnewport:我确实考虑过使用_mm_hadd_ps和_mm_dp_ps,但得到的收益微乎其微。即使展开也没有帮助我们。考虑到所有的方法,我们只观察到1.7倍左右的增益。目前我们还没有使用多线程方法寻找解决方案。 – vijayky88

+0

这种情况很有可能是内存带宽受限。你有没有做过任何分析? – mattnewport

+1

我已经使用rdtsc()和Vtune进行了性能分析 – vijayky88