標籤:style http io os 使用 ar 檔案 資料 sp
CUDA的軟體堆棧由以下三層構成:CUDA Library、CUDA runtime API、CUDA driver API,,CUDA的核心是CUDA C語言,它包含對C語言的最小擴充集和一個執行階段程式庫,使用這些擴充和執行階段程式庫的源檔案必須通過nvcc編譯器進行編譯。
CUDA C語言編譯得到的只是GPU端代碼,而要管理分配GPU資源,在GPU上分配顯存並啟動核心功能,就必須藉助CUDA運行時的API(runtime API)或者CUDA驅動API(driver API)來實現。在一個程式中只能使用CUDA運行時API與CUDA驅動API中的一種,不能混和使用。
一、CUDA C語言
CUDA C語言為程式提供了一種用C語言編寫裝置端代碼的編程方式,包括對C的一些必要擴充和一個執行階段程式庫。CUDA對C的擴充主要包括以下幾個方面
1.引入了函數類型限符。用來規定函數是在host還是在device上執行,以及這個函數是從host調用還是從device調用。這些限定符有:__device__,__host__,__global__.
2.引入了變數類型限定符。用來規定變數被儲存在哪一類儲存空間上。傳統的在CPU上啟動並執行程式,編譯器能自動決定將變數儲存在CPU的寄存器還是記憶體中,在CUDA編程模型中,一共抽象出來多棕8種不同的儲存空間。為了區分各種儲存空間,必須引入一些限定符,包括:__device__,__shared__和__constant__。注意,此處的__device__與上節中的__device__限定符的含義不同。
3.引入了內建變數類型。如char4,ushort3,double2,dim3等,它們是由基本的整型可浮點型構成的向量類型,通過x,y,z,w訪問每一個分量,在裝置端代碼中各向量類型有不同的對齊要求。
4.引入了4個內建變數。blockIdx和threadIdx用於索引線程塊和線程,gridDim和blockDim用於描述線程網格和線程塊的維度。warpZize用於查詢warp中的線程數量。
5.引入了<<< >>>運算子。用於指定線程網格和線程維度,傳遞執行參數。
6.引入了一些函靈敏:memory fence函數,同步函數,數學函數,紋理函數,測時函數,原子函數,warp vote函數。
以上擴充均有一些限制,如果違背了這些限制,nvcc將給出錯誤或警告資訊,但有時也不會報錯,程式無法運行。
二、nvcc編譯器
nvcc編譯器根據配置編譯CUDA C代碼,可以產生三種不同的輸出:PTX,CUDA二進位序列和標準C。nvcc是一種編譯驅動。通過命令列選項,nvcc可以在編譯的不同階段啟動不同的工具完成編譯工作。
nvcc工作的基本流程是:首先通過CUDAfe分離源檔案中的主機端和裝置端代碼,然後再調用不同的編譯器分別編譯。裝置端代碼由nvcc編譯成ptx代碼或者二進位代碼;主機端代碼則將以C檔案形式輸出,由其他主效能編譯器,舊ICC,GCC或者其他合適的高效能編譯器等進行編譯。不過,也可以直接在編譯的最後階段,將主機端代碼交給其他編譯器產生.obj或者.o檔案。在編譯時間,可以將裝置端代碼連結到所產生的主機端代碼,將其中的cubin對象作為全域初始化資料數組包含進來。此時,核心執行配置也要被轉換為CUDA運行啟動代碼,以載入和啟動編譯後的核心功能。使用CUDA驅動API時,可以單獨執行ptx代碼或者cubin對象,而忽略nvcc編譯得到的主機端代碼。
編譯器前端按照C++文法規則對CUDA源檔案進行處理。CUDA主機端代碼可以支援完整的C++文法,而裝置端代碼則不能完全支援。
核心功能可能通過PTX編寫,但通常還是通過CUDA C一類的進階語言進行編寫。PTX或CUDA C語言編寫的核心功能都必須通過nvcc編譯器編譯成二進位代碼。一部分PTX指令只能在擁有較高計算能力的硬體上執行,比如對全域儲存空間的32bit原子操作指令就只有計算能力1.1以上的硬體才能支援,雙精確度計算只有計算能力1.3以上的硬體才能支援。nvcc通過編譯選項來指定要輸出的PTX代碼的計算能力。因此,在需要雙精確度計算時,就必須加上-arch sm_13(或者更高計算能力)編譯選項才能正常運行,否則雙精確度計算將被編譯為間精度的計算。
三、運行時API與驅動API
CUDA runtime API和CUDA driver API提供了實現裝置管理(Device management),上下文管理(Context management),儲存空間管理費用(Memory Control),代碼塊管理 (Code Module management),執行控制(Excution Control),紋理索引管理(Texture Reference management)與OpenGL和Direct3D的互通性(Interoperity with OpenGL and Direct3D)的應用程式介面。
CUDA runtime API在CUDA driver API 的基礎上進行了封裝,隱藏了一些實現細節,編程更加方便,代碼更加簡潔。CUDA runtime API被打包放在CUDAArt包裡,其中的函數都有CUDA 首碼。CUDA運行時沒有專門的初始化函數,它將在第一次調用函數時自動完成初始化。對使用運行時函數的CUDA程式測試時要避免將這段初始化的時間計入。CUDA runtime API的編程較為簡潔,通常都會用這種API進行開發。
CUDA driver API是一種基於控制代碼的底層介面(式多個物件通過控制代碼被引用),可以載入二進位或彙編形式的核心功能模組,指定參數,並啟動計算。CUDA driver API的編程複雜,但有時能通過直接操作硬體的執行實行一些更加複雜的功能鍵,或者獲得更高的效能。由於它使用的裝置端代碼是二進位或者彙編代碼,因此可以在各種語言中調用。CUDA driver API被放在nvCUDA包裡,所有函數首碼為cu。
四、CUDA函數庫
目前CUDA中有CUFFT,CUBLAS和CUDPP三個函數庫,提供了簡單高效的常用函數。未來,CUDA中還會提供視頻編解碼與影像處理庫等,如CUVID,進一步擴充功能。CUFFT是利用GPU進行傅立葉變換的函數庫,提供了與廣泛使用的FFTW庫相似的介面。不同的是FFTW操作的資料存放區在內在中,而CUFFT操作的資料存放區在顯存,不能直接相互取代,必須加入顯存與記憶體之間的資料交換,進行封裝後才能替代FFTW庫。CUBLAS庫是一個基本的矩陣與向量運算庫,提供了與BLAS相似的介面,可以用於簡單的矩陣計算,也可以作為基礎構建更加複雜的函數包,如LAPACK等,CUBLAS操作的資料也儲存在顯存中,同樣需要封裝後才能替代BLAS中的函數。CUDPP為提供了很多基本的常州用的並行操作靈敏,如排序、搜尋等,可以作為基本組件快速地搭建出並行計算程式。調用上述函數庫使得程式員無須按照硬體特性設計複雜的演算法就能獲得很高的效能,大大縮短開發時間;缺點是上述函數庫靈活性稍差,並且有可能造成多餘的儲存空間訪問。
CUDA的軟體體系