您的位置:首页 > 运维架构

OpenCL简单入门介绍(根据《OpenCL Overview》翻译整理)

2014-01-27 16:36 453 查看
  根据《OpenCL Overview》与《OpenCL Technical Overview》整理编写,由于第一次接触OpenCL,定会有部分的专业词汇翻译不当,敬请指正。



1.《OpenCL Overview》整理笔记

这是一个异构的世界

  OpenCL让程序员写单一的可移植程序,在一个异构平台使用所有的资源

OpenCL使用

  1. 定义平台; 2. 在平台上执行代码; 3. 在内存中移动数据; 4. 编写(和编译)程序。

OpenCL平台模型

  一个主机(Host) +
一个或更多的计算设备

    -
每个计算设备由一个或多个计算单元组成

      -
每个计算单元进一步分成一个或多个处理元件



OpenCL执行模型

  OpenCL应用程序运行在一个主机(host)上,主机提交工作到计算设备。

    -工作项(Work
item)
:OpenCL上的基本工作单元

    -Kernel:工作项目的代码,基本上是个C函数

    -程序(Program):收集kernel和其它函数(类似于动态库)

    -上下文(Context):工作项目执行的环境,包括设备和它们的内存与命令队列

  应用程序队列kernel执行例子

    -
顺序排队,队列到设备

    -
顺序或乱序执行



OpenCL内存模型

  私有内存(Private
Memory)


    -
每个工作项

  局部内存(Local
Memory)


    -
工作组内共享

  全局/常量内存(Global/Constant
Memory)


    -
对所有工作组可见

  主机内存(Host
Memory)


    -
在CPU上

  内存管理显式的,你必须搬移数据从host
-> global -> local ...
,然后返回。



kernel编程:OpenCL C语言

  ISO C99的一个子集

    -
但是除了一些C99的特性,比如标准C99头文件,函数指针,递归,变长数组,和位域

  ISO
C99的一个超集


    -
工作项和工作组

    -
向量类型

    -
同步

    -
地址空间限定符(Address space qualifiers)

  包括一大组的内建函数

    -
图像处理

    -
工作项的处理

    -
专门的数学函数,等等

kernel编程:数据类型

  标量数据类型

    - char
, uchar, short, ushort, int, uint, long, ulong, float

    -
bool, intptr_t, ptrdiff_t, size_t, uintptr_t, void, half (storage)

  图像类型

    - image2d_t,
image3d_t, sampler_t

  向量数据类型

    -
Vector lengths 2, 4, 8, & 16 (char2, ushort4, int8, float16, double2, …)

    - Endian safe

    - 向量长度对齐

    - 向量操作

    - 内建函数



建立程序对象

  程序对象封装

    - 上下文

    - 程序源代码/二进制文件

    -
目标设备和构建选项的列表

  建立过程...
创建一个程序对象


    -
clCreateProgramWithSource()

    - clCreateProgramWithBinary()



OpenCL的同步:队列与事件(Queues & Events)

  事件可用于同步队列之间的kernel执行

  例子:两个队列,两个设备



OpenCL总结



2. 《OpenCL Technical Overview》整理笔记

OpenCL设计需求

  使用系统中的所有计算资源

    -
GPU,CPU,和其它处理器作为对等体一起编程

    -
同时支持数据/任务并行计算模型

  基于C的高效并行编程模型

    - 抽象底层硬件细节

  抽象是低层次、高性能的,但是设备可移植的

    -
容易上手,但主要正对开发专家

    -
生态系统基础,没有中间件或“便携”函数

  在嵌入式,桌面和服务器系统范围内都可实现

    -
HPC(高性能计算),桌面,一个规范内的手持式型材(handheld profiles)

  推动未来的硬件需求

    -
浮点精度需求

    -
同时适用消费和高性能计算应用

OpenCL剖析

  语言规范

    - 基于C的交叉平台编程接口

    - ISO
C99子集语言扩展,对开发者熟悉

    - 良好定义的数值精度,IEEE
754规定最大错误的四舍五入行为

    - 在线或离线编辑和构建的计算内核可执行文件

    - 包含一个丰富的内建函数集合

  平台层API

    - 多种计算资源之上的硬件抽象层

    - 查询、选择和初始化计算设备

    - 创建计算环境和工作队列

  运行时API

    -执行计算内核

    -管理调度、计算和内存资源

模型的层次结构

  > 平台模型

  > 内存模型

[b]  >
执行模型


[/b]

[b][b]  >
编程模型


[/b][/b]

