1. 选择OpenCL平台并创建一个上下文

平台(Platform)是指主机和OpenCL管理框架下的若干个设备构成的可以运行OpenCL程序的完整硬件系统,这个是跑OpenCL程序的基础,所以第一步要选择一个可用的OpenCL品台。一台机器上可以有不止一个这样的品台,一个平台也可以有不止一个GPU。

主要涉及的函数: clGetPlatformIDs() ,用于获取可用的平台;

clCreateContextFromType(), 创建一个OpenCL运行时山下文环境;

2. 选择设备并创建命令队列

选择平台并创建好OpenCL上下文环境之后,要做的事选择运行时用到的设备,还要创建一个命令队列,命令队列里定义了设备要完成的操作,以及各个操作的运行次序。

主要涉及的函数:clCreateCommandQueue(),用于创建一个指定设备上的上下文环境,第二个参数定义了选择的设备。

3. 创建和构建程序对象

程序对象用来存储与上下文相关联的设备的已编译可执行代码,同时也完成内核源代码的加载编译工作。

主要涉及的函数:clCreateProgramWithSource(), 这个函数会创建一个程序对象,在创建的同时,把已经转化成字符串形式的内核源代码加载到该程序对象中。

clBuildProgram()用于编译指定程序对象中的内核源代码,编译成功之后,再把编译代码存储在程序对象中。

4. 创建内核和内存对象

要执行程序对象中的已编译成功的内核运算,需要在内存中创建内核并分配内核函数的参数,在GPU上定义内存对象并分配存储空间。

主要涉及的函数:clCreateKernel(), 创建内核;

clCreateBuffer(),分配内存对象的存储空间,这些对象可以由内核函数直接访问。

5. 设置内核数据并执行内核

创建内核和内存对象之后,接下来要设置核函数的数据,并将要执行的内核排队。

主要涉及的函数:clEnqueueNDRangeKernel(),用于设置内核函数的所有参与运算的数据。    利用命令队列对要在设备上执行的内核排队。需要注意的是,执行内核排队之后并不意味着这个内核一定会立即执行,只是排队到了执行队列中。

6. 读取执行结果并释放OpenCL资源

内核执行完成之后,需要把数据从GPU拷贝到CPU中,供主机进一步处理,所有者写工作完成之后需要释放所有的OpenCL资源。

主要涉及的函数:clEnqueueReadBuffer(),读取设备内存数据到主机内存;

  clReleaseXXX(),释放OpenCL资源。

以下程序包含了以上所有6个步骤,功能很简单,实现两个数组求和。

主程序:

