OpenCL程序的第一步就是选择OpenCL平台。OpenCL平台指的是OpenCL设备和OpenCL框架的组合,不同的OpenCL厂商属于不同的OpenCL平台。一个异构计算机上可以同时存在多个OpenCL平台。
例如,在一个系统中,可能存在NVIDIA GPU、AMD GPU与Intel CPU,多个OpenCL实现并存,对于这种平台有3个不同平台。在OpenCL程序开发中,我们需要显式地指定选择用哪个平台。
对于同一平台上可能关联有不同的设备,如在Qualcomm平台,CPU和Adreno GPU都支持OpenCL,都可以作为OpenCL设备,在这种一个平台中含有多个可用计算设备的环境下,编程人员就需要人为选择使用哪种OpenCL设备。
OpenCL平台
clGetPlatformIDs
OpenCL中,cl_platform_id结构表示了一个不同的OpenCL实现(称为平台),可以使用如下函数查询来获得系统平台列表:
cl_int clGetPlatformIDs(cl_uint num_entries ,
cl_platform_id *platforms ,
cl_uint *num_platforms )
在OpenCL程序中,上述函数可以调用两次:
- 第一次调用,platforms设置为NULL,调用该函数,num_platforms中获得系统中可用的OpenCL平台数量;
- 第二次调用,根据第一次调用得到平台数量分配平台空间,调用该函数来初始化可用平台。
下面的代码清单用来说明以上操作:
cl_int err;
cl_uint num_platform;
cl_platform_id *platform;
//获得平台数量
err = clGetPlatformIDs(0, NULL, &num_platform);
//分配平台空间
platform = (cl_platform_id *)malloc(sizeof(cl_platform_id) *
num_platform);
//初始化可用平台
err = clGetPlatformIDs(num_platform, platform, NULL);
上述代码查询了系统中所有OpenCL平台,并初始化了查询到的所有平台。回过头看OpenCL 第一个程序中的例子,在这个例子中clGetPaltformIDS只调用了一次,这是为什么呢?这是因为只初始化了第一个可用的OpenCL平台。
需要指出的是,OpenCL API函数执行完成后都会有相应的返回状态,类型为cl_int,如上述例子中定义的err变量,成功执行则返回状态是CL_SUCCESS,失败则返回相应的错误状态。这部分内容将在本章最后讲解,开发人员可以通过返回状态检查函数是否成功执行。
clGetPaltformIDs可以获得平台个数信息,但是却无法知道平台属性信息,如平台名称、平台支持的OpenCL版本、平台供应商等信息。如果需要查询这些信息怎么办呢?OpenCL已经提供这样的函数可供开发人员使用。
clGetPlatformInfo
给定一个平台,使用如下函数可以获得平台的各个属性信息:
cl_int clGetPlatformInfo(cl_platform_id platform ,
cl_platform_info param_name ,
size_t param_value_size ,
void *param_value ,
size_t *param_value_size_ret)
这个函数返回给定平台的属性信息。
第一个参数platform指定查询的平台。
第二个参数param_name为查询平台的属性信息,param_name的取值如下表所示。
最后一个参数param_value_size_ret返回属性信息实际的长度。
第四个参数param_value为指向保存平台属性信息的指针。
第三个参数param_value_size指定param_value参数指向的内存空间大小,这个值必须大于等于第四个参数的返回值。
- FULL_PROFILE:OpenCL实现支持OpenCL规范的所有功能;
- EMBEDDED_PROFILE:OpenCL实现支持OpenCL嵌入式简档,是OpenCL规范的一个子集。
下面的代码来获得指定平台的5个属性信息。
size_t size;
err = clGetPlatformInfo(platform, CL_PLATFORM_NAME, 0, NULL,
&size);
char *PName = (char *)malloc(size);
err = clGetPlatformInfo(platform, CL_PLATFORM_NAME, size, PName,
NULL);
printf("CL_PLATFORM_NAME: % s\n", PName);
err = clGetPlatformInfo(platform, CL_PLATFORM_VENDOR, 0, NULL,
&size);
char *PVendor = (char *)malloc(size);
err = clGetPlatformInfo(platform, CL_PLATFORM_VENDOR, size,
PVendor, NULL);
printf("CL_PLATFORM_VENDOR: % s\n", PVendor);
err = clGetPlatformInfo(platform, CL_PLATFORM_VERSION, 0, NULL,
&size);
char *PVersion = (char *)malloc(size);
err = clGetPlatformInfo(platform, CL_PLATFORM_VERSION, size,
PVersion, NULL);
printf("CL_PLATFORM_VERSION: % s\n", PVersion);
err = clGetPlatformInfo(platform, CL_PLATFORM_PROFILE, 0, NULL,
&size);
char *PProfile = (char *)malloc(size);
err = clGetPlatformInfo(platform, CL_PLATFORM_PROFILE, size,
PProfile, NULL);
printf("CL_PLATFORM_PROFILE: % s\n", PProfile);
err = clGetPlatformInfo(platform, CL_PLATFORM_EXTENSIONS, 0,
NULL, &size);
char *PExten = (char *)malloc(size);
err = clGetPlatformInfo(platform, CL_PLATFORM_EXTENSIONS, size,
PExten, NULL);
printf("CL_PLATFORM_EXTENSIONS: % s\n", PExten);
针对NVIDIA GPU,上述代码输出为:
- CL_PLATFORM_NAME:NVIDIA CUDA
- CL_PLATFORM_VENDOR:NVIDIA Corporation
- CL_PLATFORM_VERSION:OpenCL 1.1 CUDA 6.0.1
- CL_PLATFORM_PROFILE:FULL_PROFILE
- CL_PLATFORM_EXTENSIONS:cl_khr_byte_addressable_store cl_khr_icd cl_khr_gl_sharing cl_nv_d3d9_sharing cl_nv_d3d10_sharing cl_khr_d3d10_sharing cl_nv_d3d11_sharing cl_nv_compiler_options cl_nv_device_attribute_query cl_nv_pragma_unroll
综合clGetPlatformIDs和clGetPlatformInfo两个函数。
下面的代码清单演示了列举系统可用平台,查询输出每个可用平台的属性信息。
#include〈CL/cl.h>
#include〈stdio.h>
#include〈string.h>
#include〈malloc.h>
int main()
{
cl_platform_id *platform;
cl_uint num_platform;
cl_int err;
err = clGetPlatformIDs(0, NULL, &num_platform);
platform = (cl_platform_id *)malloc(sizeof(cl_platform_id) *
num_platform);
err = clGetPlatformIDs(num_platform, platform, NULL);
for(int i = 0; i 〈 num_platform; i++)
{
size_t size;
err = clGetPlatformInfo(platform[i], CL_PLATFORM_NAME, 0, NULL, &size);
char *PName = (char *)malloc(size);
err = clGetPlatformInfo(platform[i], CL_PLATFORM_NAME, size,
PName, NULL);
printf("\nCL_PLATFORM_NAME: % s\n", PName);
err = clGetPlatformInfo(platform[i], CL_PLATFORM_VENDOR,
0, NULL, &size);
char *PVendor = (char *)malloc(size);
err = clGetPlatformInfo(platform[i], CL_PLATFORM_VENDOR,
size, PVendor, NULL);
printf("CL_PLATFORM_VENDOR: % s\n", PVendor);
err = clGetPlatformInfo(platform[i], CL_PLATFORM_VERSION,
0, NULL, &size);
char *PVersion = (char *)malloc(size);
err = clGetPlatformInfo(platform[i], CL_PLATFORM_VERSION,
size, PVersion, NULL);
printf("CL_PLATFORM_VERSION: % s\n", PVersion);
err = clGetPlatformInfo(platform[i], CL_PLATFORM_PROFILE, 0,
NULL, &size);
char *PProfile = (char *)malloc(size);
err = clGetPlatformInfo(platform[i], CL_PLATFORM_PROFILE,
size, PProfile, NULL);
printf("CL_PLATFORM_PROFILE: % s\n", PProfile);
err = clGetPlatformInfo(platform[i], CL_PLATFORM_EXTENSIONS,
0, NULL, &size);
char *PExten = (char *)malloc(size);
err = clGetPlatformInfo(platform[i], CL_PLATFORM_EXTENSIONS,
size, PExten, NULL);
printf("CL_PLATFORM_EXTENSIONS: % s\n", PExten);
free(PName);
free(PVendor);
free(PVersion);
free(PProfile);
free(PExten);
}
}