OpenCL程序分为两个部份,一部份是内核代码,负责具体算法。另一部份是主程序负责初始化OpenCL和准备数据。主程序加载内核代码,并按照即定方法进行运算。

内核代码可以写在主程序里面,也可以写在另一个文本文件里,有点像DX中的HLSL和OPENGL里的GLSL。哈哈,明白意思就行了。我们用第一种方法,把代码跟源程序分开写。

调用OpenCL大至分7个步骤

1:初始化OpenCL

2:创建上下文设备

3:创建命令队列

4:创建数据缓冲区

5:将数据上传到缓冲区

6:加载编译代码,创建内核调用函数

7:设置参数,执行内核

8:读回计算结果。

下面我们通过一个向量相加的程序来了解OpenCL 。有A,B两个四维向量,相加后值存在C向量里。OpenCL会根据用户提供的维数,将向量分解成多个任务分发给多个CPU计算。

源码分两部份

(一)vecadd.cl核心代码。

?
1
2
3
4
5
6
7
8
__kernel void vecAdd(__global int* A,
        __global int* B,
        __global int* C)
{
    //获取当前工作项所在位置(线程索引号)
    int idx = get_global_id(0);
    C[idx] = A[idx] + B[idx];
}

__kernel 指明这是一个OpenCL内核,__global 说明指针指向的是全局的设备内存空间,其它的就是C语言的函数的语法。kernel必须返回空类型。

(二)main.cpp代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <CL/cl.h>//包含CL的头文件
using namespace std;
//四维向量
#define elements 4
//从外部文件获取cl内核代码
bool GetFileData(const char* fname,string& str)
{
    FILE* fp = fopen(fname,"r");
    if(fp==NULL)
    {
        printf("no found file\n");
        return false;
    }
    int n=0;
    while(feof(fp)==0)
    {
        str += fgetc(fp);
    }
    return true;
}
int main()
{
    //先读外部CL核心代码,如果失败则退出。
    //代码存buf_code里面
    string code_file;
    if(false == GetFileData("vecadd.cl",code_file))
        return 0;
    char* buf_code = new char[code_file.size()];
    strcpy(buf_code,code_file.c_str());
    buf_code[code_file.size()-1] = NULL;
    //声明CL所需变量。
    cl_device_id device;
    cl_platform_id platform_id = NULL;
    cl_context context;
    cl_command_queue cmdQueue;
    cl_mem bufferA,bufferB,bufferC;
    cl_program program;
    cl_kernel kernel = NULL;
    //我们使用的是一维向量
    //设定向量大小(维数)
    size_t globalWorkSize[1];
    globalWorkSize[0] = elements;
    cl_int err;
    /*
        定义输入变量和输出变量,并设定初值
    */
    int* buf_A = new int[elements];
    int* buf_B = new int[elements];
    int* buf_C = new int[elements];
    size_t datasize = sizeof(int) * elements;
    buf_A[0] = 1;
    buf_A[1] = 2;
    buf_A[2] = 3;
    buf_A[3] = 4;
    buf_B[0] = 5;
    buf_B[1] = 6;
    buf_B[2] = 7;
    buf_B[3] = 8;
    //step 1:初始化OpenCL
    err = clGetPlatformIDs(1,&platform_id,NULL);
    if(err!=CL_SUCCESS)
    {
        cout<<"clGetPlatformIDs error"<<endl;
        return 0;
    }
    //这次我们只用CPU来进行并行运算,当然你也可以该成GPU
    clGetDeviceIDs(platform_id,CL_DEVICE_TYPE_CPU,1,&device,NULL);
    //step 2:创建上下文
    context = clCreateContext(NULL,1,&device,NULL,NULL,NULL);
    //step 3:创建命令队列
    cmdQueue = clCreateCommandQueue(context,device,0,NULL);
    //step 4:创建数据缓冲区
    bufferA = clCreateBuffer(context,
                             CL_MEM_READ_ONLY,
                             datasize,NULL,NULL);
    bufferB = clCreateBuffer(context,
                             CL_MEM_READ_ONLY,
                             datasize,NULL,NULL);
    bufferC = clCreateBuffer(context,
                             CL_MEM_WRITE_ONLY,
                             datasize,NULL,NULL);
    //step 5:将数据上传到缓冲区
    clEnqueueWriteBuffer(cmdQueue,
                         bufferA,CL_FALSE,
                         0,datasize,
                         buf_A,0,
                         NULL,NULL);
    clEnqueueWriteBuffer(cmdQueue,
                         bufferB,CL_FALSE,
                         0,datasize,
                         buf_B,0,
                         NULL,NULL);
    //step 6:加载编译代码,创建内核调用函数
    program = clCreateProgramWithSource(context,1,
                                        (const char**)&buf_code,
                                        NULL,NULL);
    clBuildProgram(program,1,&device,NULL,NULL,NULL);
    kernel = clCreateKernel(program,"vecAdd",NULL);
    //step 7:设置参数,执行内核
    clSetKernelArg(kernel,0,sizeof(cl_mem),&bufferA);
    clSetKernelArg(kernel,1,sizeof(cl_mem),&bufferB);
    clSetKernelArg(kernel,2,sizeof(cl_mem),&bufferC);
    clEnqueueNDRangeKernel(cmdQueue,kernel,
                           1,NULL,
                           globalWorkSize,
                           NULL,0,NULL,NULL);
    //step 8:取回计算结果
    clEnqueueReadBuffer(cmdQueue,bufferC,CL_TRUE,0,
                        datasize,buf_C,0,NULL,NULL);
    //输出计算结果
    cout<<"["<<buf_A[0]<<","<<buf_A[1]<<","<<buf_A[2]<<","<<buf_A[3]<<"]+["
    <<buf_B[0]<<","<<buf_B[1]<<","<<buf_B[2]<<","<<buf_B[3]<<"]=["
    <<buf_C[0]<<","<<buf_C[1]<<","<<buf_C[2]<<","<<buf_C[3]<<"]"<<endl;
    //释放所有调用和内存
    clReleaseKernel(kernel);
    clReleaseProgram(program);
    clReleaseCommandQueue(cmdQueue);
    clReleaseMemObject(bufferA);
    clReleaseMemObject(bufferB);
    clReleaseMemObject(bufferC);
    clReleaseContext(context);
    delete buf_A;
    delete buf_B;
    delete buf_C;
    delete buf_code;
    return 0;
}

