OpenCL簡單入門介紹(根據《OpenCL Overview》翻譯整理)

  根據《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並且動手!





發佈了33 篇原創文章 · 獲贊 8 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章