OpenCL异构并行计算编程笔记(1):平台、设备与上下文

网友投稿 924 2022-05-30

OpenCL(全称Open Computing Language,开放运算语言)是第一个面向异构系统通用目的并行编程的开放式、免费标准,也是一个统一的编程环境,便于软件开发人员为高性能计算服务器、桌面计算系统、手持设备编写高效轻便的代码,而且广泛适用于多核心处理器(CPU)、图形处理器(GPU)、Cell类型架构以及数字信号处理器(DSP)等其他并行处理器[1]。

需要注意的是,不同于其他第三方库,OpenCL只提供一个开放API的规范,仅仅定义了接口,但并没有进行实现,各个接口的实现由处理器生产厂商自己完成。所以,虽然包括Intel、AMD以及Nvidia在内的厂商都对OpenCL提供了支持,但其实现的方法却各有不同,使得在不用品牌的处理器上使用OpenCL时需要使用特定的SDK,同时在特性上会略微有所不同(但基本不会产生太大影响)。接下来就简单介绍一下基于OpenCL的异构编程方法,在进行OpenCL编程之前,最好先了解OpenCL的架构模型,具体资料可参考:从零开始学习OpenCL开发架构,在此不予赘述。(实例环境:Windows10、Visual Studio 2015、OpenCL 1.1、Intel Core i5 3437U、Nvidia GeForce 840M)

一、获取平台(Platform):

OpenCL异构并行计算编程笔记(1):平台、设备与上下文

不同厂商对于OpenCL具体的实现不同,某个厂商对于OpenCL的实现就形成了一个平台。不同厂商的处理器只能在不同的平台上运行,换句话说一个平台上只用运行实现该平台厂商的处理器。例如Intel、AMD和Nvidia均对OpenCL进行了自己的实现,在Intel的平台上可以同时使用Intel的CPU和GPU,但无法使用AMD和Nvidia的处理器;同样在AMD的平台上无法使用Intel和Nvidia二者的设备。在进行OpenCL编程时需要首先确定所选择的平台。

查询平台ID可以使用:

clGetPlatFormIDs(cl_uint num_entries, cl_platform_id*platforms, cl_uint *num_platforms)

该函数的第一个参数是platforms可以保存的平台ID的数目;

第二个参数是一个指针,用来保存找到的平台;

第三个参数保存查询到的平台的个数。

当返回值为0时,标志程序执行完成;非0时,为错误码。

通常可以使用两次该函数来获取所有的平台ID:

[cpp] view plain copy

cl_int ret;               //用于保存函数返回值

cl_uint num_platform;     //用于保存平台个数

cl_platform_id *platform  //用于保存平台ID

//

//获取函数个数

ret = clGetPlatformIDs(NULL, NULL, &num_platform);

//

//为platform分配空间

platform = new cl_platform_id[num_platform];

//获取所有平台

ret = clGetPlatformIDs(num_platform, platform, NULL);

查询平台信息可以使用:

cl_int clGetDeviceIDs(cl_platform_id platform,

cl_platform_info param_name,

size_t param_value_size,

void *param_value,

size_t *param_value_size_ret)

该函数的第一个参数是之前获取的平台ID;

第二个参数是一个枚举体,用来标识所要查询的信息;

第三个参数是一个指针,用来存放查询到的信息;

第四个参数表示指针所指内存的大小;

第五个参数用来存放查询到的信息数据的大小。

同样,通常使用两次该函数来获取平台信息:

[cpp] view plain copy

cl_int ret;                   //用于保存函数返回值

size_t ext_size;       //用于保存平台信息大小

char *ext_data;      //用于保存平台信息

cl_platform_info platform_info = CL_PLATFORM_NAME;   //设置所要查询的信息

//

//获取平台信息大小

ret = clGetPlatformInfo(platform[order], platform_info, 0, NULL, &ext_size);

//

//为ext_data分配空间

ext_data = new char[ext_size];

//获取平台信息

ret = clGetPlatformInfo(platform[order], platform_info, ext_size, ext_data, NULL);

//打印平台信息

std::cout << ext_data << std::endl;

二、获取设备(Device):

设备是运行在平台上的可进行异构计算的单元,通常对应于同一平台的处理器。获取设备ID和信息的方法与函数同获取平台类似:

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一致。

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)

第一个参数标识所要查询设备,其余参数的含义与clGetPlatformInfo一致。

设备查询函数的使用和平台一样,一般通过两次调用来获得设备的个数和相应的信息,具体可以参考获取平台相关函数的使用方法。

三、建立上下文(Context):

上下文(Context)是将同一平台上不同架构的设备连接在一起的纽带,在同一个上下文的设备才可以进行通信、读写、共享内存等操作。程序运行时,使用上下文来管理命令队列、内存、内核等对象。建立上下文可以使用:

cl_context clCreateContext(cl_context_properties *properties,

cl_uint num_devices,

const cl_device_id *devices,

void *pfn_notify (const char *errinfo, const void *private_info, size_t cb, void *user_data),

void *user_data,

cl_int *errcode_ret)

该函数第一个参数指向一个列表,用来表明建立的上下文的属性及相对应的值;

第二个参数表明上下文中设备的个数;

第三个参数是指向设备ID的指针,用来标明建立上下文的设备;

第四个参数是一个回调函数,报告建立上下文中出现的错误;

第五个参数用来返回错误码,当上下文建立成功时返回0,即CL_SUCCESS。

如果建立上下文完成,该函数返回一个非0的上下文。

实际使用时根据之前获得的设备ID来建立上下文:

[cpp] view plain copy

cl_int ret;                   //用于保存函数返回值

cl_context_properties context_props[]

= { CL_CONTEXT_PLATFORM, (cl_context_properties)platform[1], 0 };;   //设置上下文属性

//

//建立上下文

cl_context context = clCreateContext(context_props, num_device, devices, NULL, NULL, &ret);

建立完上下文,就可以在其后进行建立命令队列、设置内核等操作。我们的OpenCL编程的万里长征也算是完成了第一步。

GPU加速云服务器

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:C++ 编程习惯与编程要点
下一篇:Excel表格中跨表数据有效性怎么设置和引用
相关文章