这章将简要讨论一些开发Adreno OpenCL应用程序的基本要求,下面将会介绍如何调试和统计程序性能。

4.1  安卓平台上开发OpenCL程序

目前,Adreno GPU主要是在安卓操作系统和在部分Linux系统上支持OpenCL。为了开发带OpenCL的安卓app,开发者必须熟悉android软件开发套件(SDK)和本地开发套件(NDK 用来运行C/C++)。更多关于Android SDK和NDK的信息,可分别参考https://developer.android.com/index.htmlhttps://developer.android.com/ndk/index.html

在这章和接下来的章节中,我们假设是在Android平台上进行开发,并且开发者对Android SDK和NDK有相关经验。基于Linux的app开发与之类似。

下面是关于在骁龙平台上开发OpenCL的一些必要条件:

  • 支持OpenCL的骁龙设备。并不是所有的骁龙设备都支持OpenCL。可参考表3-1获取更多细节。
  • OpenCL软件。在Adreno GPUs上的OpenCL需要依赖QTI合适的库文件。
    •   检查设备上是否安装了OpenCL库。核心库是libOpenCL.so,通常会放在设备的/vendor/lib目录下。
    •   一些生产商会选择并不包含OpenCL软件(比如Google的Nexus和Pixel devices)。
  • OpenCL必须运行在NDK层。
  • 对于开发和测试来说,root访问权限并不是必须的,不过如果需要使用高性能模式在SOC上运行,就会需要root权限。

表4-1在Adreno GPUs上开发OpenCL的条件

条目

要求

备注

设备

Adreno A3x/A4x/A5x GPUs

操作系统

安卓,Linux

只有某些Linux平台支持OpenCL

需要的设备软件

设备上的libOpenCL.so

可能有些设备上没有

开发要求

Adreno NDK/SDK

OpenCL代码需要运行在NDK层上

设备的root访问权限

通常不需要

在高性能模式下需要

4.2 调试工具

由于GPU的并行执行特点,调试OpenCL核通常是比较具有挑战的。Adreno GPUs支持在kernel函数内部调用printf函数,这个对于调试来说非常有用。使用printf时,建议减少工作负载,因为printf会减慢代码的执行,输出有条件限制的变量从而避免打印出太多次。比如说,可能只使能一个有问题的workgroup,甚至是单个有问题的work item(通过在CLEnqueueNDRangeKernel中设置合适的偏移)。

知道设备的软件版本号是很重要的,因为某些错误或者问题或许已经在新版本中解决了。使用API函数clGetDeviceInfo,可以查询软件(驱动)和编译器的版本。可查看参考文献获取更多信息。

4.3 骁龙分析器(Snapdragon Profiler)

骁龙分析器是由QTI提供的一个统计分析工具,可以运行在Windows,Mac和Linux平台,能够让开发者分析在Android上运行的骁龙处理器的一些信息,包括CPU,GPU,DSP,内存,功率,热量,网络数据等。它支持OpenCL和许多图像的APIs,比如OpenGL ES和Vulkan。为了获取更多细节,请参考https://developer.qualcomm.com/software/snapdragon-profiler.

下面是骁龙分析器针对OpenCL进行统计分析而提供的关键特性:

1. 分析器有一个kernel分析器,可以对一个指定的kernel进行静态分析。它会提供比如寄存器占用空间,指令总数和每一种类型指令的数量等信息,这些可以帮助开发者更好的优化kernels。

2. 分析器会对指定的OpenCL应用程序提供OpenCL 的API调用轨迹和日志。这个功能可以让开发者从API层面就发现和解决瓶颈,同样也可以调试程序(通过查看调用轨迹和日志)

3. 分析器会提供一些信息,比如GPU繁忙率,ALU使用率,L1/L2 cache命中率等,这些是开发者分析kernel函数性能问题的基本信息。

4. 分析器支持基于命令行的应用程序,同样支持Android GUI app。

4.4 性能统计

给定一个app,准确统计他的性能是很困难的。GPU计时和GPU计时是两个常用的方法,它们的不同点将会在接下来的章节中讨论。

4.4.1 CPU计时

