cuda-2-程序框架

cuda程序框架

1
2
3
4
5
6
7
8
9
10
11
12
13
头文件包含
常量定义(或者宏定义)
C++ 自定义函数和CUDA核函数的声明(原型)
int main(void)
{
分配主机与设备内存
初始化主机中的数据
将某些数据从主机复制到设备
调用核函数在设备中进行计算
将某些数据从设备复制到主机
释放主机与设备内存
}
C++自定义函数与CUDA核函数的定义(实现)

获取GPU设备数量

1
__host__ __device__ cudaError_t cudaGetDeviceCount(int* devices);

功能描述:

  • 输入参数 int* count 是一个指向整型变量的指针,用于接收当前系统的CUDA设备数量
  • 函数执行成功时,将填充 count 变量
  • 如果没有可用的CUDA设备,那么 count 将被设置为0,并返回相应的错误状态
1
2
int iDeviceCount = 0;
cudaGetDeviceCount(&iDeviceCount);

设置GPU执行时使用的设备

1
2
int iDev = 0;
cudaSetDevice(iDev);

cudaSetDevice只能在主机上运行(不然已经到GPU上哪还需要设置)

内存管理

​ CUDA通过内存分配,数据传递,内存初始化,内存释放进行内存管理

C语言 CUDA语言
malloc cudaMalloc
memcpy cudaMemcpy
memset cudaMemset
free cudaFree

数据分配:

1
__host__ __device__ cudaFrror_t cudaMalloc(void **devPtr, size_t size)
  • devPtr:用于接受分配内存的地址
  • size:用于指定内存分配的大小
1
2
3
4
5
6
// 主机分配内存:
float *fpHost_A;
fpHost_A = (float*)malloc(nBtytes);
// 设备分配内存:
float *fpDevice_A;
cudaMalloc((float**)&fpDevice_A, nBytes);

数据拷贝:

1
__host__ cudaFrror_t cudaMemcpy(void *dest, const void *src, size_t count, cudaMemcpyKind kind)
  • dest:用于接受拷贝的目的地址
  • src:用于拷贝的源地址
  • count:用于指定拷贝的长度
  • kind:用于指定拷贝从哪里到哪里,有四种可能:
Kind 拷贝方向
cudaMemcpyHostToHost 主机->主机
cudaMemcpyHostToDevice 主机->设备
cudaMemcpyDeviceToHost 设备->主机
cudaMemcpyDeviceToDevice 设备->设备
cudaMemcpyDefault 默认

​ 默认方式只允许在支持同意虚拟寻址的系统上使用(自动判断拷贝方向)

内存初始化:

1
__host__ cudaFrror_t cudaMemset(void *devPtr, int value, size_t count)
  • devPtr:用于接受内存初始化的地址
  • value:用于指定内存初始化的值
  • count:用于指定内存初始化的长度

内存释放:

1
__host__ __device__ cudaFrror_t cudaFree(void *devPtr)
  • devPtr:用于接受内存释放的地址

应用实例:cuda实现矩阵加法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include <stdio.h>

__global__ void addFromGPU(float *A, float *B, float *C, const int N)
{
const int bid = blockIdx.x;
const int tid = threadIdx.x;
const int id = tid + bid * blockDim.x;

C[id] = A[id] + B[id];

}

void initialData(float *addr, int elemCount);
void setGPU();

int main(void)
{
// 1、设置GPU设备
setGPU();

// 2、分配主机内存和设备内存,并初始化
int iElemCount = 512; // 设置元素数量
size_t stBytesCount = iElemCount * sizeof(float); // 字节数

// (1)分配主机内存,并初始化
float *fpHost_A, *fpHost_B, *fpHost_C;
fpHost_A = (float *)malloc(stBytesCount);
fpHost_B = (float *)malloc(stBytesCount);
fpHost_C = (float *)malloc(stBytesCount);
if (fpHost_A != NULL && fpHost_B != NULL && fpHost_C != NULL) {
memset(fpHost_A, 0, stBytesCount); // 主机内存初始化为0
memset(fpHost_B, 0, stBytesCount);
memset(fpHost_C, 0, stBytesCount);
}
else {
printf("Fail to allocate host memory!\n");
exit(-1);
}

// (2)分配设备内存,并初始化
float *fpDevice_A, *fpDevice_B, *fpDevice_C;
cudaMalloc((float**)&fpDevice_A, stBytesCount);
cudaMalloc((float**)&fpDevice_B, stBytesCount);
cudaMalloc((float**)&fpDevice_C, stBytesCount);
if (fpDevice_A != NULL && fpDevice_B != NULL && fpDevice_C != NULL) {
cudaMemset(fpDevice_A, 0, stBytesCount); // 设备内存初始化为0
cudaMemset(fpDevice_B, 0, stBytesCount);
cudaMemset(fpDevice_C, 0, stBytesCount);
}
else {
printf("fail to allocate memory\n");
free(fpHost_A);
free(fpHost_B);
free(fpHost_C);
exit(-1);
}

// 3、初始化主机中数据
srand(666); // 设置随机种子
initialData(fpHost_A, iElemCount);
initialData(fpHost_B, iElemCount);

// 4、数据从主机复制到设备
cudaMemcpy(fpDevice_A, fpHost_A, stBytesCount, cudaMemcpyHostToDevice);
cudaMemcpy(fpDevice_B, fpHost_B, stBytesCount, cudaMemcpyHostToDevice);
cudaMemcpy(fpDevice_C, fpHost_C, stBytesCount, cudaMemcpyHostToDevice);


// 5、调用核函数在设备中进行计算
dim3 block(32);
dim3 grid(iElemCount / 32);

addFromGPU<<<grid, block>>>(fpDevice_A, fpDevice_B, fpDevice_C, iElemCount); // 调用核函数
// cudaDeviceSynchronize();

// 6、将计算得到的数据从设备传给主机
cudaMemcpy(fpHost_C, fpDevice_C, stBytesCount, cudaMemcpyDeviceToHost);


for (int i = 0; i < 10; i++) {
printf("idx=%2d\tmatrix_A:%.2f\tmatrix_B:%.2f\tresult=%.2f\n", i+1, fpHost_A[i], fpHost_B[i], fpHost_C[i]);
}

// 7、释放主机与设备内存
free(fpHost_A);
free(fpHost_B);
free(fpHost_C);
cudaFree(fpDevice_A);
cudaFree(fpDevice_B);
cudaFree(fpDevice_C);

cudaDeviceReset();
return 0;
}


void setGPU() {
int iDeviceCount = 0;
cudaError_t error = cudaGetDeviceCount(&iDeviceCount);

if(error != cudaSuccess || iDeviceCount == 0) {
printf("no compatible GPU found\n");
exit(-1);
}
else {
printf("the count of GPU id %d\n", iDeviceCount);
}

int iDev = 0;
error = cudaSetDevice(iDev);
if (error != cudaSuccess) {
printf("fail to set GPU 0 for computing\n");
exit(-1);
}
else {
printf("set GPU 0 for computing");
}
}


void initialData(float *addr, int elemCount) {
for (int i = 0; i < elemCount; i++) {
addr[i] = (float)(rand() & 0xFF) / 10.f;
}
return;
}