opencl 的基本介绍 -...

11
2 OpenCL 的基本介绍 本章开始,将以 OpenCL 的历史背景作为出发点,逐步介绍 OpenCL 有关知识。本章将 介绍 OpenCL 历史、 OpenCL 平台模型、执行模型、存储器模型、 OpenCL OpenGL 的关联、 OpenCL CUDA 的区别与联系。通过以上介绍,使得读者对于 OpenCL 有一个整体认识。 2.1 什么是 OpenCL 2008 年,苹果公司向 Khronos Group 提交了一份关于跨平台计算框架的草案,该草案由 苹果公司开发,并与 AMDIBMIntel NVIDIA 公司合作逐步完善。这个跨平台计算框 架就是 OpenCL Open Computing Language,开放计算语言)。2008 12 8 日, OpenCL 1.0 技术规范发布。2010 6 14 日, OpenCL 1.1 发布。2011 11 19 日, OpenCL 1.2 发布。 2013 11 19 日,OpenCL 2.0 发布。 OpenCL 是一个为异构并行计算平台编写程序的工业标准,此异构计算平台可映射到 CPUGPUDSP FPGA 等计算设备。OpenCL 提供了底层硬件结构的抽象模型,旨在提 供一个通用的开放 API,既减轻开发人员的编程难度,又让开发人员能够写出高效可移植代 码。例如,使用 OpenCL,开发人员可以编写在 GPU 上运行的通用计算程序,而无须将其算 法映射到 OpenGL DirectX 3D 图形 API 上。 为了描述 OpenCL 设计的核心,Khronos Group OpenCL 异构并行计算架构划分为平 台模型(platform model )、存储器模型(memory model )、执行模型(execution model )和编程 模型(programming model ),这些模型既相互独立,又相互联系,组成了 OpenCL 的有机整 体。接下来的章节,将逐步讲解这 4 个模型。由于编程模型和程序设计的细节密切相关,因 Chapter 2

Upload: others

Post on 24-Oct-2020

0 views

Category:

Documents


0 download