CPU计时是用来测量在主设备端调用OpenCL的完整执行时间。可以通过使用标准的C/C++语言库中提供的任何日期或者时间的函数来实现。下面是一个使用gettimeofday的例子。

#include <time.h>

#include <sys/time.h>

void main() {

struct timeval start, end;

gettimeofday(&start, NULL); /*get the start time*/

/*Execute function of interest*/ { . . .

clFinish(commandQ);

}

gettimeofday(&end, NULL); /*get the end time*/

/*Print the total execution time*/

printf("%ld\n", ((end.tv_sec * 1000000 + end.tv_usec)

- (start.tv_sec * 1000000 + start.tv_usec)));

}

OpenCL的实时运行队列API函数可以分为阻塞调用和非阻塞调用。对于非阻塞调用,使用CPU计时需要考虑以下几点:

  • 非阻塞调用意味着,主设备提交完任务(任务通常是放在另外一个CPU线程中排队等待执行)后,就会执行下一条指令,而不是等待函数执行完毕。

    •   kernel执行的API函数,clEnqueueNDRangeKernel,是一个非阻塞函数。
  • 对于非阻塞调用,真正的执行时间并不是函数调用的前后时间差。

当使用一个CPU计时器在host端测量kernel执行时间的时候,必须保证这个函数完全执行完,可以通过使调用clWaitforEvent(如果针对非阻塞调用有一个eventID)或者clFinish保证。同样的规则适用于调用内存交换函数的时候。

4.4.2 GPU计时

所有的OpenCL队列函数的调用,可以有选择的向host返回一个事件对象,OpenCL的性能统计API函数可以使用这个事件对象来查询执行时间。Adreno GPUs用它们自己的时钟和计时器来测量函数执行流程,并且GPU的执行时间是由GPU硬件计数器决定的,与操作系统无关。

要使能GPU计时器的功能,需要对当前的命令队列,在函数clCreateCommandQueue或者clSetCommandQueueProperty中合适位置设置标志CL_QUEUE_PROFILING_ENABLE。而且,必须为队列函数提供一个事件对象。一旦函数执行完,可以使用API函数clGetEventProfilingInfo来获取命令队列的性能统计信息。

对于一个clEnqueueNDRangeKernel调用,使用clGetEventProfilingInfo函数并设置4个统计参数,包括CL_PROFILING_COMMAND_(QUEUED , SUBMIT, START,和END)后,可以提供一个在Andreno GPU kernel启动延迟和kernel执行时间的精确的快照,如图4-1所示。

  • 前两个参数CL_PROFILING_COMMAND_(QUEUED和SUBMIT)之间的差,给出软件的开销和CPU cache 操作的开销。OpenCL软件可能选择一个kernel先加入队列,然后与接下来入队的其他kernel一起提交,如果队列中的kernel函数足够多。开发者可以使用clFlush来加速提交。
  • CL_PROFILING_COMMAND_(SUBMIT和START)的差可以给出GPU正在运行的其他工作的时间。
  • CL_ PROFILING _COMMAND_(START和END)之间的差就是kernel在GPU上的运行时间。

开发者主要就是缩小实际的kernel的运行时间。对于其他两个比较难控制的时间来说,这个的提升相对简单些。

图4-1 在Adreno GPUs中clEnqueueNDRange中的性能统计标志

4.4.3 GPU计时 vs. CPU计时

GPU和CPU计时器都可以用来统计性能性能,那对于应用程序来说使用哪一个来呢?尽管GPU计时器能能够精确的测量出GPU执行时间,但是一些硬件操作时间(比如cache 刷新)和一些软件操作(比如CPU和GPU的同步)是不在GPU的时钟系统中的。所以,对于kernel执行,GPU计时统计的性数据看起来比CPU计时统计的要好。下面是两个实际操作中的建议:

  • GPU计时应该用来衡量kernel的优化效果。GPU计时能够准确的统计出,从GPU执行的角度,通过这些优化的步骤能提升了多少性能。
  • CPU计时应该用来测量整个程序的端对端的性能(就是整个程序的性能)。如果OpenCL程序是整个应用程序流水线的一部分,那应该使用CPU计时来统计。

4.4.4 高性能模式

