OpenCL快速入门教程
来源:互联网 发布:乐视电视怎么设置网络 编辑:程序博客网 时间:2024/06/10 13:00
OpenCL: OpenCL快速
原文地址:http://opencl.codeplex.com/wikipage?title=OpenCL%20Tutorials%20-%201
这是第一篇真正的OpenCL教程。这篇文章不会从GPU结构的技术概念和性能指标入手。我们将会从OpenCL的基础API开始,使用一个小的kernel作为例子来讲解基本的计算管理。
首先我们需要明白的是,OpenCL程序是分成两部分的:一部分是在设备上执行的(对于我们,是GPU),另一部分是在主机上运行的(对于我们,是CPU)。在设备上执行的程序或许是你比较关注的。它是OpenCL产生神奇力量的地方。为了能在设备上执行代码,程序员需要写一个特殊的函数(kernel函数)。这个函数需要使用OpenCL语言编写。OpenCL语言采用了C语言的一部分加上一些约束、关键字和数据类型。在主机上运行的程序提供了API,所以i可以管理你在设备上运行的程序。主机程序可以用C或者C++编写,它控制OpenCL的环境(上下文,指令队列…)。
设备(Device)
我们来简单的说一下设备。设备,像上文介绍的一样,OpenCL编程最给力的地方。
我们必须了解一些基本概念:
Kernel:你可以把它想像成一个可以在设备上执行的函数。当然也会有其他可以在设备上执行的函数,但是他们之间是有一些区别的。Kernel是设备程序执行的入口点。换言之,Kernel是唯一可以从主机上调用执行的函数。
现在的问题是:我们如何来编写一个Kernel?在Kernel中如何表达并行性?它的执行模型是怎样的?解决这些问题,我们需要引入下面的概念:
SIMT:单指令多线程(SINGLE INSTRUCTION MULTI THREAD)的简写。就像这名字一样,相同的代码在不同线程中并行执行,每个线程使用不同的数据来执行同一段代码。
Work-item(工作项):Work-item与CUDA Threads是一样的,是最小的执行单元。每次一个Kernel开始执行,很多(程序员定义数量)的Work-item就开始运行,每个都执行同样的代码。每个work-item有一个ID,这个ID在kernel中是可以访问的,每个运行在work-item上的kernel通过这个ID来找出work-item需要处理的数据。
Work-group(工作组):work-group的存在是为了允许work-item之间的通信和协作。它反映出work-item的组织形式(work-group是以N维网格形式组织的,N=1,2或3)。
Work-group等价于CUDA thread blocks。像work-items一样,work-groups也有一个kernel可以读取的唯一的ID。
ND-Range:ND-Range是下一个组织级别,定义了work-group的组织形式(ND-Rang以N维网格形式组织的,N=1,2或3);
这是ND-Range组织形式的例子
Kernel
现在该写我们的第一个kernel了。我们写一个小的kernel将两个向量相加。这个kernel需要四个参数:两个要相加的向量,一个存储结果的向量,和向量个数。如果你写一个程序在cpu上解决这个问题,将会是下面这个样子:
在GPU上,逻辑就会有一些不同。我们使每个线程计算一个元素的方法来代替cpu程序中的循环计算。每个线程的index与要计算的向量的index相同。我们来看一下代码实现:
有一些需要注意的地方:
1. Kernel关键字定义了一个函数是kernel函数。Kernel函数必须返回void。
2. Global关键字位于参数前面。它定义了参数内存的存放位置。
另外,所有kernel都必须写在“.cl”文件中,“.cl”文件必须只包含OpenCL代码。
主机(Host)
我们的kernel已经写好了,现在我们来写host程序。
建立基本OpenCL运行环境
有一些东西我们必须要弄清楚:
Plantform(平台):主机加上OpenCL框架管理下的若干设备构成了这个平台,通过这个平台,应用程序可以与设备共享资源并在设备上执行kernel。平台通过cl_plantform来展现,可以使用下面的代码来初始化平台:
Device(设备):通过cl_device来表现,使用下面的代码:
Context(上下文):定义了整个OpenCL化境,包括OpenCL kernel、设备、内存管理、命令队列等。上下文使用cl_context来表现。使用以下代码初始化:
Command-Queue(指令队列):就像它的名字一样,他是一个存储需要在设备上执行的OpenCL指令的队列。“指令队列建立在一个上下文中的指定设备上。多个指令队列允许应用程序在不需要同步的情况下执行多条无关联的指令。”
下面的例子展示了这些元素的使用方法:
分配内存
主机的基本环境已经配置好了,为了可以执行我们的写的小kernel,我们需要分配3个向量的内存空间,然后至少初始化它们其中的两个。
在主机环境下执行这些操作,我们需要像下面的代码这样去做:
在设备上分配内存,我们需要使用cl_mem类型,像下面这样:
flags是逐位的,选项如下:
CL_MEM_READ_WRITE
CL_MEM_WRITE_ONLY
CL_MEM_READ_ONLY
CL_MEM_USE_HOST_PTR
CL_MEM_ALLOC_HOST_PTR
CL_MEM_COPY_HOST_PTR – 从 host_ptr处拷贝数据
我们通过下面的代码使用这个函数:
程序和kernel
到现在为止,你可能会问自己一些问题,比如:我们怎么调用kernel?编译器怎么知道如何将代码放到设备上?我们怎么编译kernel?
下面是我们在对比OpenCL程序和OpenCL kernel时的一些容易混乱的概念:
Kernel:你应该已经知道了,像在上文中描述的一样,kernel本质上是一个我们可以从主机上调用的,运行在设备上的函数。你或许不知道kernel是在运行的时候编译的!更一般的讲,所有运行在设备上的代码,包括kernel和kernel调用的其他的函数,都是在运行的时候编译的。这涉及到下一个概念,Program。
Program:OpenCL Program由kernel函数、其他函数和声明组成。它通过cl_program表示。当创建一个program时,你必须指定它是由哪些文件组成的,然后编译它。
你需要用到下面的函数来建立一个Program:
当我们创建了Program我们可以用下面的函数执行编译操作:
查看编译log,必须使用下面的函数:
最后,我们需要“提取”program的入口点。使用cl_kernel:
注意我们可以创建多个OpenCL program,每个program可以拥有多个kernel。
以下是这一章节的代码:
运行kernel
一旦我们的kernel建立好,我们就可以运行它。
首先,我们必须设置kernel的参数:
每个参数都需要调用一次这个函数。
当所有参数设置完毕,我们就可以调用这个kernel:
下面是这一章节的代码:
读取结果
读取结果非常简单。与之前讲到的写入内存(设备内存)的操作相似,现在我们需要存入队列一个读取缓冲区的操作:
使用方法如下:
清理
作为一名牛X的程序员我们肯定要考虑如何清理内存!
你需要知道最基本东西:使用clCreate申请的(缓冲区、kernel、队列)必须使用clRelease释放。
代码如下:
这是文章的全部内容了,码农们,作者最后说,如果你有任何问题,都可以马上联系他。
Code sample
Regular CPU code
// initializationVideoCapture vcap(...);CascadeClassifier fd("haar_ff.xml");Mat frame, frameGray;vector<rect> faces;for(;;){ // processing loop vcap >> frame; cvtColor(frame, frameGray, BGR2GRAY); equalizeHist(frameGray, frameGray); fd.detectMultiScale(frameGray, faces, ...); // draw rectangles … // show image …}
OpenCL-aware code OpenCV-2.x
// initializationVideoCapture vcap(...);ocl::OclCascadeClassifier fd("haar_ff.xml");ocl::oclMat frame, frameGray;Mat frameCpu;vector<rect> faces;for(;;){ // processing loop vcap >> frameCpu; frame = frameCpu; ocl::cvtColor(frame, frameGray, BGR2GRAY); ocl::equalizeHist(frameGray, frameGray); fd.detectMultiScale(frameGray, faces, ...); // draw rectangles … // show image …}
OpenCL-aware code OpenCV-3.x
// initializationVideoCapture vcap(...);CascadeClassifier fd("haar_ff.xml");UMat frame, frameGray;vector<rect> faces;for(;;){ // processing loop vcap >> frame; cvtColor(frame, frameGray, BGR2GRAY); equalizeHist(frameGray, frameGray); fd.detectMultiScale(frameGray, faces, ...); // draw rectangles … // show image …}
- OpenCL: OpenCL快速入门教程
- OpenCL快速入门教程
- OpenCL快速入门教程
- OpenCL快速入门教程
- OpenCL快速入门教程
- OpenCL快速入门教程
- OpenCL快速入门教程
- OpenCL快速入门教程
- OpenCL快速入门教程
- OpenCL快速入门教程
- OpenCL快速入门教程
- opencl 初学笔记2- opencl快速入门教程【数据类型规范 , 命名原则】
- OpenCL快速入门
- QT下快速开发 opencl
- OpenCL
- OpenCL
- OpenCL
- OpenCL
- android开发常用依赖包
- mongo-connector实时增量索引
- 查看Resin版本号
- Python网页抓取工具Beautiful Soup面面观!
- 自动生成unpivot,方便table展示字符度量
- OpenCL快速入门教程
- android左右滑动监听,上下滑动
- shiro入门
- Android4.4系统浏览器Chromium实现的加载模块与流程
- Schwarzer教你用OpenCV实现基于标记的AR
- TCP漏洞引来黑客对Linux系统的攻击
- android的Activity采用透明主题
- 用python连接数据库,实现用户注册和用户登录
- java-字符串把所有的a改为b