cpp檔案呼叫CUDA .cu檔案實現顯示卡加速相關程式設計
阿新 • • 發佈:2019-02-15
入門cuda遇到的不錯點撥文,故轉載如下:
本篇文章談的是cpp檔案如何呼叫CUDA的.cu檔案實現顯示卡加速的相關程式設計。當然,這是在預設已經配置好CUDA的情況下進行的,如果對於如何配置CUDA還有疑問可以看之前寫的這一篇文章。另外,現在CUDA已經放出了支援VS2013的6.5版本,所以還是建議用最新的,畢竟VS2013好用太多,配置起來也沒什麼區別。關於那篇配置文章,並沒有解決CUDA相關函式偶有錯誤提示的問題,雖然對於編譯沒有影響,但是對於有強迫症的人來說還是比較糾結的,本人研究過後會更新,望周知。
關於如何通過cpp檔案呼叫CUDA的.cu檔案實現顯示卡加速相關程式設計的問題,有兩種方法。本篇先談的是根據VS2013模板建立CUDA工程(安裝6.5版本CUDA後可看到)然後再加入cpp檔案的這一種方法。至於另外的在MFC或者win32工程等新增.cu檔案再進行呼叫這種其實本質上是差不多的,會比較麻煩,本人後面有時間再更新。
在主題開始之前,先說下如何呼叫CUDA進行顯示卡加速,其實大的方向是十分簡單的。流程大致如下:
初始化顯示卡記憶體->將主機待處理的記憶體資料拷貝到顯示卡記憶體中->利用顯示卡處理相關的資料->將處理完成的顯示卡記憶體資料拷回主機記憶體
OK,下面進入主題
首先建立CUDA工程,工程建立完成之後會有一個.cu檔案,將檔案的內容替換成如下內容然後在工程中新增main.h檔案,新增如下內容#include "cuda_runtime.h" #include "device_launch_parameters.h" #include "main.h" inline void checkCudaErrors(cudaError err)//錯誤處理函式 { if (cudaSuccess != err) { fprintf(stderr, "CUDA Runtime API error: %s.\n", cudaGetErrorString(err)); return; } } __global__ void add(int *a,int *b,int *c)//處理核函式 { int tid = blockIdx.x*blockDim.x+threadIdx.x; for (size_t k = 0; k < 50000; k++) { c[tid] = a[tid] + b[tid]; } } extern "C" int runtest(int *host_a, int *host_b, int *host_c) { int *dev_a, *dev_b, *dev_c; checkCudaErrors(cudaMalloc((void**)&dev_a, sizeof(int)* datasize));//分配顯示卡記憶體 checkCudaErrors(cudaMalloc((void**)&dev_b, sizeof(int)* datasize)); checkCudaErrors(cudaMalloc((void**)&dev_c, sizeof(int)* datasize)); checkCudaErrors(cudaMemcpy(dev_a, host_a, sizeof(int)* datasize, cudaMemcpyHostToDevice));//將主機待處理資料記憶體塊複製到顯示卡記憶體中 checkCudaErrors(cudaMemcpy(dev_b, host_b, sizeof(int)* datasize, cudaMemcpyHostToDevice)); add << <datasize / 100, 100 >> >(dev_a, dev_b, dev_c);//呼叫顯示卡處理資料 checkCudaErrors(cudaMemcpy(host_c, dev_c, sizeof(int)* datasize, cudaMemcpyDeviceToHost));//將顯示卡處理完資料拷回來 cudaFree(dev_a);//清理顯示卡記憶體 cudaFree(dev_b); cudaFree(dev_c); return 0; }
#include<time.h>//時間相關標頭檔案,可用其中函式計算影象處理速度
#include <iostream>
#define datasize 50000
下面新增main的實現檔案cpp,在cpp中實現對於CUDA的.cu檔案的呼叫。內容如下
需要注意的是,在用來被呼叫的CUDA函式中要加上extern "C" 的宣告,並在cpp檔案中進行宣告(extern "C" int runtest(int *host_a, int *host_b, int *host_c);)後再呼叫。#include "main.h" extern "C" int runtest(int *host_a, int *host_b, int *host_c);//顯示卡處理函式 int main() { int a[datasize], b[datasize], c[datasize]; for (size_t i = 0; i < datasize; i++) { a[i] = i; b[i] = i*i; } long now1 = clock();//儲存影象處理開始時間 runtest(a,b,c);//呼叫顯示卡加速 printf("GPU執行時間為:%dms\n", int(((double)(clock() - now1)) / CLOCKS_PER_SEC * 1000));//輸出GPU處理時間 long now2 = clock();//儲存影象處理開始時間 for (size_t i = 0; i < datasize; i++) { for (size_t k = 0; k < 50000; k++) { c[i] = (a[i] + b[i]); } } printf("CPU執行時間為:%dms\n", int(((double)(clock() - now2)) / CLOCKS_PER_SEC * 1000));//輸出GPU處理時間 /*for (size_t i = 0; i < 100; i++)//檢視計算結果 { printf("%d+%d=%d\n", a[i], b[i], c[i]); }*/ getchar(); return 0; }
到此本篇的第一大部分就做完了,編譯執行可以看到GPU在處理複雜平行計算的時候的確比CPU快的多。關於前面提到的另外一種方法下次再談吧,假期要結束了,額。。。
好吧,距上面文章完成已經半年之久,來填坑了,另一種方法的部落格地址在這裡。