OpenCL平台模型



  一个主机(Host) + 一个或更多的计算设备

    - 每个计算设备由一个或多个计算单元组成

      - 每个计算单元进一步分成一个或多个处理元件

OpenCL执行模型

  OpenCL编程

    - 内核

      - 执行代码的基本单元
--- 类似C函数

      - 数据并行或任务并行

    - 主机编程

      - 计算内核和内部函数收集

      - 类似于一个动态库

  内核执行

    - 主机程序通过一个叫做NDRange的索引空间调用内核

      - NDRange
=“N维范围”

      - NDRange,
可以是1, 2, 或3维空间

    - 一个内核实例在索引空间中的一个点称为一个工作项

      - 工作项有来自索引空间的唯一的全局ID

    - 工作项进一步组织成工作组

      - 工作组具有一个唯一的工作组ID

      - 工作项有在一个工作组中唯一的本地ID

内核执行

  工作项的总数:Gx X Gy

  每个工作组的大小:Sx X Sy

  全局ID可以从工作组ID本地ID计算得到



上下文和队列

  > 上下文(Contexts)用于控制和管理“世界”的状态

  > 内核(Kernels)在由主机定义和操作的上下文中执行

    -
设备


    -
内核
,OpenCL函数

    -
编程对象
,内核源代码及其可执行

    - 内存对象

  > 命令队列,协调内核的执行

    - 内核执行命令

    - 内存命令,传输或映射内存对象数据

    - 同步命令,控制命令的顺序

  > 应用队列计算内核执行实例

    - 顺序排队

    - 顺序或乱序执行

    - 事件被用于实现执行实例的适当同步

OpenCL内存模型

  > 共享内存模型

    - 宽松的一致性

  > 多个不同的地址空间

    - 地址空间可以根据设备的内存子系统进行折叠

  > 地址空间

    - 私有,专用于一个工作项
    - 本地,用于局部工作组

    - 全局,所有工作组中的所有工作项都可访问

    - 常量,只读全局空间

  > 实现这种映射层次

    - 对于可用物理内存



内存一致性

  ·OpenCL使用宽松的一致性内存模型;例如,对一个工作项可见的内存状态,对于整个工作项的集合并不一直保证一致性。”

  · 工作项内部,内存具有加载/存储一致性

  ·同一屏障内的一个工作组局部内存所有工作项具有一致性

  ·全局内存在同一屏障内的一个工作组内具有一致性,但对于不同的工作组不能保证一致性

  ·命令之间共享的内存一致性,通过同步被强制执行

数据并行编程模型

  · 定义N维计算域

    - 在一个N维域中的每个独立执行单元,被称为工作项

    - N维域定义的并行执行的工作项总数
= 全局工作大小

  · 工作组可以被组织在一起
--- 工作组


    - 组中的工作项可以相互通信

    - 可以在组内工作项之间同步执行,以协调内存访问

  · 并行执行多个工作组

    - 映射全局工作大小(global
work size)到工作组,可以是显式的或隐式的

任务并行编程模型

  · 数据并行执行模型必须被所有OpenCL计算设备实现

  · 一些计算设备,例如CPU也可以执行任务并行计算内核

    - 像单个工作项那样执行

    - 在OpenCL中编写的计算内核

    - 本地C/C++函数

基本OpenCL编程结构

  · 主机编程

[b]    平台层

[/b]

    - 查询计算设备

    - 创建上下文(Contexts)

    运行时

    - 创建上下文相关的内存对象

    - 编译和创建内核编程对象

    - 发出命令到命令队列

    - 命令同步

    - 清除OpenCL资源

[b]  · 内核[/b]

[b]    语言

[/b]

    -带一些限制和扩展的C代码

例子:向量加法

  · 计算
c = a + b


    -a,b和c是长度为N的向量

  · 基本的OpenCL概念

    - 简单内核代码

    - 基本上下文管理

    - 内存分配

    - 内核调用

平台层

  · 平台层允许应用程序查询平台的特定功能

  · 查询平台信息(例如,OpenCL配置文件)

  · 查询设备

    - clGetDeviceIDs()

    [b]  [/b]- 查找系统中存在哪些计算设备

      - 设备类型包括CPU,GPU或加速器

    - clGetDeviceInfo()

      - 查询发现计算设备的能力,例如:

      [b]  [/b]- 计算核心数量

        - NDRange限制

        - 最大工作组大小

        - 不同内存空间的大小(常量、局部变量和全局变量)

        - 最大的内存对象大小

  · 创建上下文

    - 上下文被OpenCL运行时用于在一个或多个设备中管理对象和执行内核

    - 上下文同一个或多个设备相关联

    [b]  [/b]- 多个上下文可以被关联到相同的设备

    - clCreateContext()和clCreateContextFromType()返回一个处理句柄来创建上下文