运算结果:

 [1,2,3,4] + [5,6,7,8] = [6,8,10,12]

OpenCL 第5课:向量相加相关推荐

  1. OpenCL向量相加

    原文http://www.olcf.ornl.gov/training_articles/opencl-vector-addition/ 本文仅仅是为了学习OpenCL而做的的相关翻译. 由于原文中的 ...

  2. OpenCL学习笔记——整体流程(向量相加)

    OpenCL学习笔记--整体流程 OpenCL可以实现混合设备的并行计算,这些设备包括CPU,GPU,以及其他处理器,比如Cell处理器,DSP等.使用OpenCL编程,可以实现可以值得并行加速代码. ...

  3. OpenCL 第6课:矩阵转置

    上一节我们写了个一维向量相加的程序.这节我们来看一个4×4矩阵转置程序. 4X4矩阵我们采用二维数组进行存储,在程序设计上,我们让转置过程分4次转置完成,就是一次转一行.注意这里的OpenCL的工作维 ...

  4. python 向量_关于Python中的向量相加和numpy中的向量相加效率对比

    直接使用Python来实现向量的相加 # -*-coding:utf-8-*- #向量相加 def pythonsum(n): a = range(n) b = range(n) c = [] for ...

  5. python坐标系 向量分量_关于Python中的向量相加和numpy中的向量相加效率对比

    直接使用Python来实现向量的相加 # -*-coding:utf-8-*- #向量相加 def pythonsum(n): a = range(n) b = range(n) c = [] for ...

  6. 考研:研究生考试(五天学完)之《线性代数与空间解析几何》研究生学霸重点知识点总结之第三课向量与向量空间

    考研:研究生考试(五天学完)之<线性代数与空间解析几何>研究生学霸重点知识点总结之第三课向量与向量空间 目录

  7. 像素颜色和颜色向量相加相乘的理解

    首先计算机图形学的一条原则是,如果它看上去是对的,那它就是对的.所以,对于一些计算模型来说,最重要的是最后拟合的效果.它不一定符合物理,但通常计算都以物理上的考虑为基础. 像素颜色和相关运算的理解 我 ...

  8. 向量相加后是否与目标向量平行

    一.这是一个验证向量组中是否含有相加能与目标向量平行的代码 问题描述: 给定n个向量的起点和终点x1,y1,x2,y2,再给出一个目标向量,求能否由n个向量中的两个相加构造出一个与目标向量平行的向量( ...

  9. OpenCL 第8课:旋转变换(2)

    上两节课都是对一个数组进行处理.这节我们来个有意思的.同样是旋转.但我们旋转的对象是张(256*256)的图片.图片旋转45度,旋转后大小还是256*256,超出部份进行剪除. 图片旋转处理有个特别的 ...

最新文章

  1. 笔记--待解决,整理
  2. 为数据中心度身定制智能基础设施管理系统
  3. ASP.NET Core:CMD命令行+记事本 创建Console程序和Web Application
  4. Eclipse 中隐藏的 5 个非常有用的功能
  5. 《网易编程题》买苹果
  6. 发电厂电气部分第三版pdf_火力发电厂电气主接线的特点
  7. android json字符串转成json对象_C++ 两行代码实现json与类对象互转
  8. telnet后为啥打开的时防火墙_以前用散煤取暖时,农民很大方,换上天然气后就“蔫了”,为啥?...
  9. iptables上课内容
  10. Linux SD卡建立两个分区
  11. Oracle 基本函数-数值、字符、 Instr()、日期、转换、SQL 操作符、trunc 截断
  12. 杰·亚伯拉罕的产品营销35种策略完整版
  13. 【195】apache2.4安装ssl 证书
  14. 基于百度AI开放平台及图灵机器人搭建的聊天机器人
  15. 【NLP】第10章 使用基于 BERT 的 Transformer 进行语义角色标记
  16. 推荐四个不错的公众号
  17. 【源码】Simscape教程的模拟练习题
  18. 安装谷歌扩展插件:程序包无效
  19. 【转】目前最常见的”无线通信(数据)传输技术“有哪些?
  20. Vuex存储公共的数据步骤

热门文章

  1. LSGO软件技术团队2015~2016学年第五周(0928~1004)总结
  2. 【转】刨根究底字符编码之九——字符编码方案的演变与字节序
  3. 【转】Microsoft Cloud全新认证体系介绍
  4. PowerDesigner怎样才能在修改表的字段Name的时候Code不自动跟着变
  5. Linq to SQL之使用事务
  6. 一步步编写操作系统 6 启动bochs
  7. mysql数据库字符集设置_查看和设置MySQL数据库字符集
  8. 多级队列调度算法可视化界面_C++实现操作系统调度算法(FSFS,SJF,RR,多级反馈队列算法)...
  9. CCNA-Cisco-Packet-Tracerchs(思科官网)安装教程以及使用
  10. 3dmax里面cr材质转换vr材质_3DMAX零基础入门视频全套教程