每个平台可能关联不同的设备,在把内核程序送到OpenCL设备上执行前,编程人员需要指定执行该内核代码的计算设备。
clGetDeviceIDs
OpenCL中设备对象的类型为cl_device_id,我们可以通过以下函数来查询支持OpenCL设备列表:
cl_int clGetDeviceIDs(cl_platform_id platform ,
cl_device_type device_type ,
cl_uint num_entries ,
cl_device_id *devices ,
cl_uint *num_devices )
该函数与clGetPlatformIDs函数类似,第一次调用时,devices参数设置为NULL,num_devices返回指定平台中的设备数;
第二次调用时,根据第一次调用得到设备数量分配设备空间,调用该函数来初始化可用设备。
需要注意的是,如果devices不为NULL,num_entries的值必须大于0,num_entries用于指定devices所指向的设备对象列表中最多可存放多少个设备对象,这样此函数所输出的设备对象个数不会超过num_entries的值。而num_devices则输出实际给出的设备对象的个数。
通过下面的代码清单来说明以上操作:
cl_uint num_platform;
cl_uint num_device;
cl_platform_id *platform;
cl_device_id *devices;
cl_int err;
err = clGetPlatformIDs(0, 0, &num_platform);
platform = (cl_platform_id *)malloc(sizeof(cl_platform_id) *
num_platform);
err = clGetPlatformIDs(num_platform, platform, NULL);
//获得第一个平台上的设备数量
err = clGetDeviceIDs(platform[0], CL_DEVICE_TYPE_GPU, 0, NULL,
&num_device);
devices = (cl_device_id *)malloc(sizeof(cl_device_id) *
num_device);
//初始化可用的设备
err = clGetDeviceIDs(platform[0], CL_DEVICE_TYPE_GPU, num_device,
devices, NULL);
在上面的例子中,我们查询第一个平台上GPU类型的可用OpenCL设备数量,并初始化这些设备。
对于上述例子,查询的是GPU类型的OpenCL设备。对于函数中的device_type参数,可用类型如下表所示:
clGetDeviceInfo
给定一个OpenCL设备后,使用如下函数可以获得设备的各个属性信息:
cl_int clGetDeviceInfo(cl_device_id device ,
cl_device_info param_name ,
size_t param_value_size ,
void *param_value ,
size_t *param_value_size_ret )
这个函数返回给定设备的属性信息。
第一个参数device指定查询的设备。
第二个参数param_name为查询平台的属性信息,param_name的取值如下表所示。
最后一个参数param_value_size_ret返回属性信息实际的长度。
第四个参数param_value为指向保存平台属性信息的指针。
第三个参数param_value_size指定param_value参数指向的内存空间大小,这个值必须大于第四个参数的返回值。
下面代码清单展示了如何使用clGetDeviceInfo()来查询指定平台上GPU设备的属性信息。
#include 〈stdio.h>
#include 〈stdlib.h>
#ifdef _APPLE_
#include 〈OpenCL/cl.h>
#else
#include 〈CL/cl.h>
#endif
void checkErr(cl_int err, int num)
{
if(CL_SUCCESS != err)
{
printf("OpenCL error(%d) at %d\n", err, num - 1);
}
}
int main(int argc, char **argv)
{
cl_device_id *device;
cl_platform_id platform;
cl_int err;
cl_uint NumDevice;
//选择第一个平台
err = clGetPlatformIDs(1, &platform, NULL);
checkErr(err, _LINE_);
err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU,
0, NULL, &NumDevice);
checkErr(err, _LINE_);
device = (cl_device_id *)malloc(sizeof(cl_device_id) *
NumDevice);
//选择GPU设备
err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU,
NumDevice, device, NULL);
checkErr(err, _LINE_);
for(int i = 0; i 〈 NumDevice; i++)
{
//查询设备名称
char buffer[100];
err = clGetDeviceInfo(device[i], CL_DEVICE_NAME,
100, buffer, NULL);
checkErr(err, _LINE_);
printf("Device Name:%s\n", buffer);
//查询设备计算单元最大数目
cl_uint UnitNum;
err = clGetDeviceInfo(device[i],
CL_DEVICE_MAX_COMPUTE_UNITS,
sizeof(cl_uint), &UnitNum, NULL);
checkErr(err, _LINE_);
printf("Compute Units Number: %d\n", UnitNum);
//查询设备核心频率
cl_uint frequency;
err = clGetDeviceInfo(device[i],
CL_DEVICE_MAX_CLOCK_FREQUENCY,
sizeof(cl_uint), &frequency, NULL);
checkErr(err, _LINE_);
printf("Device Frequency: %d(MHz)\n", frequency);
//查询设备全局内存大小
cl_ulong GlobalSize;
err = clGetDeviceInfo(device[i], CL_DEVICE_GLOBAL_MEM_SIZE,
sizeof(cl_ulong), &GlobalSize, NULL);
checkErr(err, _LINE_);
printf("Device Global Size: %0.0f(MB)\n",
(float)GlobalSize / 1024 / 1024);
//查询设备全局内存缓存行
cl_uint GlobalCacheLine;
err = clGetDeviceInfo(device[i],
CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE,
sizeof(cl_uint), &GlobalCacheLine,
NULL);
checkErr(err, _LINE_);
printf("Device Global CacheLine: %d(Byte)\n",
GlobalCacheLine);
//查询设备支持的OpenCL版本
char DeviceVersion[100];
err = clGetDeviceInfo(device[i], CL_DEVICE_VERSION,
100, DeviceVersion, NULL);
checkErr(err, _LINE_);
printf("Device Version:%s\n", DeviceVersion);
//查询设备拓展名
char *DeviceExtensions;
cl_uint ExtenNum;
err = clGetDeviceInfo(device[i], CL_DEVICE_EXTENSIONS,
0, NULL, &ExtenNum);
checkErr(err, _LINE_);
DeviceExtensions = (char *)malloc(ExtenNum);
err = clGetDeviceInfo(device[i], CL_DEVICE_EXTENSIONS,
ExtenNum, DeviceExtensions, NULL);
checkErr(err, _LINE_);
printf("Device Extensions:%s\n", DeviceExtensions);
free(DeviceExtensions);
}
free(device);
return 0;
}
在AMD Radeon R9 285设备上,上述代码输出结果如下:
Device Name:Tonga
Compute Units Number: 28
Device Frequency: 965(MHz)
Device Global Size: 2048(MB)
Device Global CacheLine: 64(Byte)
Device Version:OpenCL 1.2 AMD-APP (1642.5)
Device Extensions:cl_khr_fp64 cl_amd_fp64 cl_khr_global_int32_base_atomics cl_
khr_global_int32_extended_atomics cl_khr_local_int32_base_atomics cl_khr_local_
int32_extended_atomics cl_khr_int64_base_atomics cl_khr_int64_extended_atomics cl_
khr_3d_image_writes cl_khr_byte_addressable_store cl_khr_gl_sharing cl_ext_atomic_
counters_32 cl_amd_device_attribute_query cl_amd_vec3 cl_amd_printf cl_amd_media_
ops cl_amd_media_ops2 cl_amd_popcnt cl_khr_d3d10_sharing cl_khr_d3d11_sharing cl_
khr_dx9_media_sharing cl_khr_image2d_from_buffer cl_khr_spir cl_khr_gl_event
需要注意的是:查询设备不同的属性信息对应的返回值类型不同。初学者可能对此不太注意,接收返回值的变量与所需类型不一致,造成查询属性信息输出结果不正确。