命令队列

  · 命令队列存储一组操作集来执行

  · 命令队列同上下文相关联

  · 多命令队列可以被创建,用于处理不需要同步的独立命令

  · 命令队列的执行在同步点被保证完成

向量加法:上下文、设备和队列



内存对象

  · 缓冲区对象

    - 对象的一维集合(像C的数组)

    - 有效的元素,包括标量矢量类型以及用户定义的结构

    - 缓冲对象可以通过内核中的指针被访问到

  · 图像对象

    - 二维或三维纹理,帧缓冲器或图像

    - 必须通过内建函数编址

  · 采样对象

    -
描述如何在内核中采样一张图像

    [b]  [/b]- 寻址模式

      - 过滤模式

创建内存对象

  · clCreateBuffer(),
clCreateImage2D(), 和clCreateImage3D()

  · 内存对象在一个相关的上下文中创建

  · 内存可以被创建为只读,只写,或读写

  · 对象在平台存储空间中的创建位置可以被控制

    - 设备内存

    - 存有从主机指针处拷贝的数据的设备内存

    - 主机内存

    - 与指针相关的主机内存

   [b]   [/b]- 在那个点的内存在同步点保证是有效的

  · 图像对象也用通道格式创建

    - 通道顺序(例如,RGB,RGBA,等)

    - 通道类型(例如,UNORM
INT8,FLOAT,等)

操作对象数据

  · 对象数据可以被拷贝到内存,从主机内存,或到其它对象

  · 内存命令在命令缓冲区中排队,当命令被执行时处理

    - clEnqueueReadBuffer(),
clEnqueueReadImage()

    - clEnqueueWriteBuffer(),
clEnqueueWriteImage()

    - clEnqueueCopyBuffer(),
clEnqueueCopyImage()

  · 数据可以在图像和缓冲区对象之间拷贝

    - clEnqueueCopyImageToBuffer()

    - clEnqueueCopyBufferToImage()

  · 对象数据的区域可以被访问,通过映射进主机地址空间

    - clEnqueueMapBuffer(),
clEnqueueMapImage()

    - clEnqueueUnmapMemObject()

向量加法:创建内存对象



编程对象

  · 程序对象封装

    - 一个相关的上下文

    - 程序源代码或二进制文件

    - 最新成功的程序构建,目标设备列表,构建选项

    - 附加的内核对象的数量

  · 构建过程

  [b]  1.
创建程序对象
[/b]

    [b]  [/b]- clCreateProgramWithSource()

      - clCreateProgramWithBinary()

    2.
构建程序可执行


[b]      [/b]- 从源代码或二进制文件编译和连接,对于所有设备或相关上下文中的特定设备

      - clBuildProgram()

      - 构建选项

      [b]  [/b]- 预处理器

        - 数学内部函数(浮点性能)

        - 优化

内核对象

  · 内核对象封装

    - 程序中声明的特定内核函数

    - 用于内核执行的参数值

  · 创建内核对象

    - clCreateKernel(),在程序中为单个函数创建内核对象

    - clCreateKernelsInProgram(),在程序中为所有内核创建一个对象

  · 设置参数

    - clSetKernelArg(<kernel>,
<argument index>)

    - 每个参数的数据必须在内核函数中进行设置

    - 参数值被拷贝和存储在内核对象中

  · 内核与程序对象比较

    - 内核与程序执行相关

    - 程序与程序源码相关

向量加法:程序与内核



向量加法:设置内核参数



内核执行

  · 一个执行内核的命令,必须排队到命令队列

  · clEnqueueNDRangeKernel()

    - 数据并行执行模型

    - 描述内核执行的索引空间

    - 需要NDRandge()维度和工作组大小的信息

  · clEnqueueTask()

    - 任务并行执行模型(多队列任务)

    - 内核在单工作项上执行

  · clEnqueueNativeKernel()

    - 任务并行执行模型

    - 执行一个未编译的本地C/C++函数,使用OpenCL编译器

    - 此模式不使用内核对象,因此参数必须被传递

