CUDA编程 C++指引

时间:2022-03-21 00:57:39

简述

利用GPU显卡硬件,进行cuda C++编程,加速C++程序,适合高度并行计算的情况

环境配置

1.安装显卡驱动

CUDA编程 C++指引

2.VS2019设置

右击工程——>生成依赖项——>生成自定义 ,将对话框中CUDA前面的勾打上

CUDA编程 C++指引

添加CUDA程序文件,后缀名为.cu

CUDA编程 C++指引

右击cu文件——>属性,在 常规——>项类型 里面选择CUDA C/C++

CUDA编程 C++指引

内容

1.常用概念

  • 主机

将CPU的内存称为主机,Host

  • 设备

将GPU的显示内存称为设备,Device

  • 线程(Thread)

通过GPU的一个核进行处理

  • 线程块(Block)

由多个线程组成线程块,各block是并行执行的,block间无法通信,无执行顺序

  • 线程格(Grid)

由多个线程块组成的线程网格

  • 核函数

是在GPU上执行的函数,核函数用__global__符号声明,每个线程都会执行核函数

  • 共享内存

用__shared__关键字表示,同一个线程块内的所有线程共享该内存区域,使用__syncthreads()控制线程同步

2.运行方式

执行<<<  >>>配置指定线程运行方式,第一个参数是线程网格维度(线程块的数目),第二个参数是块维度(每个块中线程的数目);

CUDA编程 C++指引

线程分布以列为主序(从上往下)

CUDA编程 C++指引

CUDA编程 C++指引

dim3是三维数据结构,对应x(列数),y(行数),z(z默认为1),可使用亍一维、二维或三维的索引来标识线程,构成一维、二维或三维线程块;

CUDA编程 C++指引

CUDA编程 C++指引

​threadIdx,是获取线程thread的ID索引;如果线程是一维的那么就取threadIdx.x,二维的还可以多取到一个值threadIdx.y,以此类推到三维threadIdx.z;

blockIdx,线程块的ID索引;同样有blockIdx.x,blockIdx.y,blockIdx.z

blockDim,线程块的维度,同样有blockDim.x,blockDim.y,blockDim.z

gridDim,线程格的维度,同样有gridDim.x,gridDim.y,gridDim.z​

3.cu文件调用

C++不能直接调用核函数,C语言可直接调用CUDA核函数;用extern "C"可让C++函数调用

CUDA编程 C++指引


4.CUDA编程案例指引

(1)内存初始化:开辟GPU(设备Device)内存空间; 
GPUCAL::GPUCAL(int imgArrayrow, int imgArraycol)

{

cublasStatus_t status = cublasCreate(&cuHandle);

if (status != CUBLAS_STATUS_SUCCESS)

{

if (status == CUBLAS_STATUS_NOT_INITIALIZED) {

std::cout << "CUBLAS 对象实例化出错" << std::endl;

}

return;

}

imgArrayRow = imgArrayrow;

imgArrayCol = imgArraycol;

result = (int*)malloc(RESULTSIZE * sizeof(int));

cudaMalloc((void**)&dimgArray, imgArrayRow * imgArrayCol * sizeof(double));

cudaMalloc((void**)&dresult, RESULTSIZE * sizeof(int));

}
(2)拷贝数据:拷贝主机(Host)内存到设备(Device)内存;
cudaMemcpy(dimgArray, imgArray, imgArrayRow * imgArrayCol * sizeof(double), cudaMemcpyHostToDevice);
(3)多线程运算:调用cu文件的核函数进行多线程处理
void GPUCAL::MatCal(double* imgArray, int* result, double upper, double lower)

{

cudaMemcpy(dimgArray, imgArray, imgArrayRow * imgArrayCol * sizeof(double), cudaMemcpyHostToDevice);

auto starttime = system_clock::now();

SearchDefectFunc(dimgArray, imgArrayRow, imgArrayCol, upper, lower, dresult);

cudaMemcpy(result, dresult, RESULTSIZE * sizeof(int), cudaMemcpyDeviceToHost);

duration<double> dif = system_clock::now() - starttime;

std::cout << "GPU运算并取回所耗时间为:" << dif.count() << "s" << std::endl;

//for (int i = 0; i < 10; i++) {

// std::cout << result[i] << " ";

// std::cout << "dresult" << std::endl;

//}

}
(4)内存释放:回收释放开辟的设备(Device)空间和主机(Host)空间
GPUCAL::~GPUCAL(void)

{

free(result);

result = NULL;

cudaFree(dresult);

std::cout << "free GPU memory" << std::endl;

}