TRANSCRIPT

  • 第 2 章

    OpenCL 的基本介绍

    本章开始,将以 OpenCL 的历史背景作为出发点,逐步介绍 OpenCL 有关知识。本章将介绍 OpenCL 历史、OpenCL 平台模型、执行模型、存储器模型、OpenCL 与 OpenGL 的关联、OpenCL 与 CUDA 的区别与联系。通过以上介绍,使得读者对于 OpenCL 有一个整体认识。

    2.1 什么是 OpenCL

    2008 年,苹果公司向 Khronos Group 提交了一份关于跨平台计算框架的草案,该草案由苹果公司开发,并与 AMD、IBM、Intel 和 NVIDIA 公司合作逐步完善。这个跨平台计算框架就是 OpenCL(Open Computing Language,开放计算语言)。2008 年 12 月 8 日,OpenCL 1.0技术规范发布。2010 年 6 月 14 日,OpenCL 1.1 发布。2011 年 11 月 19 日,OpenCL 1.2 发布。2013 年 11 月 19 日,OpenCL 2.0 发布。

    OpenCL 是一个为异构并行计算平台编写程序的工业标准,此异构计算平台可映射到CPU、GPU、DSP 和 FPGA 等计算设备。OpenCL 提供了底层硬件结构的抽象模型,旨在提供一个通用的开放 API,既减轻开发人员的编程难度,又让开发人员能够写出高效可移植代码。例如,使用 OpenCL,开发人员可以编写在 GPU 上运行的通用计算程序,而无须将其算法映射到 OpenGL 或 DirectX 的 3D 图形 API 上。

    为了描述 OpenCL 设计的核心,Khronos Group 将 OpenCL 异构并行计算架构划分为平台模型(platform model)、存储器模型(memory model)、执行模型(execution model)和编程模型(programming model),这些模型既相互独立,又相互联系,组成了 OpenCL 的有机整体。接下来的章节,将逐步讲解这 4 个模型。由于编程模型和程序设计的细节密切相关,因

    Chapter 2

  • 第 2 章 OpenCL 的基本介绍   15

    此放在第 3 章详细说明。

    2.2 OpenCL 平台模型

    平台模型是关于 OpenCL 如何看待硬件的一个抽象描述。OpenCL 平台模型由主机及其相连的一个或多个 OpenCL 设备组成,如图 2-1 所示。通常主机是指包含 X86 或 ARM 处理器的计算平台。OpenCL 设备可以是 CPU(也可以将主机端的 CPU 作为 OpenCL 设备)、GPU、DSP、FPGA 或硬件商提供、OpenCL 开发商支持的任何其他处理器。每个 OpenCL设备有一个或者多个计算单元(Compute Units,CU),而每个计算单元又由一个或多个处理单元(Processing Elements,PE)组成,处理单元是设备上执行数据计算的最小单元。后面谈到 OpenCL 内存模型和工作组时,就会明白为什么会把 OpenCL 设备分为处理单元和计算 单元。

    图 2-1 OpenCL 平台模型

    OpenCL 平台模型包含一个主机及一个或多个 OpenCL 设备,每个 OpenCL 设备包含一个或多个计算单元,每个计算单元包含一个或多个处理单元。

    由于 OpenCL 的平台模型包含了至少两种处理器,如何连接这两种处理器就和在这两种处理器之间传输信息的性能密切相关,目前 OpenCL 设备主要通过 PCI-e 总线和主机相连接。

    2.3 OpenCL 执行模型

    OpenCL 程序包含主机端程序和设备端内核(kernel) 程序。主机端程序运行在主机处理器上,主机端程序以命令方式将内核程序从主机提交到 OpenCL 设备,OpenCL 设备在处理单元上执行计算。根据这两个不同执行单元定义了 OpenCL 执行模型。

    内核在 OpenCL 设备上执行,完成 OpenCL 应用的具体工作。内核通常是一些计算量大、逻辑比较简单的函数,OpenCL 设备通过内核将输入数据计算处理后输出到主机。在

  • 16   OpenCL 异构并行计算:原理、机制与优化实践

    OpenCL 中定义了三类内核: OpenCL 内核:用 OpenCL C 编程语言编写,并用 OpenCL C 编译器编译的函数。所有 OpenCL 实现都必须支持 OpenCL 内核和 OpenCL C 编程语言。原生内核:OpenCL 之外创建的函数,在 OpenCL 中可以通过一个函数指针来访问。例如,这些函数可以是主机源代码中定义的函数,或者是从一个专门库导出的函数。

    需要指出的是,执行原生内核是 OpenCL 的一个可选功能,原生内核的语义依赖于具体 OpenCL 实现。内建内核:被绑定到特定设备,并不需要源码编译成程序对象的函数。常见用法是针

    对公开固定函数硬件或固件,将它们关联到一个特定的 OpenCL 设备或自定义设备。内建内核是 OpenCL 扩展功能,内建内核语义依赖于具体 OpenCL 实现。例如,Intel针对运动搜索,提供了 block_motion_estimate_intel 内建内核,使用 clCreateProgramWithBuiltInKernels() 函数来创建程序对象,block_motion_estimate_intel 内建内核函数名“ block_motion_estimate_intel”作为参数提供给 clCreateProgramWithBuiltInKernels函数即可。

    由于 OpenCL 设备通常没有 IO 处理能力,因此 IO 操作通常由主机承担,这意味着程序开始执行时,数据通常都在主机上,故 OpenCL 设备需要从主机上获得数据,在 OpenCL 设备计算完成后,又需要将数据从 OpenCL 设备复制回主机。

    对于 OpenCL 执行模型来说,最重要的是上下文、命令队列和内核三个概念,理解了这三个概念就基本上理解了 OpenCL 的本质。

    2.3.1 上下文

    OpenCL 程序的计算工作是在 OpenCL 设备上执行的,不过主机在 OpenCL 应用中扮演着重要的角色。主机使用 OpenCL API 来创建和管理上下文,内核在此上下文中执行。上下文定义了内核执行的环境,包含了:

    设备:OpenCL 平台包含的一个或多个设备;内核对象:在 OpenCL 设备上运行的 OpenCL 内核函数;程序对象:实现整个内核程序的源代码和目标二进制码;

    存储器对象:对主机和 OpenCL 设备可见的对象,内核执行时操作这些对象的实例。OpenCL 支持的设备有 CPU、GPU、DSP、FPGA 等。例如,在同一系统中,可能有

    CPU 和 GPU,主机程序请求系统发现这些资源,然后确定使用哪些设备。设备的选择取决于具体问题和运行的内核,主机可能选择 CPU、一个 GPU、CPU+GPU、多个 GPU 等多个组合方案。一旦确定组合方案,就会在定义的上下文中包含这些 OpenCL 设备。

    上下文还包括了一个或多个程序对象。此处的“程序”非我们平时所理解的运行在某

    个系统之上的应用软件,最好把它想象成一个动态库,可以从中取出内核使用的函数。程序

    对象会在运行时由主机程序构建。为什么程序对象会在运行时才编译构建 ? 这看起来有些奇

  • 第 2 章 OpenCL 的基本介绍   17

    怪。OpenCL 是一套跨平台计算框架,对 OpenCL 开发人员来说,你可能并不知道 OpenCL应用最终会在 CPU 平台、GPU 平台还是 FPGA 平台上运行,只知道目标平台符合 OpenCL规范。对于这个问题,解决办法就是主机程序根据上下文中的设备(只有此时才确定最终平

    台,从而知道如何编译代码来创建内核代码)特性,在运行时从代码中构建程序对象。为了

    在性能和平台无关之间均衡,OpenCL 提供了两种方式从代码中构建对象,一种是从程序源代码中构建,另一种是从源代码中已经编译好的代码上构建。

    OpenCL 支持很多不同平台,不同平台有各自不同的存储器体系结构,为了处理这种情况,OpenCL 引入了存储器对象的概念。存储器对象在主机上明确定义,并在主机与 OpenCL设备间交换数据。虽然增加了 OpenCL 开发人员的负担,但这样却支持了更多的平台。

    关于上下文的具体内容将在 3.3 节中详细阐述。

    2.3.2 命令队列

    OpenCL 没 有 定 义 主 机 代 码 如 何 工 作 的 具 体 细 节, 只 是 定 义 了 它 通 过 命 令 队 列 与OpenCL 设备如何交互。命令队列由主机或运行在设备中的内核(该功能需要支持 OpenCL 2.0 的设备!)提交给命令队列。命令会在命令队列中等待,直到被调度到 OpenCL 设备上执行。OpenCL 的一个命令队列在上下文中关联到一个 OpenCL 设备。放入命令队列中的命令分为下列三种类型:

    内核入队命令:将一个内核入队关联到同一个 OpenCL 设备的命令队列中;存储器入队命令:将在主机与设备内存对象间传输数据,或者将内存对象映射到主机

    地址空间,或者从主机地址空间取消映射提交给命令队列;

    同步命令:对命令队列中需要执行的命令施加执行顺序约束,如只有某个命令执行完

    成其他命令才能开始执行。

    关于在 OpenCL 中命令队列如何工作,在 3.3 节进行详细阐述。命令可以以异步方式执行,在这种方式下主机或运行在设备中的内核向命令队列提交命

    令,然后继续工作,而不必等待命令完成。如果有必要等待一个命令完成,可以利用命令执

    行相关的同步机制进行同步。命令同步将在第 6 章进行详细阐述。一个命令队列中的命令执行时可以有以下两种模式:

    按序(in-order)执行:命令按其排入命令队列中的先后顺序执行,并按顺序完成。乱序(out-of-order)执行:命令以任意顺序执行,通过显式的同步点或显式事件依赖项来约束顺序。

    OpenCL 平台都支持按序模式,但乱序模式是可选的。需要注意的是,对于某些应用而言,算法在执行时,可能会有额外的计算,而这种额外

    的计算不能静态地确定。

    与内核有关的计算,在运行时只作为内核实例执行。常规方法上,可以通过主机程序多

    次启动内核实例来执行,但这样会显著地增加开销或加重应用程序控制流。一个方便有效的

  • 18   OpenCL 异构并行计算:原理、机制与优化实践

    方法就是从内核内部嵌套内核命令队列。对于支持 OpenCL 2.0 的设备,可以在设备上入队内核,不需要主机程序参与,这称为设备端队列,实现了嵌套并行。设备端内核命令队列与

    主机端内核命令队列类似,运行在设备上的内核(父内核)入队一个内核实例(子内核)到设

    备端命令队列。这个过程是乱序执行的。这部分内容将在 4.16 节中详细阐述。

    2.3.3 内核在 OpenCL 设备上执行

    主机发出一个命令,提交一个内核到 OpenCL 设备上执行,OpenCL 运行时将会创建一个整数索引空间。索引空间是 OpenCL 支持的一个 N 维值的网格,称为 NDRange,其中 N为 1,2 或 3。三个长度为 N 的数据确定了 NDRange 的以下特征:

    每个维度索引空间(或全局大小)的范围;

    一个偏移指数 F 表明每个维度的初始索引值(默认为 0);一个工作组(局部大小)每个维度大小。

    内核、关联内核参数的参数值和定义索引空间的参数,这三个定义了一个内核实例。对

    应这个索引空间中的各个点将分别执行内核的一个实例。我们将执行内核的各个实例称为一

    个工作项(work-item),工作项将由它在索引空间中的坐标来标识,这个坐标就是工作组的全局 ID,值从 F 到 F 加上该维度元素个数减 1。每个工作项使用内核定义的同样的指令序列,尽管指令序列是相同的,但是由于代码中通过全局 ID 选择的数据不同,因此每个工作项的行为也不同。工作项提供了对索引空间细粒度的分解。

    多个工作项组织为工作组(work-group),工作组中工作项的数量由内核入队时的参数决定。工作组横跨了整个全局索引空间,提供了对索引空间粗粒度的分解。同样,每个工作组

    被指定了一个唯一的 ID,值从 0 开始,到该维度中工作组个数减 1。对于分配到一个工作组内的每个工作项,除了有一个全局 ID,也赋予了一个局部 ID 来表示它在所属工作组中的位置,这个局部 ID 的值从 0 开始,到工作组内该维度元素个数减 1。通过结合工作组 ID 和工作组中的局部 ID 可以唯一地定义一个工作项。在 4.5 节中,将会详细讲解确定 ID 的几个函数。

    例如,定义一个 2 维索引空间。索引空间的工作项大小为(AX,AY),每个工作组大小为(BX,BY),全局偏移 ID(FX,FY)。对于此种情况,索引空间的工作项总个数为 AX*AY,每

    个工作组中工作项个数为 BX*BY,则工作组的大小 (CX,CY) 的值为:CX=ceil(AX/BX)CY=ceil(AY/BY)

    工作项在工作组内的局部 ID 为(lx,ly),大小为(0,0)~(BX-1,BY-1)。工作组的 ID为(Wx,Wy),大小为(0,0)~(CX-1,CY-1)。对于工作项全局 ID(gx,gy) 可以结合全局ID(lx,ly) 和工作组 ID(Wx,Wy) 来计算:

    gx=Wx*BX+lx+FXgy=Wy*BY+ly+FY

  • 第 2 章 OpenCL 的基本介绍   19

    图 2-2 提供了一个具体的例子,其中各个小方块分别是一个工作项。对于这个例子,每个维度中使用默认偏移是 0。

    BX 4

    AX 12CX 3

    CY

    15

    BY

    4

    图 2-2 2 维 NDRange 示例

    图 2-2 中阴影方块的全局 ID 为 (gx,gy)=(6,5),工作组 ID(Wx,Wy)=(1,1),工作项局部ID(lx,ly)=(2,1)。

    2.4 OpenCL 存储器模型

    在 OpenCL 执行模型的上下文中,我们简要提及 OpenCL 存储器对象,并没有详细讲述OpenCL 存储器对象的细节,也没有提及 OpenCL 存储器对象的不同类别等问题。这些问题在本节中都能够得到解决。我们将从存储器区域、存储器对象、共享虚拟存储器三方面分析

    OpenCL 存储器模型。而关于存储器一致性模型,将在 5.6 节中进行详细介绍。

    2.4.1 存储器区域

    OpenCL 异构平台由主机端和设备端构成,存储器区域包含主机与设备的内存。在OpenCL 中具体定义了下面几种不同的存储器区域:

    主机内存(host memory):主机直接可用的内存,OpenCL 并未定义主机内存的具体行为。通过 OpenCL API 或者共享虚拟存储器接口,实现存储器对象在主机与设备间的传输。

    全局存储器(global memory):这个存储器区域允许上下文中任何设备中所有工作组的所有工作项的读写,工作项可以读写存储器对象中的任意元素。全局存储器的读写

    可能会被缓存,这取决于设备能力。

    常量存储器(constant memory):全局存储器中的一块区域,在内核实例执行期间其保存的数据保持不变。对工作项而言这个存储器对象是只读的,主机负责对该存储器

  • 20   OpenCL 异构并行计算:原理、机制与优化实践

    对象的分配和初始化。

    局部存储器(local memory):这个存储器区域对工作组是局部可见的,它可以用来分配由该工作组中所有工作项共享的变量。

    私有存储器(private memory):这个存储器区域是一个工作项的私有区域。一个工作项私有存储器中定义的变量对其他工作项是不可见的。

    这些存储器区域以及它们与平台和执行模型的关系如图 2-3 所示。一般对于存储器与主机端共享的 OpenCL 设备而言,一个 OpenCL 设备关联局部存储器和私有存储器;全局存储器和常量存储器由在上下文内的所有设备间共享,OpenCL 设备可能包含缓存来支持对这两个存储器的高效访问。

    OpenCL

    OpenCL

    OpenCL

    1

    1

    1

    1

    1 1

    1

    1 M 1 M

    M 1 M

    1 1

    图 2-3 OpenCL 内存模型

    全局存储器和常量存储器可以在一个上下文内的一个或多个设备间共享,一个 OpenCL设备关联局部存储器和私有存储器。

  • 第 2 章 OpenCL 的基本介绍   21

    2.4.2 存储器对象

    全局存储器中的数据内容通过存储器对象来表示。一个存储器对象就是对全局存储器区

    域的一个引用。在 OpenCL 中,存储器对象分为三种不同类型:缓冲(buffer): 内核可用的一个连续的存储器区域,编程人员可以将内建数据类型、矢量类型数据或用户自定义的数据结构(当然要符合 OpenCL 编程规范)映射到这个缓冲区,内核通过指针来访问缓冲区。

    图像(image): 图像对象用于存储基于标准格式的图像。图像对象是一个不透明的数据结构,使用 OpenCL API 函数来管理。通常不允许 OpenCL 内核对单个图像同时进行读和写。然而在 OpenCL 2.0 中,提供了同步和栅栏操作来放宽这个限制。在第 4章中,我们对此会有详细阐述。

    管道(pipe): 管道存储器是数据项有序的队列。管道有两个端点:一个是写端点,用于插入数据项;另一个是读端点,数据项从读端点被移除。同一时刻,仅有一个内核

    实例可向一个管道写入数据,同时仅有一个内核实例可从一个管道读出数据。

    大多数情况下,主机和 OpenCL 设备存储器模型是独立的。一旦分配存储器对象,对设备上的内核是有效的。不过在某些情况下,它们是需要交互的。在主机和设备间有三种交互

    方式:读 / 写 / 填充、映射和解映射以及拷贝。要显式地读 / 写 / 填充数据,主机将命令入队,在主机和全局存储器之间传输数据。实

    现主机与 OpenCL 存储器对象间映射和解映射的方法允许主机将一个存储器区域映射到主机可以访问的地址空间。在主机程序安全操作存储器对象之前,主机将这个存储器对象入队到

    一个映射命令中;主机完成了对这个存储器区域的操作,则入队一个解映射命令,从而使得

    内核可以安全地读写缓冲。

    拷贝命令是将存储器对象在两个缓冲间拷贝,这两个缓冲可驻留在主机或设备上。

    上述三个操作命令可以是阻塞或非阻塞操作。关于这部分内容,将在第 5 章详细阐述。

    2.4.3 共享虚拟存储器

    通过映射,可以将设备全局存储器区域映射到主机可以访问的地址空间。而除了这种方

    式,在 OpenCL 2.0 中,OpenCL 通过共享虚拟存储器(Shared Virtual Memory,SVM)机制扩展了全局存储器区域到主机内存区域的方式。在 OpenCL 2.0 中定义了三种 SVM 类型:

    粗粒度 SVM:共享发生在 OpenCL 缓冲存储器对象区域的粒度;细粒度 SVM :共享发生在 OpenCL 缓冲存储器对象里独立地以字节加载 / 存储的 粒度;

    细粒度系统 SVM:共享发生在主机内存内任何地方独立地以字节加载 / 存储的粒度。粗粒度内存 SVM 是 OpenCL 的核心规范,而对于后两种细粒度实现是可选。从概念上来说,读者可能不太明白三种 SVM 到底实现什么功能,这没有关系。只要记

  • 22   OpenCL 异构并行计算:原理、机制与优化实践

    住有三种 SVM 类型,在第 5 章中会通过具体的例子来讲解 SVM 的作用和用法。

    2.5 OpenCL 与 OpenGL

    如图 2-4 所示,从 GPU 诞生之日起,GPU 的设计逻辑与 CPU 的设计逻辑相差很多。GPU 从诞生之日起,它的定位是 3D 图形渲染设备。在设计 GPU 时从其功能出发,把更多的晶体管用于数据处理。这使得 GPU 相比 CPU 有更强的单精度浮点运算能力。人们为了充分利用 GPU 的性能,使用了很多方法。这其中不得不提 OpenGL(Open Graphics Library,开放图形库)。

    CPU GPU

    Control

    DRAMDRAM

    Cache

    ALU ALU

    ALU ALU

    图 2-4 CPU 与 GPU 架构区别

    OpenGL 定义了一个跨编程语言、跨平台的应用程序接口规范,它用于生成二维、三维图像。这个接口由近 350 个不同的函数调用组成,用来从简单的图像比特绘制到复杂的三维景象。

    当我们把绘制的图像传递给 OpenGL 后,OpenGL 还要做很多才能完成 3D 空间到屏幕的投影。这一系列的过程称为 OpenGL 渲染流水线。一般的渲染流水线过程如图 2-5 所示。在顶点装配和片段操作中,使用 GPU 中的着色器(英文为 shader,实际上就是 GPU 的处理器)来进行相应操作。进行几何处理的处理器叫顶点着色器,它负责对顶点进行坐标转换、

    投影变换等;进行片段颜色处理的叫片段着色器。

    随着 GPU 技术的发展,GPU 的图形渲染流水线从固定功能流水线发展到可编程渲染流水线。可编程渲染流水线含有若干可编程着色器(比如,OpenGL 2.0 起支持顶点和片段着色器;OpenGL 3.2 起支持了几何着色器;OpenGL 4.0 起支持了细分曲面相关的着色器;OpenGL 4.3 又引入了计算着色器),这些可编程着色器处理单元可实现用户自定义算法的功能。OpenGL 中的 GLSL(OpenGL Shading Language,OpenGL 着色器语言)就是一种着色器语言。利用 GLSL 可以实现上述 GPGPU(General Purpose GPU,通用计算 GPU)的各种着色器程序。但为了掌握 GLSL,人们需要去学习太多的计算机图像学知识,这使得在开始时的学习曲线比较陡峭。

  • 第 2 章 OpenCL 的基本介绍   23

    图 2-5 OpenGL 图像流水线

    从 2007 年以后,基于 CUDA 和 OpenCL 这些被设计成具有近似于高阶语言的语法特性的新 GPGPU 语言,降低了人们使用 GPGPU 的难度,平缓了开始时的学习曲线。使得在GPGPU 领域,OpenGL 中的 GLSL 逐渐退出了人们的视线。OpenCL 与 OpenGL 一样,都是基于硬件 API 的编程。

    2.6 OpenCL 与 CUDA2007 年,NVIDIA 向市场推出 GPGPU 整套解决方案——CUDA。CUDA 是集硬件与软

    件于一体的集成技术。CUDA C 编程是在 C99 的扩展上进行的,这大大降低了开发 GPGPU程序的难度,使得开发人员可以方便地开发 GPGPU 程序。对于 CUDA C 的代码,只能运行在 NVIDIA G80 架构以后的 GPU 上。

    OpenCL 是 2008 年才发布的基于硬件 API 编程的工业标准。OpenCL 相比 CUDA,支持的平台更多,除了 GPU 还有 CPU、DSP、FPGA 等设备。截至本书撰写之时,OpenCL 已发布 4 个正式标准,最新版本为 OpenCL 2.1,而 NVIDIA 的 GPU 只支持到 OpenCL 1.2,对于开发人员来说有点遗憾。OpenCL 编程模型设计时,借鉴和参考了 CUDA 编程模型。从编程语言来看,OpenCL 和 CUDA 语法基本类似,所以对开发人员而言,如果熟悉 OpenCL 或CUDA 中的其中一种,要熟悉另外一种编程语言是很容易的,这也使 CUDA 与 OpenCL 程序之间相互移植会比较容易。不过由于 OpenCL 支持平台更多,所以在主机端 OpenCL 处理相比 CUDA 显得有点烦琐。

    本书针对 OpenCL 编程,对 CUDA 以及其他异构并行编程方式将做简要概述,不详细展开。对 CUDA 编程有兴趣的读者,可以从 NVIDIA 官网(http://www.nvidia.com/content/cuda/cuda-downloads.html)下载 CUDA 有关文档和开发包。

    2.7 本章小结本章介绍了 OpenCL 的基本概念:平台模型、执行模型、存储器模型。本章并没有介绍

  • 24   OpenCL 异构并行计算:原理、机制与优化实践

    编程模型。

    在平台模型中,OpenCL 将计算平台抽象成主机加 OpenCL 设备的模式,主机负责将命令入队交给 OpenCL 设备计算,而 OpenCL 设备负责计算内核。

    在执行模型中,上下文负责管理 OpenCL 执行所需要的资源,包括设备、命令队列、存储器对象、程序对象等。一个命令队列对象关联到一个 OpenCL 设备,主机通过命令队列向OpenCL 设备提交操作。

    在存储器模型中,全局存储器、常量存储器对所有内核实例都可见,而局部存储器只对

    一个工作组中的所有工作项可见,经常用于工作组内数据共享,私有存储器只对某个工作项

    可见。