笔记第1篇-OpenCL基础

注:本笔记基于互联网上各个博文整合,如有侵权请及时告知。文末有参考博文的链接。

CPU,GPU的架构简介

CPU:多指令单数据流(流水线模式),MISD,擅长逻辑控制。

GPU:单指令多数据流(向量算法),SIMD,擅长并行计算。

所以1个CPU+几个GPGPU(通用并行处理的GPU)的架构即异构编程。

使用通用的OpenCL接口(API)开发的应用可以在不同的SDK中通用,OPenCL只是一个标准,Intel,AMD,NVIDIA等各大厂商采用不同的SDK进行自定制的开发;

OpenCL硬件层的抽象

它是一个Host(控制处置单元,常通由一个CPU担负)和一堆Compute Device(计算设备,由一些GPU、CPU其他支撑的芯片担负),其中Compute Device切分为很多Processing Element(这是独立介入单数据计算的最小单元,这个不同硬件实现都不一样,如GPU可能就是其中一个Processor,而CPU多是一个Core,我猜的。。因为这个实现对开发者是隐藏的),其中很多个Processing Element可以构成组为一个Compute Unit,一个Unit内的element之间可以便利的同享memory,也只有一个Unit内的element可以实现同步等操作。

可以理解为:

Host是公司的总经理:负责对公司的整体任务分配与调度。

Compute Device是公司总经理管理的若干个实施部门:各个这样的部门负责把总经理分配的任务并行地完成。但是,各部门执行同样的运算任务。

Compute Unit是各部门下面的各个项目组,负责把任务在技术层面上实现。各个项目组的技术细节不对外公开(项目组内共享Local Memory)。

Processing element是员工,负责项目组内任务的实施,是最底层的工作节点。员工有自己私有的技术(Private Memory)。整个公司内,每个Processing Element有自己的索引号(Global ID),工号。在每个项目组(Workgroup)内,有自己项目组内的编号,就是LocalID。下图从Compute Device进行划分。

如上图,有全局内存(变量),全局常量,本地内存以及局部变量。

OpenCL的软件层架构:

Setup相关知识(系统的初始化):

-Device:对应一个计算设备;注意,多核的CPU是一个整个的Device。即Device是单个CPU或GPU或FPGA。

-Context:上下文;一个Context包括几个Device,Context是这些Device的联系纽带,只有在同一个Context里的Device才能彼此交流任务。你的单板上可以有很多Context。Context可以由CPU或CPU+GPU创建。

-Command queue:给每个Device提交的指令序列。

内存相关知识:

       -Buffer:内存

       -Images:原生的用于GPU运算的图像处理的“类型”,表示各种维度的图像。

       -数据交互的方式:A 将地址拷贝到工作组空间,计算完成再拷贝出去(传形参);B 将计算数据组的地址传输进去(传指针)。

GPU代码执行相关知识:

       -Program:包括Kernel和其他库等。OpenCL是动态编译的语言,源代码编译后生成一个相同的中间文件,该中间文件连接不同的linker时生成不同的程序。然后将程序读入Compute Device。

       -kernel:在processing element(PE,员工)处跑的内核程序,是最基本的处理事情。各个PE的内核(算法)相同而处理的数据不同,这就是所谓的单指令多数据体系(SIMD)。

       -Work item:processing element在代码里的表示,一个Work Item代表一个processing element(PE,员工)。

       -程序对象:内核程序的源代码文件(.cl文件)和可执行文件。内存对象:计算设备执行OpenCL内核程序所需的变量。

并行与同步相关的知识:

       -任务并行与数据并行:任务并行是指流水线的工作模式。数据并行是指多组数据同时进行相同计算的方式(所有的矩阵操作基本都可以用!)

       -Command queue命令队列:每个计算设备Compute Device都有一个或多个命令队列。但一个命令队列只管理一个计算设备。通过命令队列,可以实现宿主机和计算设备的异步控制。分为启动命令(开始执行kernel程序);内存命令(在host和内存设备之间移动数据,或进行内存映射);同步命令(约束命令在计算设备的执行情况)。

       -Events(事件):命令队列中每条命令都有着命令的状态,当命令的状态发生变化,就产生了事件Event。在分布式计算的环境中,Events用于不同计算单元之间的同步。

-按事件发生位置来分:内核端事件:主要负责异步执行命令的同步操作(多个处理单元的阶段同步)和全局内核和本地内存的同步。主机端事件:完成命令队列之间的同步操作(统筹各个计算设备的操作)。

-按事件发生原因来分:

命令事件

CL_QUEUED:命令已经加入命令队列。

CL_SUBMITTED:命令已经有宿主机提交给与所在命令队列相关联的设备。

CL_RUNNING:该命令正在执行。

CL_COMPLETE:命令已经完成

ERROR_CORE:负数,指代不同的错误情况。

用户自定义事件

需要进行同一上下文内的各ConputeDevice之间同步时,用用户自定义事件。

cl_event clCreateUserEvent(

cl_context context, //指定上下文

cl_uint* errcode_ret //该函数所关联的错误值

)

如果创建成功,errcode_ret会被赋值为CL_SUCCESS或者错误时,赋值为以下的值:

CL_INVALID_EVENT:上下文不合法

CL_OUT_OF_RESOURCE: 资源未就绪或分配资源失败

CL_OUT_OF_HOST_MEMORY:宿主机资源未就绪或分配资源失败

之后我们就可以在各个处理函数中设置返回的事件的值:

cl_intclSetUserEventStatus(

cl_eventevent, //具体事件值

cl_intexecution_status //指向状态

)

-同步:

OpenCL是基于任务并行,主机控制的模型,其中每一项任务都是数据并行的,具体通过使用和设备关联的线程安全的命令队列来实现。

-单设备同步:通过以下设置:

A设置barrier(即屏障,在组内所有的item没有到达这个barrier之前,所有的item是不向下执行的)。

cl_int clEnqueueBarrier(

cl_command_queuecommand_queue

)

B等待事件(等待事件,即将一个等待事件加入命令队列,只有这个等待事件满足以后,才能执行之后加入的命令)。

C阻塞访问:在内存IO读取时设置一个标志,当标志有效时,会阻塞直到拷贝完成。

-多设备同步:cFinish,等待另一个命令队列执行完成,之后的命令才能继续执行。如一个CPU一个GPU,两者需要互相访问彼此的数据,那么如何实现同步呢,如果CPU要访问CPU的数据,必须等待CPU当前的命令队列执行完成,不再占用内存,GPU才能进行访问。clFinish可以阻塞程序的执行直到命令队列中的所有命令都执行完成。但是这只是相当于在末尾加上了一个barrier。



posted @ 2018-04-16 14:17  云远·笨小孩  阅读(386)  评论(0编辑  收藏  举报