1. 簡介
OpenCL(Open Computing Language),即開放運算語言,是一個統一的開放式的開發平臺。OpenCL是首個提出的并行開發的開放式的、兼容的、免費的標準,它的目的是為異構系統通用提供統一開發平臺。OpenCL最初是由蘋果公司設想和開發,并在與AMD,IBM,英特爾和NVIDIA技術團隊的合作之下初步完善。隨后,蘋果將這一草案提交至Khronos Group。
2.框架組成
OpenCL的框架組成可以劃分為三個部分,分別為OpenCL平臺API、OpenCL運行時API,以及OpenCL內核編程語言。
2.1 平臺API
平臺(Platform)這個詞在OpenCL中擁有非常特定的含義,它表示的是宿主機、OpenCL設備和OpenCL框架的組合。多個OpenCL平臺可以共存于一臺異構計算機。舉個例子,CPU開發人員和GPU開發人員可以在同一個系統上分別定義自己的OpenCL框架。這時就需要一種方法來查詢系統中可用的OpenCL 框架,哪些OpenCL設備是可用的,以及這些OpenCL設備的特性。相當于CUDA的主機和設備之間的關系。
此外,為了形成一個給定的OpenCL應用平臺,還需要對這些框架和設備所屬的子集進行控制。這些功能都是由OpenCL平臺API中的函數來解決的。此外,平臺API還提供了為OpenCL創建上下文的函數。OpenCL的上下文規定了OpenCL應用程序的打開方式(相當是CUDA中核函數的調用),這可以在宿主機程序代碼中得到驗證。
2.2 運行時API
平臺API提供函數創建好上下文之后,運行時API主要提供使用上下文提供的功能滿足各種應用需求的函數。這是一個規模龐大且內容十分復雜的函數集。運行時API的第一個任務是創建一個命令隊列。命令隊列與設備相關聯,而且一個上下文中可以同時存在多個活動的命令隊列。有了命令隊列,就可以通過調用運行時API提供的函數來進行內存對象的定義以及管理內存中的對象所依賴的所有其他對象。以上是內存對象的持有操作,另外還有釋放操作,也是由運行時API提供的。
此外,運行時API還提供了創建動態庫所需要的程序對象的函數,正是這些動態庫實現了Kernel的定義。最后,運行時層的函數會發出與命令隊列交互的命令。此外,管理數據共享和對內核的執行加以限制同步點也是由運行時API處理的。
2.3 內核編程語言
內核編程語言是用于編寫OpenCL內核代碼的。除了宿主機程序之外,內核程序也十分重要,它負責完成OpenCL中的實際工作。在部分OpenCL實現中用戶可以跟其他語言編寫的原生內核實現交互,但多數情況下內核是需要用戶使用內核編程語言編寫實現的。OpenCL C編程語言就是OpenCL中的內核編程語言,該編程語言是"ISO C99 標準"的一個擴展子集,也就是說它是由 ISO C99語言派生而來的。現在的OpenCL2.1還支持C++,是基于eISO/IEC JTC1 SC22 WG21 N 3690(C++14)。
2.4 適合平臺
1)AMD
根據AMD官網所提供的內容,OpenCL在AMD顯卡中只能適用X86核心的CPU架構,而對其他PowerPC和ARM架構則不適用;并且也不是所有的AMD顯卡都能運行OpenCL,按其官網介紹只能是AMD Radeon、AMD FirePro和AMD Firestream三種類型的顯卡;但對于操作系統則可以是Linux或Windows的系統。
2)NVIDIA
NVIDIA OpenCL是一種運行于具有CUDA能力GPU上的一種底層API,即OpenCL是運行于CUDA之上的一種API,從而若適用CUDA的平臺,也同樣適用OpenCL。根據NVIDIA官網最新版本的CUDA 7.5適合的平臺。
3.計算架構
OpenCL 的設計目標是為開發人員提供一套移植性強且高效運行的解決方案。為了更好的描述OpenCL設計的核心理念,Khronos Group官方將OpenCL的計算架構分解成四個模型,分別平臺模型(Platform Model)、內存模型(Memory Model)、執行模型(Execution Model)以及編程模型(Programming Model)。
3.1 平臺模型(Platform Model)
從整體上來看,主機(host)端是負責掌管整個運算的所有計算資源,因此OpenCL 應用程序首先是由主機端開始,然后由程序將各個計算命令從主機端發送給每個 GPU 設備處理單元,運行完畢之后最后由主機端結束。
從圖中可以直觀的看到,最基本處理單位是Processing Element,簡稱PE(處理單元),而一個或多個PE組成了Compute Unit,簡稱CU(計算單元),進而一個或多個CU就組成了Compute Device,即OpenCL設備。最后,一個或多個OpenCL設備連接到主機,并等待著處理主機發送的計算指令,由于PE是最基本處理單位,因此每條計算指令最終都歸PE進行處理,而PE是在CU中的。
3.2 內存模型(Memory Model)
OpenCL將內核程序中用到的內存分為圖示的四種不同的類型。
其中它們的讀寫特性分別為:
- Global memory:工作區內的所有工作節點都可以自由的讀寫其中的任何數據。OpenCL C語言提供了全局緩存(Global buffer)的內建函數。
- Constant memory: 工作區內的所有工作節點可以讀取其中的任何數據但不可以對數據內容進行更改,在內核程序的執行過程中保持不變。主機端負責分配和初始化常量緩存(Constant buffer)。
- Local memory: 只有同一工作組中的工作節點才可以對該類內存進行讀寫操作。它既可以為 OpenCL 的執行分配一塊私有內存空間,也可以直接將其映射到一塊全局緩存(Global buffer)上。特點是運行速度快。
- Private memory: 只有當前的工作節點能對該內存進行訪問和讀寫操作。一個工作節點內部的私有緩存(Private buffer)對其他節點來說是不可見的。
3.3 執行模型(Execution Model)
OpenCL的執行模型是應用程序通過主機端對OpenCL設備端上的內核程序進行管理,該模型分為兩個模塊:一個是在主機端執行的管理程序,也稱為Hostprogram,另一個是主機端的Hostprogram所管理的在OpenCL上執行的程序,也被稱作Kernels。在執行Kernels前,先要建立一個索引空間,來對設備里的每個節點進行標識,每個節點都將執行相同的kernel程序。在每個工作組中,都有一個局部ID,每個節點在全局里還有個全局 ID,OpenCL使用NDRange來定義這個索引空間。
如圖示的OpenCL執行模型,其過程可以細分為如下的步驟完成:
- 查詢連接主機上的OpenCL設備;
- 創建一個關聯到OpenCL設備的context;
- 在關聯的設備上創建可執行程序;
- 從程序池中選擇kernel程序;
- 從主機或設備上創建存儲單元;
- 如果需要將主機的數據復制到OpenCL設備上的存儲單元上;
- 執行kernel程序執行;
- 從OpenCL設備上復制結果到主機上
3.4 編程模型(Programming Model)
OpenCL支持兩種編程模型,分別為數據并行編程模型和任務并行編程模型,并支持上面由這兩種編程模型混合的混合編程模型。
數據并行編程模型
OpenCL提供一個分層的數據并行編程模型,即典型的SIMD計算模型,其特點是每個數據經由同樣的指令序列處理,而處理數據的次序是不確定的,并且每個數據的處理是不相干的,即任一線程的計算不得依賴于其它線程的結果(包括中間結果)。任務并行編程模型
任務并行模型中的每個內核是在一個獨立的索引空間中執行的,也就是說,執行內核的計算機單元內只有一個工作組,其中只有一個工作項。在這樣的模型中,每個線程都可以執行不同的帶啊,著相當于MIMD的計算模型,適合多核心CPU。