OpenCL程序的计算工作是在OpenCL设备上执行的,不过主机在OpenCL应用中扮演着重要的角色。主机使用OpenCL API来创建和管理上下文,内核在此上下文中执行。上下文定义了内核执行的环境,包含了:
- 设备:OpenCL平台包含的一个或多个设备;
-
内核对象:在OpenCL设备上运行的OpenCL内核函数;
-
程序对象:实现整个内核程序的源代码和目标二进制码;
-
存储器对象:对主机和OpenCL设备可见的对象,内核执行时操作这些对象的实例。
OpenCL支持的设备有CPU、GPU、DSP、FPGA等。例如,在同一系统中,可能有CPU和GPU,主机程序请求系统发现这些资源,然后确定使用哪些设备。设备的选择取决于具体问题和运行的内核,主机可能选择CPU、一个GPU、CPU+GPU、多个GPU等多个组合方案。一旦确定组合方案,就会在定义的上下文中包含这些OpenCL设备。
上下文还包括了一个或多个程序对象。此处的“程序”非我们平时所理解的运行在某个系统之上的应用软件,最好把它想象成一个动态库,可以从中取出内核使用的函数。程序对象会在运行时由主机程序构建。为什么程序对象会在运行时才编译构建?这看起来有些奇怪。
OpenCL是一套跨平台计算框架,对OpenCL开发人员来说,你可能并不知道OpenCL应用最终会在CPU平台、GPU平台还是FPGA平台上运行,只知道目标平台符合OpenCL规范。对于这个问题,解决办法就是主机程序根据上下文中的设备(只有此时才确定最终平台,从而知道如何编译代码来创建内核代码)特性,在运行时从代码中构建程序对象。为了在性能和平台无关之间均衡,OpenCL提供了两种方式从代码中构建对象,一种是从程序源代码中构建,另一种是从源代码中已经编译好的代码上构建。
OpenCL支持很多不同平台,不同平台有各自不同的存储器体系结构,为了处理这种情况,OpenCL引入了存储器对象的概念。存储器对象在主机上明确定义,并在主机与OpenCL设备间交换数据。虽然增加了OpenCL开发人员的负担,但这样却支持了更多的平台。