根據《OpenCL Overview》與《OpenCL Technical Overview》整理編寫,由於第一次接觸OpenCL,定會有部分的專業詞彙翻譯不當,敬請指正。
1.《OpenCL Overview》整理筆記
這是一個異構的世界
OpenCL讓程序員寫單一的可移植程序,在一個異構平臺上使用所有的資源。
OpenCL使用
1. 定義平臺; 2. 在平臺上執行代碼; 3. 在內存中移動數據; 4. 編寫(和編譯)程序。
OpenCL平臺模型
一個主機(Host) +
一個或更多的計算設備
-
每個計算設備由一個或多個計算單元組成
-
每個計算單元進一步分成一個或多個處理元件
OpenCL執行模型
OpenCL應用程序運行在一個主機(host)上,主機提交工作到計算設備。
-工作項(Work
item):OpenCL上的基本工作單元
-Kernel:工作項目的代碼,基本上是個C函數
-程序(Program):收集kernel和其它函數(類似於動態庫)
-上下文(Context):工作項目執行的環境,包括設備和它們的內存與命令隊列
應用程序隊列kernel執行例子
-
順序排隊,隊列到設備
-
順序或亂序執行
OpenCL內存模型
私有內存(Private
Memory)
-
每個工作項
局部內存(Local
Memory)
-
工作組內共享
全局/常量內存(Global/Constant
Memory)
-
對所有工作組可見
主機內存(Host Memory)
-
在CPU上
內存管理是顯式的,你必須搬移數據從host
-> global -> local ... ,然後返回。
kernel編程:OpenCL C語言
ISO C99的一個子集
-
但是除了一些C99的特性,比如標準C99頭文件,函數指針,遞歸,變長數組,和位域
ISO
C99的一個超集
-
工作項和工作組
-
向量類型
-
同步
-
地址空間限定符(Address space qualifiers)
包括一大組的內建函數
-
圖像處理
-
工作項的處理
-
專門的數學函數,等等
kernel編程:數據類型
標量數據類型
- char
, uchar, short, ushort, int, uint, long, ulong, float
-
bool, intptr_t, ptrdiff_t, size_t, uintptr_t, void, half (storage)
圖像類型
- image2d_t,
image3d_t, sampler_t
向量數據類型
-
Vector lengths 2, 4, 8, & 16 (char2, ushort4, int8, float16, double2, …)
- Endian safe
- 向量長度對齊
- 向量操作
- 內建函數
建立程序對象
程序對象封裝
- 上下文
- 程序源代碼/二進制文件
-
目標設備和構建選項的列表
建立過程...
創建一個程序對象
-
clCreateProgramWithSource()
- clCreateProgramWithBinary()
OpenCL的同步:隊列與事件(Queues & Events)
事件可用於同步隊列之間的kernel執行
例子:兩個隊列,兩個設備
OpenCL總結
2. 《OpenCL Technical Overview》整理筆記
OpenCL設計需求
使用系統中的所有計算資源
-
GPU,CPU,和其它處理器作爲對等體一起編程
-
同時支持數據/任務並行計算模型
基於C的高效並行編程模型
- 抽象底層硬件細節
抽象是低層次、高性能的,但是設備可移植的
-
容易上手,但主要正對開發專家
-
生態系統基礎,沒有中間件或“便攜”函數
在嵌入式,桌面和服務器系統範圍內都可實現
- HPC(高性能計算),桌面,一個規範內的手持式型材(handheld profiles)
推動未來的硬件需求
-
浮點精度需求
-
同時適用消費和高性能計算應用
OpenCL剖析
語言規範
- 基於C的交叉平臺編程接口
- ISO
C99子集語言擴展,對開發者熟悉
- 良好定義的數值精度,IEEE
754規定最大錯誤的四捨五入行爲
- 在線或離線編輯和構建的計算內核可執行文件
- 包含一個豐富的內建函數集合
平臺層API
- 多種計算資源之上的硬件抽象層
- 查詢、選擇和初始化計算設備
- 創建計算環境和工作隊列
運行時API
-執行計算內核
-管理調度、計算和內存資源
模型的層次結構
> 內存模型
>
執行模型
>
編程模型
OpenCL平臺模型
一個主機(Host) + 一個或更多的計算設備
- 每個計算設備由一個或多個計算單元組成
- 每個計算單元進一步分成一個或多個處理元件
OpenCL執行模型
OpenCL編程
- 內核
- 執行代碼的基本單元
--- 類似C函數
- 數據並行或任務並行
- 主機編程
- 計算內核和內部函數收集
- 類似於一個動態庫
內核執行
- 主機程序通過一個叫做NDRange的索引空間調用內核
- NDRange
=“N維範圍”
- NDRange,
可以是1, 2, 或3維空間
- 一個內核實例在索引空間中的一個點稱爲一個工作項
- 工作項有來自索引空間的唯一的全局ID
- 工作項進一步組織成工作組
- 工作組具有一個唯一的工作組ID
- 工作項有在一個工作組中唯一的本地ID
內核執行
工作項的總數:Gx X Gy
每個工作組的大小:Sx X Sy
全局ID可以從工作組ID和本地ID計算得到
上下文和隊列
> 上下文(Contexts)用於控制和管理“世界”的狀態
> 內核(Kernels)在由主機定義和操作的上下文中執行
-
設備
-
內核,OpenCL函數
-
編程對象,內核源代碼及其可執行
- 內存對象
> 命令隊列,協調內核的執行
- 內核執行命令
- 內存命令,傳輸或映射內存對象數據
- 同步命令,控制命令的順序
> 應用隊列計算內核執行實例
- 順序排隊
- 順序或亂序執行
- 事件被用於實現執行實例的適當同步
OpenCL內存模型
> 共享內存模型
- 寬鬆的一致性
> 多個不同的地址空間
- 地址空間可以根據設備的內存子系統進行摺疊
> 地址空間
- 私有,專用於一個工作項
- 本地,用於局部工作組
- 全局,所有工作組中的所有工作項都可訪問
- 常量,只讀全局空間
> 實現這種映射層次
- 對於可用物理內存
內存一致性
·“OpenCL使用寬鬆的一致性內存模型;例如,對一個工作項可見的內存狀態,對於整個工作項的集合並不一直保證一致性。”
· 工作項內部,內存具有加載/存儲一致性
·同一屏障內的一個工作組,局部內存對所有工作項具有一致性
·全局內存在同一屏障內的一個工作組內具有一致性,但對於不同的工作組並不能保證一致性
·命令之間共享的內存一致性,通過同步被強制執行
數據並行編程模型
· 定義N維計算域
- 在一個N維域中的每個獨立執行單元,被稱爲工作項
- N維域定義的並行執行的工作項總數
= 全局工作大小
· 工作組可以被組織在一起
--- 工作組
- 組中的工作項可以相互通信
- 可以在組內工作項之間同步執行,以協調內存訪問
· 並行執行多個工作組
- 映射全局工作大小(global work size)到工作組,可以是顯式的或隱式的
任務並行編程模型
· 數據並行執行模型必須被所有OpenCL計算設備實現
· 一些計算設備,例如CPU也可以執行任務並行計算內核
- 像單個工作項那樣執行
- 在OpenCL中編寫的計算內核
- 本地C/C++函數
基本OpenCL編程結構
· 主機編程
平臺層
- 查詢計算設備
- 創建上下文(Contexts)
運行時
- 創建上下文相關的內存對象
- 編譯和創建內核編程對象
- 發出命令到命令隊列
- 命令同步
- 清除OpenCL資源
· 內核
語言
- 帶一些限制和擴展的C代碼
例子:向量加法
· 計算
c = a + b
- a,b和c是長度爲N的向量
· 基本的OpenCL概念
- 簡單內核代碼
- 基本上下文管理
- 內存分配
- 內核調用
平臺層
· 平臺層允許應用程序查詢平臺的特定功能
· 查詢平臺信息(例如,OpenCL配置文件)
· 查詢設備
- clGetDeviceIDs()
- 查找系統中存在哪些計算設備
- 設備類型包括CPU,GPU或加速器
- clGetDeviceInfo()
- 查詢發現計算設備的能力,例如:
- 計算核心數量
- NDRange限制
- 最大工作組大小
- 不同內存空間的大小(常量、局部變量和全局變量)
- 最大的內存對象大小
· 創建上下文
- 上下文被OpenCL運行時用於在一個或多個設備中管理對象和執行內核
- 上下文同一個或多個設備相關聯
- 多個上下文可以被關聯到相同的設備
- clCreateContext()和clCreateContextFromType()返回一個處理句柄來創建上下文
命令隊列
· 命令隊列存儲一組操作集來執行
· 命令隊列同上下文相關聯
· 多命令隊列可以被創建,用於處理不需要同步的獨立命令
· 命令隊列的執行在同步點被保證完成
向量加法:上下文、設備和隊列
內存對象
· 緩衝區對象
- 對象的一維集合(像C的數組)
- 有效的元素,包括標量和矢量類型以及用戶定義的結構
- 緩衝對象可以通過內核中的指針被訪問到
· 圖像對象
- 二維或三維紋理,幀緩衝器或圖像
- 必須通過內建函數編址
· 採樣對象
-
描述如何在內核中採樣一張圖像
- 尋址模式
- 過濾模式
創建內存對象
· clCreateBuffer(),
clCreateImage2D(), 和clCreateImage3D()
· 內存對象在一個相關的上下文中創建
· 內存可以被創建爲只讀,只寫,或讀寫
· 對象在平臺存儲空間中的創建位置可以被控制
- 設備內存
- 存有從主機指針處拷貝的數據的設備內存
- 主機內存
- 與指針相關的主機內存
- 在那個點的內存在同步點保證是有效的
· 圖像對象也用通道格式創建
- 通道順序(例如,RGB,RGBA,等)
- 通道類型(例如,UNORM
INT8,FLOAT,等)
操作對象數據
· 對象數據可以被拷貝到內存,從主機內存,或到其它對象
· 內存命令在命令緩衝區中排隊,當命令被執行時處理
- clEnqueueReadBuffer(),
clEnqueueReadImage()
- clEnqueueWriteBuffer(),
clEnqueueWriteImage()
- clEnqueueCopyBuffer(),
clEnqueueCopyImage()
· 數據可以在圖像和緩衝區對象之間拷貝
- clEnqueueCopyImageToBuffer()
- clEnqueueCopyBufferToImage()
· 對象數據的區域可以被訪問,通過映射進主機地址空間
- clEnqueueMapBuffer(),
clEnqueueMapImage()
- clEnqueueUnmapMemObject()
向量加法:創建內存對象
編程對象
· 程序對象封裝
- 一個相關的上下文
- 程序源代碼或二進制文件
- 最新成功的程序構建,目標設備列表,構建選項
- 附加的內核對象的數量
· 構建過程
1.
創建程序對象
- clCreateProgramWithSource()
- clCreateProgramWithBinary()
2.
構建程序可執行
- 從源代碼或二進制文件編譯和連接,對於所有設備或相關上下文中的特定設備
- clBuildProgram()
- 構建選項
- 預處理器
- 數學內部函數(浮點性能)
- 優化
內核對象
· 內核對象封裝
- 程序中聲明的特定內核函數
- 用於內核執行的參數值
· 創建內核對象
- clCreateKernel(),在程序中爲單個函數創建內核對象
- clCreateKernelsInProgram(),在程序中爲所有內核創建一個對象
· 設置參數
- clSetKernelArg(<kernel>,
<argument index>)
- 每個參數的數據必須在內核函數中進行設置
- 參數值被拷貝和存儲在內核對象中
· 內核與程序對象比較
- 內核與程序執行相關
- 程序與程序源碼相關
向量加法:程序與內核
向量加法:設置內核參數
內核執行
· 一個執行內核的命令,必須排隊到命令隊列
· clEnqueueNDRangeKernel()
- 數據並行執行模型
- 描述內核執行的索引空間
- 需要NDRandge()維度和工作組大小的信息
· clEnqueueTask()
- 任務並行執行模型(多隊列任務)
- 內核在單工作項上執行
· clEnqueueNativeKernel()
- 任務並行執行模型
- 執行一個未編譯的本地C/C++函數,使用OpenCL編譯器
- 此模式不使用內核對象,因此參數必須被傳遞
命令隊列和同步
· 命令隊列執行
- 執行模型信號時,命令已完成或數據已準備就緒
- 命令隊列可以明確地刷新到設備
- 命令隊列順序或亂序執行
- 順序,命令在順序隊列中完成,並且正確的內存是一致的
- 亂序,不保證當命令執行時或內存是一致性的,沒有同步的話
· 同步
- 當對主機的命令完成時的信號,或其它在隊列中的命令
- 阻塞調用
- 命令未返回直到完成
- clEnqueueReadBuffer()可以被調用作爲阻塞,將會阻塞直到完成
- 事件對象
- 跟蹤一個命令的執行狀態
- 一些命令可以阻塞指導事件對象發送一個先前命令完成的信號
- clEnqueueNDRangeKernel()將一個事件對象作爲參數,並等待直到一個先前命令(例如,clEnqueueWriteBuffer)完成
- 配置文件
- 隊列屏障,隊列命令可以阻塞命令的執行
向量加法:調用內核,讀取輸出
計算內核的OpenCL C
· 由ISO
C99派生
- 一些限制:遞歸,函數指針,C99標準頭文件中的函數
- 由C99定義的預處理指令被支持
· 內建數據類型
- 標量和常量數據類型,指針
- 數據類型轉換函數:convert_type<_sat><_roundingmode>
- 圖像類型:image2d_t,
image3d_t和sampler_t
· 內建函數
--- 必須的
- 工作項函數,math.h,讀寫圖像
- 關聯式,幾何函數,同步函數
· 內建函數
--- 可選的
- 雙精度,原子到全局和局部內存
- 舍入模式的選擇,寫到image3d_t上
OpenCL C語言函數要點
· 函數限定符
- “__kernel”限定符聲明一個函數作爲內核
- 內核可以調用其它內核函數
· 地址空間限定符
- __global,
__local, __constant, __private
-
指針內核參數必須用地址空間限定符修飾來聲明
· 工作項函數
-
查詢工作項的標識符
- get_work_dim()
- get_global_id(),
get_local_id(), get_group_id()
· 圖像函數
-
圖像必須通過內建函數來訪問
-
讀寫執行通過從主機採樣對象或在源代碼中定義
· 同步函數
- 屏蔽,組內的所有工作項必須在任何工作項可繼續之前執行屏蔽函數
-
內存柵欄,提供對存儲器操作的順序
向量加法內核
OpenCL C語言限制
· 不支持
函數指針
· 在同一個內核中,允許使用指向指針的指針,但不能作爲一個參數
· 不支持 位域
· 不支持 可變長數組和結構體
· 不支持 遞歸
· 不支持 寫入的類型小於32位的指針
· 不支持 double類型,但保留
· 不支持 3D影像寫操作
· 有些限制是通過擴展解決
可選的擴展
· 擴展是可選功能,通過OpenCL接觸
· OpenCL的工作組已經批准了由OpenCL的規格支持多種擴展功能:
· 雙精度浮點類型
· 內建函數來支持doubles
· 原子函數
· 三維圖像寫入
· 字節尋址存儲(寫指針類型<32位)
· 內建函數支持半類型
OpenGL互操作性
· 一個IP架構下兩個標準
- 使得非常密切的協作設計
· 高效的跨API通信
- 同時仍然允許這兩個API來處理其設計工作負載的類型
· OpenCL可高效地同OpenGL共享資源
- 紋理,緩衝區對象,渲染緩衝
- 數據是共享的,但不可複製
- OpenCL的對象是從OpenGL的對象創建
- clCreateFromGLBuffer(),
clCreateFromGLTexture2D(), clCreateFromGLRenderbuffer()
· 應用程序可選擇計算設備來運行OpenCL和OpenGL
- 高效地排隊OpenCL和OpenGL命令到硬件
- 靈活的調度和同步
· 舉例
- 頂點(Vertex)和圖像數據由OpenCL的生成,然後用OpenGL渲染
- 圖像由OpenGL渲染後,由OpenCL內核後處理
OpenCL總結
· 跨供應商標準的便攜式異構編程
- 開放、免費的版權標準,來自主要供應商的臨界質量支持
· 創造顯著的商業機會
- 移除作爲市場障礙的碎片化,以增加並行計算的增長
· 在Khronos的API生態系統中的核心角色
- 在Khronos,多個相關的API正被在一個IP框架下合作開發
· 快速部署
- 公開規則在六個月內產生,在2009年實現
- 將運行於目前最新一代的GPU硬件 · 更多說明書和幻燈片在www.khronos.org/opencl/
- 如果這裏講的與你公司相關,請加入Khronos並且動手!