cuda 用CUDA对两个数组求和
示例
本示例说明了如何创建一个简单的程序,该程序将int使用CUDA对两个数组求和。
CUDA程序是异构的,由在CPU和GPU上运行的部分组成。
利用CUDA的程序的主要部分类似于CPU程序,包括
为将在GPU上使用的数据分配内存
数据从主机内存复制到GPU内存
调用内核函数来处理数据
将结果复制到CPU内存
要分配设备内存,我们使用cudaMalloc功能。可以在设备和主机之间复制数据cudaMemcpy。的最后一个参数cudaMemcpy指定复制操作的方向。有5种可能的类型:
cudaMemcpyHostToHost-主机->主机
cudaMemcpyHostToDevice-主机->设备
cudaMemcpyDeviceToHost-设备->主机
cudaMemcpyDeviceToDevice-设备->设备
cudaMemcpyDefault-基于默认的统一虚拟地址空间
接下来,调用内核函数。三重人字形之间的信息是执行配置,该配置决定了多少个设备线程并行执行内核。第一个数字(2例如)指定块数,第二个(例如)指定块(size+1)/2中的线程数。请注意,在此示例中,我们将大小加1,以便我们请求一个额外的线程,而不是让一个线程负责两个元素。
由于内核调用是异步函数,因此它cudaDeviceSynchronize被调用以等待执行完成。结果数组将复制到主机内存,并使用释放设备上分配的所有内存cudaFree。
将函数定义为内核 __global__声明说明符。每个线程都会调用此函数。如果希望每个线程处理结果数组的元素,则需要一种区分和标识每个线程的方法。CUDA定义变量blockDim,blockIdx和threadIdx。预定义变量blockDim包含内核启动的第二个执行配置参数中指定的每个线程块的尺寸。预定义的变量threadIdx和blockIdx包含的线程的它的线程块内的网格内的索引和线程块,分别。注意,由于请求的线程数可能比数组中的元素多,因此我们需要传递信息size以确保不访问数组末尾。
#include "cuda_runtime.h" #include "device_launch_parameters.h" #include <stdio.h> __global__ void addKernel(int* c, const int* a, const int* b, int size) { int i =blockIdx.x*blockDim.x+ threadIdx.x; if (i < size) { c[i] = a[i] + b[i]; } } //使用CUDA并行添加向量的辅助函数。 void addWithCuda(int* c, const int* a, const int* b, int size) { int* dev_a = nullptr; int* dev_b = nullptr; int* dev_c = nullptr; //为三个向量分配GPU缓冲区(两个输入,一个输出) cudaMalloc((void**)&dev_c, size * sizeof(int)); cudaMalloc((void**)&dev_a, size * sizeof(int)); cudaMalloc((void**)&dev_b, size * sizeof(int)); //将输入向量从主机内存复制到GPU缓冲区。 cudaMemcpy(dev_a, a, size * sizeof(int), cudaMemcpyHostToDevice); cudaMemcpy(dev_b, b, size * sizeof(int), cudaMemcpyHostToDevice); //在GPU上启动内核,每个元素只有一个线程。 //2是计算块数,(size+1)/2是一个块中的线程数 addKernel<<<2, (size + 1) / 2>>>(dev_c, dev_a, dev_b, size); //cudaDeviceSynchronize等待内核完成,然后返回 //启动过程中遇到的任何错误。 cudaDeviceSynchronize(); //将输出向量从GPU缓冲区复制到主机内存。 cudaMemcpy(c, dev_c, size * sizeof(int), cudaMemcpyDeviceToHost); cudaFree(dev_c); cudaFree(dev_a); cudaFree(dev_b); } int main(int argc, char** argv) { const int arraySize = 5; const int a[arraySize] = { 1, 2, 3, 4, 5 }; const int b[arraySize] = { 10, 20, 30, 40, 50 }; int c[arraySize] = { 0 }; addWithCuda(c, a, b, arraySize); printf("{1, 2, 3, 4, 5} + {10, 20, 30, 40, 50} = {%d, %d, %d, %d, %d}\n", c[0], c[1], c[2], c[3], c[4]); cudaDeviceReset(); return 0; }