骁龙的SOC拥有先进的动态时钟和电源管理机制,这种机制能够自动控制系统使系统在特定的场景中运行在低功耗模式下,这种模式能够减少耗电。通常情况下,如果有高强度的工作负荷,系统会自动提升时钟频率和电压,使得设备进入所谓的高性能模式,从而提升性能和满足高工作负荷。

对于OpenCL优化,如果系统动态调整了时钟频率,理解和统计性能是十分困难的。因此,为了性能的精度和一致性,建议使能高性能模式。

如果没有设置高性能模式,在一系列的OpenCLkernel中,第一个kernel函数通常会表现出更长的启动延迟和更慢的执行时间。所以,必须在启动真正的GPU任务之前,需要用一些简单的kernel热身GPU。

一个OpenCL kernel的性能不是只依赖于GPU。在CPU上运行API函数跟在GPU上执行的kernel一样重要。所以,为了达到最佳性能,CPU和GPU都需要使能高性能模式。另外,为减少来自UI渲染的接口调用,建议:

  • 保证当前正在统计的性能的应用程序已经渲染了整个屏幕,这样其他的动作不能再更新屏幕。
  • 如果是一个内部的程序,保证SurfaceFlinger并没有在安卓上运行。这样就能保证,只有正在被统计性能的应用函数在使用CPU和GPU。

对于A3x, A4x和 A5x GPU,使能高性能模式的一系列命令有很大的区别。可参考Section A获取更多细节。

4.4.5 GPU的频率控制

应用程序可以使用cl_qcom_perf_hit扩展功能来控制GPU频率。当创建OpenCL上下文时,这个扩展功能允许应用程序设置一个性能提示属性。性能的等级可以使HIGH,NORMAL和LOW.NORMAL性能等级会使能动态的时钟和电压控制。HIGH和LOW性能等级将会禁止这种动态控制,强制GPU分别运行在最高和最低频率上。

注意:性能等级仅仅是一个提示。驱动会尝试遵循这个提示,但是,其他一些因素,比如热量控制,或者外部的应用程序或服务都可以否决这个提示。这个性能提示的扩展功能给了应用程序一些平衡功率/性能弹性。但是,必须要小心的使用,因为这个对SOC层的功耗消耗有很大的影响。

Qualcomm_Mobile_OpenCL.pdf 翻译-4-Adreno OpenCL的程序开发的更多相关文章

  1. Qualcomm_Mobile_OpenCL.pdf 翻译-2

    2  Opencl的简介 这一章主要讨论Opencl标准中的关键概念和在手机平台上开发Opencl程序的基础知识.如果想知道关于Opencl更详细的知识,请查阅参考文献中的<The OpenCL ...

  2. Qualcomm_Mobile_OpenCL.pdf 翻译-1

    1 前言 1.1 目的 这篇文档的主要目的是,向原始设备制造商(OEMs),独立软件供应商(ISVs),第三方开发者们,提供在基于高通骁龙400系列.600系列,和800系列的手机平台和芯片上进行开发 ...

  3. Qualcomm_Mobile_OpenCL.pdf 翻译-7 内存性能优化

    内存优化是最重要也是最有效的OpenCL性能优化技术.大量的应用程序是内存限制而不是计算限制.所以,掌握内存优化的方法是OpenCL优化的基础.在这章中,将会回顾OpenCL的内存模型,然后是最优的实 ...

  4. Qualcomm_Mobile_OpenCL.pdf 翻译-6-工作组尺寸的性能优化

    对于许多kernels来说,工作组大小的调整会是一种简单有效的方法.这章将会介绍基于工作组大小的基础知识,比如如何获取工作组大小,为什么工作组大小非常重要,同时也会讨论关于最优工作组大小的选择和调整的 ...

  5. Qualcomm_Mobile_OpenCL.pdf 翻译-5-性能优化的概述

    这章提供了一个OpenCL应用程序优化的总体概述.更多的细节将会在接下来的章节中找到. 注意:OpenCL程序的优化是具有挑战性的.相比初始的程序开发工作,经常需要做更多的工作. 5.1 性能移植性 ...

  6. Qualcomm_Mobile_OpenCL.pdf 翻译-3

    3 在骁龙上使用OpenCL 在今天安卓操作系统和IOT(Internet of Things)市场上,骁龙是性能最强的也是最被广泛使用的芯片.骁龙的手机平台将最好的组件组合在一起放到了单个芯片上,这 ...

  7. Qualcomm_Mobile_OpenCL.pdf 翻译-9-OpenCL优化用例的学习

    在这一章中,将会用一些例子来展示如何使用之前章节中讨论的技术来进行优化.除了一些小的简单代码片段的展示外,还有两个熟知的图像滤波处理,Epsilon滤波和Sobel滤波,将会使用之前章节中讨论的方法进 ...

  8. Qualcomm_Mobile_OpenCL.pdf 翻译-8-kernel性能优化

    这章将会说明一些kernel优化的小技巧. 8.1 kernel合并或者拆分 一个复杂的应用程序可能包含很多步骤.对于OpenCL的移植性和优化,可能会问需要开发有多少个kernel.这个问题很难回答 ...

  9. Qualcomm_Mobile_OpenCL.pdf 翻译-10-总结

    这篇文档主要是介绍了关于在Adreno GPUs上优化OpenCL代码的详细方法.文档中提供的大量信息能够帮助开发者理解OpenCL基础和Adreno结构,还有最重要的,掌握OpenCL优化技能. O ...

