利用AVX指令集优化自适应滤波器

时间:2014-07-23 12:44:44

标签: optimization filtering intel sse avx

我正在尝试使用AVX优化自适应滤波代码,其滤波器内核对于每个像素(例如0到991)可能是随机的。

下面给出了相应的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. 输入
  3. x,输出y
  4. w是大小为w[992][2*N_filt + 1]的过滤器内核,其中每个索引初始化为992 set
  5. 任何人都可以帮我了解如何使用AVX优化上述代码吗?如果无法使用AVX,请建议任何其他方法来优化目标为3x。

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

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

相乘并成对添加值,为您提供8种产品的总和:_mm256_mul_ps,_mm256_fmadd_ps。

接下来,你需要使用一系列水平加法压缩为单个值,产生4,8和16个产品的总和:_mm_hadd_ps。

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