OpenCL编程入门
原文地址:http://www.cnblogs.com/mikewolf2002/archive/2012/01/30/2332391.html
1、OpenCL架構(gòu)
????? OpenCL可以實(shí)現(xiàn)混合設(shè)備的并行計算,這些設(shè)備包括CPU,GPU,以及其它處理器,比如Cell處理器,DSP等。使用OpenCL編程,可以實(shí)現(xiàn)可移植的并行加速代碼。[但由于各個OpenCL device不同的硬件性能,可能對于程序的優(yōu)化還要考慮具體的硬件特性]。
?? 通常OpenCL架構(gòu)包括四個部分:
- 平臺模型(Platform Model)
- 執(zhí)行模型(Execution Model)
- 內(nèi)存模型(Memory Model)
- 編程模型(Programming Model)
2、OpenCL平臺模型
????? 不同廠商的OpenCL實(shí)施定義了不同的OpenCL平臺,通過OpenCL平臺,主機(jī)能夠和OpenCL設(shè)備之間進(jìn)行交互操作。現(xiàn)在主要的OpenCL平臺有AMD、Nvida,Intel等。OpenCL使用了一種Installable Client Driver模型,這樣不同廠商的平臺就能夠在系統(tǒng)中共存。在我的計算機(jī)上就安裝有AMD和Intel兩個OpenCL Platform[現(xiàn)在的OpenCL driver模型不允許不同廠商的GPU同時運(yùn)行]。
?OpenCL平臺通常包括一個主機(jī)(Host)和多個OpenCL設(shè)備(device),每個OpenCL設(shè)備包括一個或多個CU(compute units),每個CU包括又一個或多個PE(process element)。 每個PE都有自己的程序計數(shù)器(PC)。主機(jī)就是OpenCL運(yùn)行庫宿主設(shè)備,在AMD和Nvida的OpenCL平臺中,主機(jī)一般都指x86 CPU。
??????? AMD平臺來說,所有的CPU是一個設(shè)備,CPU的每一個core就是一個CU,而每個GPU都是獨(dú)立的設(shè)備。
?OpenCL平臺通常包括一個主機(jī)(Host)和多個OpenCL設(shè)備(device),每個OpenCL設(shè)備包括一個或多個CU(compute units),每個CU包括又一個或多個PE(process element)。 每個PE都有自己的程序計數(shù)器(PC)。主機(jī)就是OpenCL運(yùn)行庫宿主設(shè)備,在AMD和Nvida的OpenCL平臺中,主機(jī)一般都指x86 CPU。
??????? AMD平臺來說,所有的CPU是一個設(shè)備,CPU的每一個core就是一個CU,而每個GPU都是獨(dú)立的設(shè)備。
3、OpenCL編程的一般步驟
??下面我們通過一個實(shí)例來了解OpenCL編程的步驟,假設(shè)我們用的是AMD OpenCL平臺(因為本人的GPU是HD5730),安裝了AMD Stream SDK 2.6,并在VS2008中設(shè)置好了include,lib目錄等。
??? 首先我們建立一個控制臺程序,最初的代碼如下:
1: #include "stdafx.h"2: #include <CL/cl.h>3: #include <stdio.h>4: #include <stdlib.h>5: 6: #pragma comment (lib,"OpenCL.lib")7: 8: int main(int argc, char* argv[])9: {10: return 0;11: }第一步,我們要選擇一個OpenCL平臺,所用的函數(shù)就是
? ? ?通常,這個函數(shù)要調(diào)用兩次,第一次得到系統(tǒng)中可使用的平臺數(shù)目,然后為(Platform)平臺對象分配空間,第二次調(diào)用就是查詢所有的平臺,選擇自己需要的OpenCL平臺。代碼比較長,具體可以看下AMD Stream SDK 2.6中的TemplateC例子,里面描述如何構(gòu)建一個健壯的最小OpenCL程序。為了簡化代碼,使程序看起來不那么繁瑣,我直接調(diào)用該函數(shù),選取系統(tǒng)中的第一個OpenCL平臺,我的系統(tǒng)中安裝AMD和Intel兩家的平臺,第一個平臺是AMD的。另外,我也沒有增加錯誤檢測之類的代碼,但是增加了一個status的變量,通常如果函數(shù)執(zhí)行正確,返回的值是0。
1: #include "stdafx.h"2: #include <CL/cl.h>3: #include <stdio.h>4: #include <stdlib.h>5: 6: #pragma comment (lib,"OpenCL.lib")7: 8: int main(int argc, char* argv[])9: {10: cl_uint status;11: cl_platform_id platform;12: 13: status = clGetPlatformIDs( 1, &platform, NULL );14: 15: return 0;16: }第二步是得到OpenCL設(shè)備
? 這個函數(shù)通常也是調(diào)用兩次,第一次查詢設(shè)備數(shù)量,第二次檢索得到我們想要的設(shè)備。為了簡化代碼,我們直接指定GPU設(shè)備。
下面我們來看下OpenCL中Context的概念:通常,Context是指管理OpenCL對象和資源的上下文環(huán)境。為了管理OpenCL程序,下面的一些對象都要和Context關(guān)聯(lián)起來:
—設(shè)備(Devices):執(zhí)行Kernel程序?qū)ο蟆?/span>
—程序?qū)ο?#xff08;Program objects): kernel程序源代碼
—Kernels:運(yùn)行在OpenCL設(shè)備上的函數(shù)。
—內(nèi)存對象(Memory objects): device處理的數(shù)據(jù)對象。
—命令隊列(Command queues): 設(shè)備之間的交互機(jī)制。
?????? 注意:創(chuàng)建一個Context的時候,我們必須把一個或多個設(shè)備和它關(guān)聯(lián)起來。對于其它的OpenCL資源,它們創(chuàng)建時候,也要和Context關(guān)聯(lián)起來,一般創(chuàng)建這些資源的OpenCL函數(shù)的輸入?yún)?shù)中,都會有Context。
這個函數(shù)中指定了和Context關(guān)聯(lián)的一個或多個設(shè)備對象,properties參數(shù)指定了使用的平臺,如果為NULL,廠商選擇的缺省值被使用,這個函數(shù)也提供了一個回調(diào)機(jī)制給用戶提供錯誤報告。
現(xiàn)在的代碼如下:
1: #include "stdafx.h"2: #include <CL/cl.h>3: #include <stdio.h>4: #include <stdlib.h>5: 6: #pragma comment (lib,"OpenCL.lib")7: 8: int main(int argc, char* argv[])9: {10: cl_uint status;11: cl_platform_id platform;12: 13: status = clGetPlatformIDs( 1, &platform, NULL );14: 15: cl_device_id device;16: 17: clGetDeviceIDs( platform, CL_DEVICE_TYPE_GPU,18: 1,19: &device,20: NULL);21: cl_context context = clCreateContext( NULL,22: 1,23: &device,24: 25: 26: return 0;27: }
接下來,我們要看下命令隊列。在OpenCL中,命令隊列就是主機(jī)的請求,在設(shè)備上執(zhí)行的一種機(jī)制。Kernel執(zhí)行前,我們一般要進(jìn)行一些內(nèi)存拷貝的工作,比如把主機(jī)內(nèi)存中的數(shù)據(jù)傳輸?shù)皆O(shè)備內(nèi)存中。
另外要注意的幾點(diǎn)就是:對于不同的設(shè)備,它們都有自己的獨(dú)立的命令隊列;命令隊列中的命令(kernel函數(shù))可能是同步的,也可能是異步的,它們的執(zhí)行順序可以是有序的,也可以是亂序的。
命令隊列在device和context之間建立了一個連接。
命令隊列properties指定以下內(nèi)容:
- 是否亂序執(zhí)行(在AMD GPU中,好像現(xiàn)在還不支持亂序執(zhí)行)
- 是否啟動Profiling。Profiling通過事件機(jī)制來得到kernel執(zhí)行時間等有用的信息,但它本身也會有一些開銷。
如下圖所示,命令隊列把設(shè)備和context聯(lián)系起來,盡管它們之間不是物理連接。
1: #include "stdafx.h"2: #include <CL/cl.h>3: #include <stdio.h>4: #include <stdlib.h>5: 6: #pragma comment (lib,"OpenCL.lib")7: 8: int main(int argc, char* argv[])9: {10: cl_uint status;11: cl_platform_id platform;12: 13: status = clGetPlatformIDs( 1, &platform, NULL );14: 15: cl_device_id device;16: 17: clGetDeviceIDs( platform, CL_DEVICE_TYPE_GPU,18: 1,19: &device,20: NULL);21: cl_context context = clCreateContext( NULL,22: 1,23: &device,24: NULL, NULL, NULL);25: 26: cl_command_queue queue = clCreateCommandQueue( context,27: device,28: CL_QUEUE_PROFILING_ENABLE, NULL );29: 30: return 0;31: }
總結(jié)
以上是生活随笔為你收集整理的OpenCL编程入门的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DP之八
- 下一篇: 【.NET特供-第三季】ASP.NET