GPGPU OpenCL编程步骤与简单实例

举报
风吹稻花香 发表于 2021/06/05 00:02:38 2021/06/05
【摘要】 GPGPU OpenCL编程步骤与简单实例 参考:http://www.cnblogs.com/xudong-bupt/p/3582780.html  1.OpenCL概念   OpenCL是一个为异构平台编写程序的框架,此异构平台可由CPU、GPU或其他类型的处理器组成。OpenCL由一门用于编写kernels (在OpenCL设备上运行的函数)的语言(基于...

GPGPU OpenCL编程步骤与简单实例

参考:http://www.cnblogs.com/xudong-bupt/p/3582780.html 

1.OpenCL概念

  OpenCL是一个为异构平台编写程序的框架,此异构平台可由CPU、GPU或其他类型的处理器组成。OpenCL由一门用于编写kernels (在OpenCL设备上运行的函数)的语言(基于C99)和一组用于定义并控制平台的API组成。

  OpenCL提供了两种层面的并行机制:任务并行与数据并行。

2.OpenCL与CUDA的区别

  不同点:OpenCL是通用的异构平台编程语言,为了兼顾不同设备,使用繁琐。

CUDA是nvidia公司发明的专门在其GPGPU上的编程的框架,使用简单,好入门。

  相同点:都是基于任务并行与数据并行。

3.OpenCL的编程步骤

  (1)Discover and initialize the platforms

调用两次clGetPlatformIDs函数,第一次获取可用的平台数量,第二次获取一个可用的平台。

  (2)Discover and initialize the devices

调用两次clGetDeviceIDs函数,第一次获取可用的设备数量,第二次获取一个可用的设备。

  (3)Create  a context(调用clCreateContext函数)

上下文context可能会管理多个设备device。

  (4)Create a command queue(调用clCreateCommandQueue函数)

一个设备device对应一个command queue。

上下文conetxt将命令发送到设备对应的command queue,设备就可以执行命令队列里的命令。

  (5)Create device buffers(调用clCreateBuffer函数)

Buffer中保存的是数据对象,就是设备执行程序需要的数据保存在其中。

  Buffer由上下文conetxt创建,这样上下文管理的多个设备就会共享Buffer中的数据。

  (6)Write host data to device buffers(调用clEnqueueWriteBuffer函数)

  (7)Create and compile the program

创建程序对象,程序对象就代表你的程序源文件或者二进制代码数据。

  (8)Create the kernel(调用clCreateKernel函数)

根据你的程序对象,生成kernel对象,表示设备程序的入口。

  (9)Set the kernel arguments(调用clSetKernelArg函数)

  (10)Configure the work-item structure(设置worksize)

配置work-item的组织形式(维数,group组成等)

  (11)Enqueue the kernel for execution(调用clEnqueueNDRangeKernel函数)

将kernel对象,以及 work-item参数放入命令队列中进行执行。

  (12)Read  the output buffer back to the host(调用clEnqueueReadBuffer函数)

  (13)Release OpenCL resources(至此结束整个运行过程)

4.说明

  OpenCL中的核函数必须单列一个文件。

  OpenCL的编程一般步骤就是上面的13步,太长了,以至于要想做个向量加法都是那么困难。

  不过上面的步骤前3步一般是固定的,可以单独写在一个.h/.cpp文件中,其他的一般也不会有什么大的变化。

5.程序实例,向量运算

5.1通用前3个步骤,生成一个文件

  tool.h

复制代码
 1 #ifndef TOOLH
 2 #define TOOLH
 3 
 4 #include <CL/cl.h>
 5 #include <string.h>
 6 #include <stdio.h>
 7 #include <stdlib.h>
 8 #include <iostream>
 9 #include <string>
10 #include <fstream>
11 using namespace std;
12 
13 /** convert the kernel file into a string */
14 int convertToString(const char *filename, std::string& s);
15 
16 /**Getting platforms and choose an available one.*/
17 int getPlatform(cl_platform_id &platform);
18 
19 /**Step 2:Query the platform and choose the first GPU device if has one.*/
20 cl_device_id *getCl_device_id(cl_platform_id &platform);
21 
22 #endif
复制代码

  tool.cpp

复制代码
 1 #include <CL/cl.h>
 2 #include <string.h>
 3 #include <stdio.h>
 4 #include <stdlib.h>
 5 #include <iostream>
 6 #include <string>
 7 #include <fstream>
 8 #include "tool.h"
 9 using namespace std;
