OpenCL入門(一):簡單概念
這段時間一直在進行OpenCL方面的學習。感覺OpenCL是一個非常厲害的程式開發體系,他的作用就是使用同一套語言開發出來的程式在不同的平臺上都可以跑。
OpenCL現在主要用於並行開發,並行的意義就是很多處理器拿著不同的原材料做完全相同的處理得到不同的結果。這個“同時”的好處在於,由於處理過程完全相同,那麼我直接將任務分發給所有可以執行這項任務的單元,這樣所有人都可以獨立地進行處理。背景理解可以參考這邊文章:連結
OpenCL執行包含2個環境(也叫2個端):主機端(host)和裝置端(device)。
host端絕大部分情況就是我們所說的CPU;裝置端則是那些支援OpenCL的裝置,比如顯示卡、FPGA等。他們的作用分別是:主機端負責排程任務,是指揮的角色;裝置則負責具體的並行處理,是勞動者的角色。
下面,我通過梳理OpenCL通用的開發流程來說明上面這些東西的意義:
(1)找平臺Platform(在Host端執行)
找平臺Platform基本等同於找當前Host端(裝CPU的那臺電腦上)有幾個OpenCL開發環境,比如你有NVIDIA的CUDA環境就算一個CUDA的Platform,你有Altera的OpenCL環境就算Altera的platform。換句話說,找Platform就是找你那個支援OpenCL的裝置是哪家公司的產品,基本上一家公司就算一個platform(當然也不排除1家公司多個platform的情況)。
(2)找裝置Device(在Host端執行)
找到平臺Platform後,你確定了主機上有哪些公司提供的OpenCL開發環境了,接下來,你需要確定你電腦上可以用於並行處理的裝置有哪些,比如安裝好的顯示卡和安裝好的FPGA板(當然驅動配置好是前提)。
(3)建立上下文Context(在Host端執行)
在我看來,上下文這個東西就像是你召集小夥伴開會需要一個名目一樣,比如以煮飯為目的召集一幫人來幹活,一部分人負責買菜,一部分做菜。這個煮飯的名目就算是一個上下文,在這個上下文內(名目下)不同裝置(負責不同大任務的人群)才有相互協作的理由。
(4)建立命令佇列Command_queue(在Host端執行)
依照煮飯的那個例子,有一個協同工作的名目之後,每一個部分的人就要開始自己的工作了(相當於裝置準備開始處理了)。此時,這些人就需要為自己負責的部分列一個任務清單,比如做菜的那部分人列的清單是先做什麼菜,先炒什麼配料等,這些小任務的先後順序在這個清單中有先後規定。命令佇列就是這樣的清單,它裡面說明了裝置執行任務處理的先後順序。
(5)建立3大物件(在Host端執行)
OpenCL開發是面向物件的程式開發,所以接下來需要搞定3大物件:建立記憶體物件、建立並編譯程式物件、建立核心物件。
建立記憶體物件就相當於你煮飯需要準備原料一樣,進行任務處理之前你需要把要用到的資料準備好(並放置到相應的位置),資料就是以記憶體物件的形式進行準備和放置。
建立和編譯程式物件只能通過程式開發的角度進行理解。以編寫helloWorld程式為例,你需要先寫一份cpp程式碼,然後編譯成exe檔案再執行。那麼建立和編譯程式物件就是這樣一個過程,只是面向物件的OpenCL程式設計將程式物件化了。
建立核心物件則是從編譯好的程式物件中將單獨的編譯好的OpenCL核心函式拿出來。這樣看來,一個.cl檔案裡面可以包含很多kernel函式(也就是核心函式),那麼由這個.cl檔案編譯而成的就是程式物件,裡面每一個kernel函式都被編譯成單獨的kernel物件。
(6)設定核心引數(在Host端執行)
現在核心函式已經編譯好了,但是此時的核心函式是外部的檔案,這個檔案在執行時可能需要傳引數進去(與執行含引數的函式原理一樣,需要傳外部引數進去)。所以你需要在主機上指定這些kernel函式在執行時需要傳哪些引數進去。
(7)執行核心引數(在Device端執行)
一切準備就緒,裝置就開始按照命令佇列裡面的順序開始給具體的處理單元分發任務了。在煮飯的例子中,負責一個具體任務的人群(對應一個裝置)開始給下面每一個人都分配任務,如果此時任務清單(對應命令佇列)上說此時的任務時切菜,那麼每一個人(對應每一個處理單元)就從準備好的材料(對應記憶體物件)中拿出一份菜(對應具體資料)出來同時做同樣的切菜過程(對應執行同一份kernel函式)。
上述就是OpenCL程式開發中最基本的7個流程。可以看出準備工作都是在Host主機端完成的,只有具體的並行任務才交給了裝置來執行。