#include <iostream>
#include <fstream>
#include <sstream>
#include <CL/cl.h>const int ARRAY_SIZE = 1000;//一、 选择OpenCL平台并创建一个上下文
cl_context CreateContext()
{cl_int errNum;cl_uint numPlatforms;cl_platform_id firstPlatformId;cl_context context = NULL;//选择可用的平台中的第一个errNum = clGetPlatformIDs(1, &firstPlatformId, &numPlatforms);if (errNum != CL_SUCCESS || numPlatforms <= 0){std::cerr << "Failed to find any OpenCL platforms." << std::endl;return NULL;}//创建一个OpenCL上下文环境cl_context_properties contextProperties[] ={CL_CONTEXT_PLATFORM,(cl_context_properties)firstPlatformId,0};context = clCreateContextFromType(contextProperties, CL_DEVICE_TYPE_GPU,NULL, NULL, &errNum);return context;
}//二、 创建设备并创建命令队列
cl_command_queue CreateCommandQueue(cl_context context, cl_device_id *device)
{cl_int errNum;cl_device_id *devices;cl_command_queue commandQueue = NULL;size_t deviceBufferSize = -1;// 获取设备缓冲区大小errNum = clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, NULL, &deviceBufferSize);if (deviceBufferSize <= 0){std::cerr << "No devices available.";return NULL;}// 为设备分配缓存空间devices = new cl_device_id[deviceBufferSize / sizeof(cl_device_id)];errNum = clGetContextInfo(context, CL_CONTEXT_DEVICES, deviceBufferSize, devices, NULL);//选取可用设备中的第一个commandQueue = clCreateCommandQueue(context, devices[0], 0, NULL);*device = devices[0];delete[] devices;return commandQueue;
}// 三、创建和构建程序对象
cl_program CreateProgram(cl_context context, cl_device_id device, const char* fileName)
{cl_int errNum;cl_program program;std::ifstream kernelFile(fileName, std::ios::in);if (!kernelFile.is_open()){std::cerr << "Failed to open file for reading: " << fileName << std::endl;return NULL;}std::ostringstream oss;oss << kernelFile.rdbuf();std::string srcStdStr = oss.str();const char *srcStr = srcStdStr.c_str();program = clCreateProgramWithSource(context, 1,(const char**)&srcStr,NULL, NULL);errNum = clBuildProgram(program, 0, NULL, NULL, NULL, NULL);return program;
}//创建和构建程序对象
bool CreateMemObjects(cl_context context, cl_mem memObjects[3],float *a, float *b)
{memObjects[0] = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,sizeof(float) * ARRAY_SIZE, a, NULL);memObjects[1] = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,sizeof(float) * ARRAY_SIZE, b, NULL);memObjects[2] = clCreateBuffer(context, CL_MEM_READ_WRITE,sizeof(float) * ARRAY_SIZE, NULL, NULL);return true;
}// 释放OpenCL资源
void Cleanup(cl_context context, cl_command_queue commandQueue,cl_program program, cl_kernel kernel, cl_mem memObjects[3])
{for (int i = 0; i < 3; i++){if (memObjects[i] != 0)clReleaseMemObject(memObjects[i]);}if (commandQueue != 0)clReleaseCommandQueue(commandQueue);if (kernel != 0)clReleaseKernel(kernel);if (program != 0)clReleaseProgram(program);if (context != 0)clReleaseContext(context);
}int main(int argc, char** argv)
{cl_context context = 0;cl_command_queue commandQueue = 0;cl_program program = 0;cl_device_id device = 0;cl_kernel kernel = 0;cl_mem memObjects[3] = { 0, 0, 0 };cl_int errNum;// 一、选择OpenCL平台并创建一个上下文context = CreateContext();// 二、 创建设备并创建命令队列commandQueue = CreateCommandQueue(context, &device);//创建和构建程序对象program = CreateProgram(context, device, "HelloWorld.cl");// 四、 创建OpenCL内核并分配内存空间kernel = clCreateKernel(program, "hello_kernel", NULL);//创建要处理的数据float result[ARRAY_SIZE];float a[ARRAY_SIZE];float b[ARRAY_SIZE];for (int i = 0; i < ARRAY_SIZE; i++){a[i] = (float)i;b[i] = (float)(ARRAY_SIZE - i);}//创建内存对象if (!CreateMemObjects(context, memObjects, a, b)){Cleanup(context, commandQueue, program, kernel, memObjects);return 1;}// 五、 设置内核数据并执行内核errNum = clSetKernelArg(kernel, 0, sizeof(cl_mem), &memObjects[0]);errNum |= clSetKernelArg(kernel, 1, sizeof(cl_mem), &memObjects[1]);errNum |= clSetKernelArg(kernel, 2, sizeof(cl_mem), &memObjects[2]);size_t globalWorkSize[1] = { ARRAY_SIZE };size_t localWorkSize[1] = { 1 };errNum = clEnqueueNDRangeKernel(commandQueue, kernel, 1, NULL,globalWorkSize, localWorkSize,0, NULL, NULL);// 六、 读取执行结果并释放OpenCL资源errNum = clEnqueueReadBuffer(commandQueue, memObjects[2], CL_TRUE,0, ARRAY_SIZE * sizeof(float), result,0, NULL, NULL);for (int i = 0; i < ARRAY_SIZE; i++){std::cout << result[i] << " ";}std::cout << std::endl;std::cout << "Executed program succesfully." << std::endl;getchar();Cleanup(context, commandQueue, program, kernel, memObjects);return 0;
}

核函数文件“HelloWorld.cl”:

__kernel void hello_kernel(__global const float *a,__global const float *b,__global float *result)
{int gid = get_global_id(0);result[gid] = a[gid] + b[gid];
}

执行结果:

转载于:https://www.cnblogs.com/mtcnn/p/9411859.html

