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数据,此时就要逐行注释核函数的语句,比较耗费时间。