CUDA與C++混合編程

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,同樣異常

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章