OpenCL编程基本流程及完整示例相关推荐

  1. SpringBoot 整合Activiti(二)——流程审批完整示例

    前两天做了一个SpringBoot整合Activiti的完整示例,功能包括:退回/通过(节点条件).指定办理人.生成流程图.高亮显示已办节点.查询任务列表(办理人)等,下面先简单记录(含完整代码),十 ...

  2. OpenCL程序编程基本流程

    本文转自http://www.photoneray.com/opencl_01/#program OpenCL作为一门开源的异构并行计算语言,设计之初就是使用一种模型来模糊各种硬件差异.作为软件开发人 ...

  3. Opencl编程的标准开发流程

    Opencl编程的标准开发流程 前言 OpenCL执行流程 模板 前言 在前面的内容中介绍 了opencl编程环境的搭建方式环境搭建,本篇文章以为例讲述opencl编程的标准开发流程 编程环境:VS2 ...

  4. OpenCL编程详细解析与实例

    OpenCL编程详细解析与实例 C语言与OpenCL的编程示例比较 参考链接: https://www.zhihu.com/people/wujianming_110117/posts 先以图像旋转的 ...

  5. 【Kotlin】Lambda 表达式 ( 简介 | 表达式语法 | 表达式类型 | 表达式返回值 | 调用方式 | 完整示例 )

    文章目录 I . Lambda 表达式 简介 II . Lambda 表达式语法 III . Lambda 表达式类型 IV . Lambda 表达式返回值 V . Lambda 表达式调用 VI . ...

  6. Spring Integration完整示例

    本文是我们名为" Spring Integration for EAI "的学院课程的一部分. 在本课程中,向您介绍了企业应用程序集成模式以及Spring Integration如 ...

  7. springcloud项目的启动顺序_Spring Cloud微服务项目完整示例,含注册中心,网关,断路器等等...

    Spring Cloud微服务项目完整示例 目的是为了演示基于Spring Cloud微服务框架,搭建一个接近业务实际场景的项目,只实现了后端项目,前端可以使用VUE或者其他框架. 后端框架包括注册中 ...

  8. php云打印类,PHP应用:PHP云打印类完整示例

    <PHP应用:PHP云打印类完整示例>要点: 本文介绍了PHP应用:PHP云打印类完整示例,希望对您有用.如果有疑问,可以联系我们. 本文实例讲述了PHP云打印类.分享给大家供大家参考,具 ...

  9. java中实现工厂日历_Java实现的日历功能完整示例

    本文实例讲述了java实现的日历功能.分享给大家供大家参考,具体如下: 应用名称:Java日历 用到的知识:Java GUI编程,日期操作 开发环境:win8+eclipse+jdk1.8 功能说明: ...

  10. Camunda入门(四) - 流程应用(支付流程)入门示例

    参考文章:Camunda入门(四) - 流程应用(支付流程)入门示例_罗小爬EX的博客-CSDN博客_camunda入门 1. 支付流程 - 场景设定 为了快速上手Camunda,结合Camunda官 ...

最新文章

  1. mac 制作usb启动盘_如何使用Mac制作Windows 10 USB-从Mac终端构建可启动的ISO
  2. 读“基于深度学习的图像风格迁移研究综述”有感
  3. 一句话搞定python六剑客
  4. 一篇特别长的总结(C专家编程)
  5. ios基础之归档和解档
  6. 五、“嵌段共聚醚酯型”易去污整理剂的结构特点及对织物服用性的影响?
  7. 帆软按钮控件变查询_如何设置finereport按钮控件的可用时间
  8. HttpURLConnection的流式输出的缺陷和解决方法
  9. HDFS基本命令及上传文件API
  10. 2021中国WMS市场发展趋势和特点
  11. 分布式数据库cobar
  12. 长沙云长计算机,【长沙记忆】原来关羽和长沙有这么多不解之缘
  13. 揭开MySQL数据库的神秘面纱!
  14. 写乐100道练习题_写乐大型21K详细评测(文长慎入)
  15. DBD::mysql的安装
  16. 国家省份城市级联菜单
  17. 1502: [NOI2005]月下柠檬树
  18. maven 开发 ejb ear
  19. C#窗口的更新过程解析
  20. Playwright-Node.js 自动化办公

热门文章

  1. cmake 交叉编译_如何使用CMake编译RTT微内核
  2. 计算机专业基础 -- 网络相关AJAX基础知识
  3. linux中python如何调用matlab的数据_如何在Python中创建Gif动图?(动图数据可视化基础教学)
  4. http协议的状态码——400,401,403,404,500,502,503,301,302等常见网页错误代码
  5. 深度学习图片卷积输出大小计算公式
  6. 软件公司的管理规范化了、编制都齐全了,一般小公司是承受不了的这么庞大的开支的...
  7. 微软正式提供免费杀毒软件下载 仅限7.5万份
  8. 一致性hash算法的应用研究学习
  9. 最优化方法:拉格朗日乘数法(转)
  10. 英国电信选择由 Canonical 开发的 Ubuntu OpenStack 作为云平台