OpenCL优化案例研究 (4)

OpenCL优化案例研究 (4)

    • 9.3 Sobel滤波
      • 9.3.1 算法优化
      • 9.3.2 数据包优化
      • 9.3.3 向量化加载/存储优化
      • 9.3.4 性能和总结
    • 9.4 总结

9.3 Sobel滤波

Sobel滤波,又称Sobel算子,被用于许多图像处理和计算机视觉算法的边缘检测。它使用两个3x3核与原始图像结合来近似求导数。有两个内核,一个是水平方向,另一个是垂直方向,如图9-7所示。

OpenCL优化案例研究 (4)_第1张图片

图9-7 Sobel滤波的双向操作

9.3.1 算法优化

Sobel滤波是一个可分离滤波,可以分解为:

图9-8 Sobel 滤波分解式

与不可分离的2D滤波相比,2D可分离滤波可以将复杂度从O(n2)降低到O(n)。由于二维滤波的高复杂度和计算成本,使用可分离滤波代替不可分离滤波是非常可取的。

9.3.2 数据包优化

虽然可分离滤波的计算量大大减少,但过滤每个点所需的像素数是相同的,即对于这个3x3核,8个相邻像素加上中心像素。很容易看出这是一个内存绑定问题。因此,如何有效地将像素加载到GPU中是提高性能的关键。三种选择如下图所示:

图9-9 每个工作项处理一个像素:每个内核加载3x3像素

OpenCL优化案例研究 (4)_第2张图片

图9-10 处理16x1像素:加载18x3像素

OpenCL优化案例研究 (4)_第3张图片

图9-11 处理16x2像素:加载18x4像素

下表汇总了每种情况下所需的总字节数和平均字节数。对于图9-9中的第1种情况,每个工作项只处理一个像素上的Sobel滤波。随着每个工作项的像素数量的增加,图9-10和图9-11所示的情况下,要加载的数据量会减少。这通常会导致从全局内存到GPU的数据流量减少,以带来更好的性能。

表9-4 三种情况下的数据加载/存储量

9.3.3 向量化加载/存储优化

使用OpenCL中的向量化加载/存储函数,如float4、int4和char4等,可以进一步减少16x1和16x2情况下的加载/存储数量。表9-5显示了向量化情况下的加载/存储请求数(假设像素数据类型为8位字符)。

表9-5 通过向量化加载/存储数值

short16 line_a = convert_short16(as_uchar16(*((__global uint4*)(inputImage+offset))));

有两个像素在边界被加载,如下:

short2 line_b = convert_short2(*((__global uchar2 *)(inputImage +offset+
16)));

注意:每个工作项处理的像素数的增加可能会导致严重的寄存器占用压力,导致寄存器溢出到私有内存并导致性能下降。

9.3.4 性能和总结

应用这两个优化步骤后,性能得到了显著提升,如图9-12所示,其中MSM8992 (Adreno 418)上的原始(单像素/工作项)归一化为1。

图9-12 通过数据包和向量化加载/存储来提升性能

总结一下,以下是这个用例优化的关键点。

  • 数据封装提高了内存访问效率
  • 向量化负载/存储是减少内存占用的关键
  • 在这种情况下,短类型优于整数或char类型

在这种情况下,不使用本地内存。数据包和向量化加载/存储将最小化可重用数据的重叠。因此,使用本地内存并不一定能提高性能。

还可以使用其他选项来提高性能,例如,在全局缓冲区上使用纹理。

9.4 总结

本章提供了一些示例和代码片段来演示前面章节中介绍的优化规则以及性能是如何变化的。开发者应该尝试在实际设备上遵循这些步骤。建议,由于编译器和驱动程序的升级,并不是所有的结果都可以精确地重现。但通常,通过这些优化步骤也可以实现类似的性能提升。

你可能感兴趣的:(OpenCL,笔记,Adreno,GPU,opencl,adreno)