10 
11 /** convert the kernel file into a string */
12 int convertToString(const char *filename, std::string& s)
13 {
14  size_t size;
15 char*  str;
16 std::fstream f(filename, (std::fstream::in | std::fstream::binary));
17 
18 if(f.is_open())
19  {
20  size_t fileSize;
21 f.seekg(0, std::fstream::end);
22 size = fileSize = (size_t)f.tellg();
23 f.seekg(0, std::fstream::beg);
24 str = new char[size+1];
25 if(!str)
26  {
27  f.close();
28 return 0;
29  }
30 
31  f.read(str, fileSize);
32  f.close();
33 str[size] = '\0';
34 s = str;
35  delete[] str;
36 return 0;
37  }
38 cout<<"Error: failed to open file\n:"<<filename<<endl;
39 return -1;
40 }
41 
42 /**Getting platforms and choose an available one.*/
43 int getPlatform(cl_platform_id &platform)
44 {
45 platform = NULL;//the chosen platform
46 
47 cl_uint numPlatforms;//the NO. of platforms
48 cl_int status = clGetPlatformIDs(0, NULL, &numPlatforms);
49 if (status != CL_SUCCESS)
50  {
51 cout<<"Error: Getting platforms!"<<endl;
52 return -1;
53  }
54 
55 /**For clarity, choose the first available platform. */
56 if(numPlatforms > 0)
57  {
58 cl_platform_id* platforms =
59 (cl_platform_id* )malloc(numPlatforms* sizeof(cl_platform_id));
60 status = clGetPlatformIDs(numPlatforms, platforms, NULL);
61 platform = platforms[0];
62  free(platforms);
63  }
64 else
65 return -1;
66 }
67 
68 /**Step 2:Query the platform and choose the first GPU device if has one.*/
69 cl_device_id *getCl_device_id(cl_platform_id &platform)
70 {
71 cl_uint numDevices = 0;
72 cl_device_id *devices=NULL;
73 cl_int status = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 0, NULL, &numDevices);
74 if (numDevices > 0) //GPU available.
75  {
76 devices = (cl_device_id*)malloc(numDevices * sizeof(cl_device_id));
77 status = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, numDevices, devices, NULL);
78  }
79 return devices;
80 }
复制代码

5.2核函数文件

  HelloWorld_Kernel.cl

1 __kernel void helloworld(__global double* in, __global double* out)
2 {
3 int num = get_global_id(0);
4 out[num] = in[num] / 2.4 *(in[num]/6) ;
5 }

 5.3主函数文件

  HelloWorld.cpp

复制代码
 1 //For clarity,error checking has been omitted.
 2 #include <CL/cl.h>
 3 #include "tool.h"
 4 #include <string.h>
 5 #include <stdio.h>
 6 #include <stdlib.h>
 7 #include <iostream>
 8 #include <string>
 9 #include <fstream>
10 using namespace std;
11 
12 int main(int argc, char* argv[])
13 {
14  cl_int status;
15 /**Step 1: Getting platforms and choose an available one(first).*/
16  cl_platform_id platform;
17  getPlatform(platform);
18 
19 /**Step 2:Query the platform and choose the first GPU device if has one.*/
20 cl_device_id *devices=getCl_device_id(platform);
21 
22 /**Step 3: Create context.*/
23 cl_context context = clCreateContext(NULL,1, devices,NULL,NULL,NULL);
24 
25 /**Step 4: Creating command queue associate with the context.*/
26 cl_command_queue commandQueue = clCreateCommandQueue(context, devices[0], 0, NULL);
27 
28 /**Step 5: Create program object */
29 const char *filename = "HelloWorld_Kernel.cl";
30 string sourceStr;
31 status = convertToString(filename, sourceStr);
32 const char *source = sourceStr.c_str();
33 size_t sourceSize[] = {strlen(source)};
34 cl_program program = clCreateProgramWithSource(context, 1, &source, sourceSize, NULL);
35 
36 /**Step 6: Build program. */
37 status=clBuildProgram(program, 1,devices,NULL,NULL,NULL);
38 
39 /**Step 7: Initial input,output for the host and create memory objects for the kernel*/
40 const int NUM=512000;
41 double* input = new double[NUM];
42 for(int i=0;i<NUM;i++)
43 input[i]=i;
44 double* output = new double[NUM];
45 
46 cl_mem inputBuffer = clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR, (NUM) * sizeof(double),(void *) input, NULL);
47 cl_mem outputBuffer = clCreateBuffer(context, CL_MEM_WRITE_ONLY , NUM * sizeof(double), NULL, NULL);
48 
49 /**Step 8: Create kernel object */
50 cl_kernel kernel = clCreateKernel(program,"helloworld", NULL);
51 
52 /**Step 9: Sets Kernel arguments.*/
53 status = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&inputBuffer);
54 status = clSetKernelArg(kernel, 1, sizeof(cl_mem), (void *)&outputBuffer);
55 
56 /**Step 10: Running the kernel.*/
57 size_t global_work_size[1] = {NUM};
58  cl_event enentPoint;
59 status = clEnqueueNDRangeKernel(commandQueue, kernel, 1, NULL, global_work_size, NULL, 0, NULL, &enentPoint);
60 clWaitForEvents(1,&enentPoint); ///wait
61  clReleaseEvent(enentPoint);
62 
63 /**Step 11: Read the cout put back to host memory.*/
64 status = clEnqueueReadBuffer(commandQueue, outputBuffer, CL_TRUE, 0, NUM * sizeof(double), output, 0, NULL, NULL);
65 cout<<output[NUM-1]<<endl;
66 
67 /**Step 12: Clean the resources.*/
68 status = clReleaseKernel(kernel);//*Release kernel.
69 status = clReleaseProgram(program); //Release the program object.
70 status = clReleaseMemObject(inputBuffer);//Release mem object.
71 status = clReleaseMemObject(outputBuffer);
72 status = clReleaseCommandQueue(commandQueue);//Release  Command queue.
73 status = clReleaseContext(context);//Release context.
74 
75 if (output != NULL)
76  {
77  free(output);
78 output = NULL;
79  }
80 
81 if (devices != NULL)
82  {
83  free(devices);
84 devices = NULL;
85  }
86 return 0;
87 }
复制代码

 

编译、链接、执行:

  g++ -I /opt/AMDAPP/include/ -o A  *.cpp -lOpenCL ; ./A

文章来源: blog.csdn.net,作者:网奇,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/jacke121/article/details/64123261

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。