生活随笔
收集整理的這篇文章主要介紹了
CUDA从入门到精通(四):加深对设备的认识
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
CUDA從入門到精通(四):加深對設備的認識
2013-07-23 13:17?
4211人閱讀??
收藏?
舉報
?
分類: GPU(29)?
版權聲明:本文為卜居原創文章,未經博主允許不得轉載。卜居博客地址:http://blog.csdn.net/kkk584520
前面三節已經對CUDA做了一個簡單的介紹,這一節開始真正進入編程環節。
首先,初學者應該對自己使用的設備有較為扎實的理解和掌握,這樣對后面學習并行程序優化很有幫助,了解硬件詳細參數可以通過上節介紹的幾本書和官方資料獲得,但如果仍然覺得不夠直觀,那么我們可以自己動手獲得這些內容。
?
以第二節例程為模板,我們稍加改動的部分代碼如下:
[cpp]?view plaincopy print?
????? ???cudaError_t?cudaStatus;?? int?num?=?0;?? cudaDeviceProp?prop;?? cudaStatus?=?cudaGetDeviceCount(&num);?? for(int?i?=?0;i<num;i++)?? {?? ????cudaGetDeviceProperties(&prop,i);?? }?? cudaStatus?=?addWithCuda(c,?a,?b,?arraySize);??
這個改動的目的是讓我們的程序自動通過調用cuda API函數獲得設備數目和屬性,所謂“知己知彼,百戰不殆”。
cudaError_t 是cuda錯誤類型,取值為整數。
cudaDeviceProp為設備屬性結構體,其定義可以從cuda Toolkit安裝目錄中找到,我的路徑為:C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.0\include\driver_types.h,找到定義為:
[cpp]?view plaincopy print?
? ? ?? struct?__device_builtin__?cudaDeviceProp?? {?? ????char???name[256];???????????????????? ????size_t?totalGlobalMem;??????????????? ????size_t?sharedMemPerBlock;???????????? ????int????regsPerBlock;????????????????? ????int????warpSize;????????????????????? ????size_t?memPitch;????????????????????? ????int????maxThreadsPerBlock;??????????? ????int????maxThreadsDim[3];????????????? ????int????maxGridSize[3];??????????????? ????int????clockRate;???????????????????? ????size_t?totalConstMem;???????????????? ????int????major;???????????????????????? ????int????minor;???????????????????????? ????size_t?textureAlignment;????????????? ????size_t?texturePitchAlignment;???????? ????int????deviceOverlap;???????????????? ????int????multiProcessorCount;?????????? ????int????kernelExecTimeoutEnabled;????? ????int????integrated;??????????????????? ????int????canMapHostMemory;????????????? ????int????computeMode;?????????????????? ????int????maxTexture1D;????????????????? ????int????maxTexture1DMipmap;??????????? ????int????maxTexture1DLinear;??????????? ????int????maxTexture2D[2];?????????????? ????int????maxTexture2DMipmap[2];???????? ????int????maxTexture2DLinear[3];???????? ????int????maxTexture2DGather[2];???????? ????int????maxTexture3D[3];?????????????? ????int????maxTextureCubemap;???????????? ????int????maxTexture1DLayered[2];??????? ????int????maxTexture2DLayered[3];??????? ????int????maxTextureCubemapLayered[2];?? ????int????maxSurface1D;????????????????? ????int????maxSurface2D[2];?????????????? ????int????maxSurface3D[3];?????????????? ????int????maxSurface1DLayered[2];??????? ????int????maxSurface2DLayered[3];??????? ????int????maxSurfaceCubemap;???????????? ????int????maxSurfaceCubemapLayered[2];?? ????size_t?surfaceAlignment;????????????? ????int????concurrentKernels;???????????? ????int????ECCEnabled;??????????????????? ????int????pciBusID;????????????????????? ????int????pciDeviceID;?????????????????? ????int????pciDomainID;?????????????????? ????int????tccDriver;???????????????????? ????int????asyncEngineCount;????????????? ????int????unifiedAddressing;???????????? ????int????memoryClockRate;?????????????? ????int????memoryBusWidth;??????????????? ????int????l2CacheSize;?????????????????? ????int????maxThreadsPerMultiProcessor;?? };??
后面的注釋已經說明了其字段代表意義,可能有些術語對于初學者理解起來還是有一定困難,沒關系,我們現在只需要關注以下幾個指標:
name:就是設備名稱;
totalGlobalMem:就是顯存大小;
major,minor:CUDA設備版本號,有1.1, 1.2, 1.3, 2.0, 2.1等多個版本;
clockRate:GPU時鐘頻率;
multiProcessorCount:GPU大核數,一個大核(專業點稱為流多處理器,SM,Stream-Multiprocessor)包含多個小核(流處理器,SP,Stream-Processor)
?
編譯,運行,我們在VS2008工程的cudaGetDeviceProperties()函數處放一個斷點,單步執行這一函數,然后用Watch窗口,切換到Auto頁,展開+,在我的筆記本上得到如下結果:
可以看到,設備名為GeForce 610M,顯存1GB,設備版本2.1(比較高端了,哈哈),時鐘頻率為950MHz(注意950000單位為kHz),大核數為1。在一些高性能GPU上(如Tesla,Kepler系列),大核數可能達到幾十甚至上百,可以做更大規模的并行處理。
PS:今天看SDK代碼時發現在help_cuda.h中有個函數實現從CUDA設備版本查詢相應大核中小核的數目,覺得很有用,以后編程序可以借鑒,摘抄如下:
[cpp]?view plaincopy print?
?? inline?int?_ConvertSMVer2Cores(int?major,?int?minor)?? {?? ?????? ????typedef?struct?? ????{?? ????????int?SM;??? ????????int?Cores;?? ????}?sSMtoCores;?? ?? ????sSMtoCores?nGpuArchCoresPerSM[]?=?? ????{?? ????????{?0x10,??8?},??? ????????{?0x11,??8?},??? ????????{?0x12,??8?},??? ????????{?0x13,??8?},??? ????????{?0x20,?32?},??? ????????{?0x21,?48?},??? ????????{?0x30,?192},??? ????????{?0x35,?192},??? ????????{???-1,?-1?}?? ????};?? ?? ????int?index?=?0;?? ?? ????while?(nGpuArchCoresPerSM[index].SM?!=?-1)?? ????{?? ????????if?(nGpuArchCoresPerSM[index].SM?==?((major?<<?4)?+?minor))?? ????????{?? ????????????return?nGpuArchCoresPerSM[index].Cores;?? ????????}?? ?? ????????index++;?? ????}?? ?? ?????? ????printf("MapSMtoCores?for?SM?%d.%d?is?undefined.??Default?to?use?%d?Cores/SM\n",?major,?minor,?nGpuArchCoresPerSM[7].Cores);?? ????return?nGpuArchCoresPerSM[7].Cores;?? }?? ??
可見,設備版本2.1的一個大核有48個小核,而版本3.0以上的一個大核有192個小核!
?
前文說到過,當我們用的電腦上有多個顯卡支持CUDA時,怎么來區分在哪個上運行呢?這里我們看一下addWithCuda這個函數是怎么做的。
[cpp]?view plaincopy print?
cudaError_t?cudaStatus;?? ?? ?? cudaStatus?=?cudaSetDevice(0);?? if?(cudaStatus?!=?cudaSuccess)?{?? ????fprintf(stderr,?"cudaSetDevice?failed!??Do?you?have?a?CUDA-capable?GPU?installed?");?? ????goto?Error;?? }??
使用了cudaSetDevice(0)這個操作,0表示能搜索到的第一個設備號,如果有多個設備,則編號為0,1,2...。
再看我們本節添加的代碼,有個函數cudaGetDeviceCount(&num),這個函數用來獲取設備總數,這樣我們選擇運行CUDA程序的設備號取值就是0,1,...num-1,于是可以一個個枚舉設備,利用cudaGetDeviceProperties(&prop)獲得其屬性,然后利用一定排序、篩選算法,找到最符合我們應用的那個設備號opt,然后調用cudaSetDevice(opt)即可選擇該設備。選擇標準可以從處理能力、版本控制、名稱等各個角度出發。后面講述流并發過程時,還要用到這些API。
?
如果希望了解更多硬件內容可以結合http://www.geforce.cn/hardware獲取。
總結
以上是生活随笔為你收集整理的CUDA从入门到精通(四):加深对设备的认识的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。