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

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,同样异常

 

 

在一个核函数里不用for (g_idx = bid * THREAD_NUM + tid; g_idx < nPixelNum; g_idx += THREAD_NUM * BLOCK_NUM),直接写普通函数,得出来的值是不对的,不知为啥。

 

gpu 程序目前本人没有debug 成功,唯一的调试方法是核函数外转成cpu数据,此时就要逐行注释核函数的语句,比较耗费时间。

你可能感兴趣的:(C++)