OpenCL 通用编程与优化(12)


8.4 回路展开

循环展开通常是一个很好的实践,因为它可以降低指令执行成本和提高性能。Adreno编译器通常可以根据某些启发式方法自动展开循环。但是,也有可能编译器会基于寄存器分配预算等因素选择不完全展开循环,或者编译器由于缺乏知识而无法展开循环。在这些情况下,开发人员可能会给编译器一个提示,或者手动强制它展开这些循环,如下所示:

  • 一个内核可以通过使用来给出一个提示
 __attribute__((opencl_unroll_hint)) or 
__attribute__((opencl_unroll_hint(n))).
  • 或者,内核也可以使用指令 #pragma unroll 展开循环。
  • 最后一个选项是手动展开循环。

8.5避免分支分化

一般来说,当同一波中的工作项遵循不同的执行路径时,gpu并不高。对于不同的分支,一些工作项可能会导致GPU占用率降低,如图8-1所示。此外,条件检查代码,就像ef-else一样,通常调用控制流硬件逻辑,这是昂贵的。

在这里插入图片描述
图8-1两波散度的图形表示

有一些方法可以避免或减少分歧和条件检查。在算法层面上,人们可以将属于一个分支的工作项分组为一个非发散波。开发人员可以将一些简单的发散的检查操作或有条件的检查操作转换为快速的ALU操作。第10.3.6节中的一个示例展示了由昂贵的控制流逻辑执行的三元操作如何被转换为快速的ALU 8.6操作。另一种方法是使用像选择这样的功能,它可以使用快速的ALU操作,而不是控制流逻辑。

8.6 处理图像边界

许多操作可以访问图像边界之外的像素。为了更好地处理边界,应考虑以下选项:

  • 如果可能的话,会提前放置图片。
  • 使用带有良好采样器的图像对象(纹理引擎会自动处理它)。
  • 编写单独的内核来处理边界,或者让CPU处理边界像素。

8.7 避免使用size_t

在许多情况下,64位内存地址给OpenCL内核编译带来了复杂性,开发人员必须小心。开发人员应该避免将变量定义为内核中的size_t类型。对于64位操作系统,一个在内核内定义为size_t的变量可能必须作为一个64位长来处理。Adrenogpu必须使用两个32位寄存器来模拟64位。因此,使用size_t变量需要更多的寄存器资源,这通常意味着由于较少的活动波和较小的工作组规模而导致的性能下降。因此,开发人员应该使用32位或更短的数据类型,而不是size_t。

对于返回size_t的OpenCL中的内置函数,编译器可能会尝试根据其知识推导出并限制其范围。例如,get_local_id以size_t的形式返回结果,尽管local_id永远不会超过32位。在这种情况下,编译器使用简短的数据类型。然而,通常为编译器提供数据类型的最佳知识是一个很好的做法,以便更好地提高寄存器的使用和代码质量。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值