我正在尝试使用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;
}
}
,其中
filterindex
是一个输入缓冲区,它为每个像素保存滤镜索引(0到991)[周围像素之间的这些索引上没有图案] x
,输出y
w
是大小为w[992][2*N_filt + 1]
的过滤器内核,其中每个索引初始化为992 set 任何人都可以帮我了解如何使用AVX优化上述代码吗?如果无法使用AVX,请建议任何其他方法来优化目标为3x。
答案 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条指令。