随机推荐

  1. tps抖动

    https://blog.csdn.net/lzqinfen/article/details/46820673 tps抖动厉害的原因?突然增加成倍的用户,如果性能表现良好,TPS应该成倍增加,响应时间 ...

  2. 让socket端口不被子进程继承

    有两个程序A,B A绑定端口8000,然后用system函数启动程序B,然后再把A杀掉,这个时候再重启A的时候会发现绑定端口失败, 原因是端口被B绑定了,实际上是被继承了,为了避免这种情况,需要对主s ...

  3. JAVA-Runnable、Callable、FutureTask

    通常,创建线程的执行单元有两种,一种是直接继承 Thread,另外一种就是实现 Runnable 接口. 但这两种都有一个问题就是无法有返回值,且子线程在执行过程中无法抛出异常.想线程有返回值,可以使 ...

  4. OpenCV学习笔记(5)——颜色空间转换

    学习如歌对图像进行颜色空间转换,从BGR到灰度图,或者从BGR到HSV等 创建一个程序用来从一幅图像中获取某个特定颜色的物体 1.转换颜色空间 OpenCV中有超过150种进行颜色空间转化的方法,但是 ...

  5. Python解决数据样本类别分布不均衡问题

    所谓不平衡指的是:不同类别的样本数量差异非常大. 数据规模上可以分为大数据分布不均衡和小数据分布不均衡.大数据分布不均衡:例如拥有1000万条记录的数据集中,其中占比50万条的少数分类样本便于属于这种 ...

  6. JavaEE-实验二 Java集合框架实验

    该博客仅专为我的小伙伴提供参考而附加,没空加上代码具体解析,望各位谅解 1.  使用类String类的分割split 将字符串  “Solutions to selected exercises ca ...

  7. 阶段3 2.Spring_07.银行转账案例_8 基于接口的动态代理回顾

    创建 Producer 生产者的类 创建标准.这标准就是接口 创建消费者的类 以前的方式,客户直接找生产厂家 代理商出现以后,怎么去联系代理商 动态代理 第一个参数是ClassLoader 第二个参数 ...

  8. kernel function

    下面这张图位于第一.二象限内.我们关注红色的门,以及“北京四合院”这几个字下面的紫色的字母.我们把红色的门上的点看成是“+”数据,紫色字母上的点看成是“-”数据,它们的横.纵坐标是两个特征.显然,在这 ...

  9. Java servlet和JSP的区别和联系

    Java servlet技术:在Java代码中嵌入HTML JSP技术:HTML输出时比较便捷,就在HTML中嵌入Java代码 Java servlet技术:擅长编写Java代码 JSP技术:擅长页面 ...

  10. docker容器和宿主机之间复制文件

    https://blog.csdn.net/u012416928/article/details/55049063 https://blog.csdn.net/u011596455/article/d ...