命令队列和同步

  · 命令队列执行

    - 执行模型信号时,命令已完成或数据已准备就绪

    - 命令队列可以明确地刷新到设备

    - 命令队列顺序或乱序执行

    [b]  [/b]- 顺序,命令在顺序队列中完成,并且正确的内存是一致的

      - 乱序,不保证当命令执行时或内存是一致性的,没有同步的话

  · 同步

    - 当对主机的命令完成时的信号,或其它在队列中的命令

    - 阻塞调用

    [b]  [/b]- 命令未返回直到完成

      - clEnqueueReadBuffer()可以被调用作为阻塞,将会阻塞直到完成

    - 事件对象

      - 跟踪一个命令的执行状态

      - 一些命令可以阻塞指导事件对象发送一个先前命令完成的信号

      [b]  [/b]- clEnqueueNDRangeKernel()将一个事件对象作为参数,并等待直到一个先前命令(例如,clEnqueueWriteBuffer)完成

        - 配置文件

    - 队列屏障,队列命令可以阻塞命令的执行

向量加法:调用内核,读取输出



计算内核的OpenCL C

  · 由ISO
C99派生


    - 一些限制:递归,函数指针,C99标准头文件中的函数

    - 由C99定义的预处理指令被支持

  · 内建数据类型

    - 标量和常量数据类型,指针

    - 数据类型转换函数:convert_type<_sat><_roundingmode>

    - 图像类型:image2d_t,
image3d_t和sampler_t

  · 内建函数
--- 必须的


    - 工作项函数,math.h,读写图像

    - 关联式,几何函数,同步函数

  · 内建函数
--- 可选的


    - 双精度,原子到全局和局部内存

    - 舍入模式的选择,写到image3d_t上

OpenCL C语言函数要点

  · 函数限定符

    - “__kernel”限定符声明一个函数作为内核

    - 内核可以调用其它内核函数

  · 地址空间限定符

    - __global,
__local, __constant, __private

    -
指针内核参数必须用地址空间限定符修饰来声明

  · 工作项函数

    -
查询工作项的标识符

    - get_work_dim()

    - get_global_id(),
get_local_id(), get_group_id()

  · 图像函数

    -
图像必须通过内建函数来访问

    -
读写执行通过从主机采样对象或在源代码中定义

  · 同步函数

    - 屏蔽,组内的所有工作项必须在任何工作项可继续之前执行屏蔽函数

    -
内存栅栏,提供对存储器操作的顺序

向量加法内核



OpenCL C语言限制

  · 不支持
函数指针

  · 在同一个内核中,允许使用指向指针的指针,但不能作为一个参数

  · 不支持 位域

  · 不支持 可变长数组和结构体

  · 不支持 递归

  · 不支持 写入的类型小于32位的指针

  · 不支持 double类型,但保留

  · 不支持 3D影像写操作

  · 有些限制是通过扩展解决

可选的扩展

  · 扩展是可选功能,通过OpenCL接触

  · OpenCL的工作组已经批准了由OpenCL的规格支持多种扩展功能

  [b]  [/b]· 双精度浮点类型

    · 内建函数来支持doubles

    · 原子函数

    · 三维图像写入

    · 字节寻址存储(写指针类型<32位)

    · 内建函数支持半类型

OpenGL互操作性

  · 一个IP架构下两个标准

    - 使得非常密切的协作设计

  · 高效的跨API通信

    - 同时仍然允许这两个API来处理其设计工作负载的类型

  · OpenCL可高效地同OpenGL共享资源

    - 纹理,缓冲区对象,渲染缓冲

    - 数据是共享的,但不可复制

    - OpenCL的对象是从OpenGL的对象创建

    [b]  -[/b] clCreateFromGLBuffer(),
clCreateFromGLTexture2D(), clCreateFromGLRenderbuffer()

  · 应用程序可选择计算设备来运行OpenCL和OpenGL

    - 高效地排队OpenCL和OpenGL命令到硬件

    - 灵活的调度和同步

  · 举例

    - 顶点(Vertex)和图像数据由OpenCL的生成,然后用OpenGL渲染

    - 图像由OpenGL渲染后,由OpenCL内核后处理

OpenCL总结

  · 跨供应商标准的便携式异构编程

    - 开放、免费的版权标准,来自主要供应商的临界质量支持

  · 创造显著的商业机会

    - 移除作为市场障碍的碎片化,以增加并行计算的增长

  · 在Khronos的API生态系统中的核心角色

    - 在Khronos,多个相关的API正被在一个IP框架下合作开发

  · 快速部署

    - 公开规则在六个月内产生,在2009年实现

    - 将运行于目前最新一代的GPU硬件

  · 更多说明书和幻灯片在www.khronos.org/opencl/

    - 如果这里讲的与你公司相关,请加入Khronos并且动手!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: