CUDA與C++ 混合使用的目的是GPU加速C++程序,適合並行計算較多的情況。以下爲實現步驟:
1、確定電腦有GPU,並安裝對應版本的CUDA,配置CUDA如下:
裝好CUDA 5.5 sdk後,默認會自動添加好系統環境變量。如果有問題可能是環境變量不全,可參考網上的教程,再次配置。
2、配置VS
將bin/lib/Include仿照opencv等三方庫的配置方法進行VS配置。
關鍵:
11、右鍵工程-->生成自定義 ,將對話框中CUDA5.5前面的勾打上。
22、右鍵xx.cu文件-->屬性,在 常規-->項類型 裏面選擇CUDA C/C++(由於cu文件是由nvcc編譯的,這裏要修改編譯鏈接屬性)
至此,配置完畢。
3、CUDA與C++實現:
通過性能分析工具(如vs)找到CPU程序最耗時的多個地方,並確定耗時程序的入口函數
將CPU函數進行清理
1.將循環部分的代碼找出來。
2.將函數內所用到的數據從C++類結構變成C的結構體。
3.標準化輸入輸出,保證其爲C結構,並與原程序的數據進行無縫對接。
4.將循環內部的函數也做相同處理,最終得到C版本的且輸入輸出與原程序對接的CPU程序。
5.保證清理後的CPU程序正常正確運行。
將清理後的CPU函數變爲cuda核函數
1.申請設備內存
2.拷貝主機內存到設備內存
3.核函數計算
4.拷貝設備內存回主機內存
5.釋放資源
優化cuda核函數
性能分析
以下爲一個簡單的例子
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include<cuda.h>
bool InitCUDA(void)
{
int count = 0;
int i = 0;
cudaGetDeviceCount(&count);
if (count == 0) {
fprintf(stderr, "There is no device.\n");
return false;
}
for (i = 0; i < count; i++) {
cudaDeviceProp prop;
if (cudaGetDeviceProperties(&prop, i) == cudaSuccess) {
if (prop.major >= 1) {
break;
}
}
}
if (i == count) {
fprintf(stderr, "There is no device supporting CUDA.\n");
return false;
}
cudaSetDevice(i);
printf("CUDA initialized.\n");
cudaDeviceProp prop;
cudaGetDeviceProperties(&prop, i);
printf("Device : \" %s \" \n\n", prop.name);
return true;
}
/////.cu
__global__ void init(float *Cs, float *Ct, float *ps, float *pt, float *u, int nPixelNum) {
int g_idx;
const int bid = blockIdx.x;
const int tid = threadIdx.x;
for (g_idx = bid * THREAD_NUM + tid; g_idx < nPixelNum; g_idx += THREAD_NUM * BLOCK_NUM)
{
if (Cs[g_idx] - Ct[g_idx] >= 0)
{
u[g_idx] = 1.0f;
}
ps[g_idx] = MIN(Cs[g_idx], Ct[g_idx]);
pt[g_idx] = ps[g_idx];
}
}
extern "C" ///CUDA 通過C嵌入C++
void runMaxFlow()
{
.....
int nPixelNum = Ny*Nx;
float * dev_Cs = 0;
float * dev_Ct = 0;
........
cudaError_t cudaStatus;
// Allocate GPU buffers for three vectors (two input, one output) .
cudaStatus = cudaMalloc((void**)&dev_cvg, sizeof(float));
cudaStatus = cudaMalloc((void**)&dev_Cs, nPixelNum * sizeof(float));
.........
// Copy input vectors from host memory to GPU buffers.
cudaStatus = cudaMemcpy(dev_Cs, Cs, nPixelNum * sizeof(float), cudaMemcpyHostToDevice);
cudaStatus = cudaMemcpy(dev_Ct, Ct, nPixelNum * sizeof(float), cudaMemcpyHostToDevice);
.....
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMalloc failed!");
goto Error;
}
init << < BLOCK_NUM, THREAD_NUM >> >(dev_Cs, dev_Ct, dev_ps, dev_pt, dev_u, nPixelNum);
//調用內核核函數
cudaStatus = cudaGetLastError();
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "runMaxFlow_GPU launch failed: %s\n", cudaGetErrorString(cudaStatus));
goto Error;
}
// cudaDeviceSynchronize waits for the kernel to finish, and returns
// any errors encountered during the launch.
cudaStatus = cudaDeviceSynchronize();
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMalloc failed!");
goto Error;
}
Error://釋放內存
cudaFree(dev_Cs);
cudaFree(dev_Ct);
}
/////cpp(不用包含cu文件)
extern "C" void runMaxFlow(float *Cs, float *Ct, float *alpha, float *pars, float *u);//必須
......
runMaxFlow(Cs.data(), Ct.data(), alpha.data(), pars, u.data());//正常調用即可
......
Cuda的內存分配機制搞不清,考慮循環中多次申請、釋放內存耗時,想申請一塊全局或Static指針內存,函數中直接cudaMemcpy,程序報拷貝異常,也試着將外邊分配好的GPU內存傳入函數後再cudaMemcpy,同樣異常