学习cuda(1)

参考书籍《GPU高性能编程cuda实战》

我们将CPU以及主存称为主机,将GPU以及显存称为设备

来看第一个cuda程序
#include
__global__ void kernel()
{
}
int main()
{
	kernel<<<1,1>>>();
	printf("hello world\n");
	return 0;
}

和普通的C代码很相似,也有所不同。kernel()函数带有修饰符__global__;主函数中对kernel()的调用,带有修饰符<<<1,1>>>。
在GPU设备上执行的函数通常被称为核函数。其实,cuda中为标准C增加的__global__修饰符就是告诉编译器,该函数应该被交给编译设备代码的编译器,而不是主机编译器。至于调用设备代码为什么要用尖括号,我们后续再说。

传递参数

核函数当然是可以传参的,看看代码。

#include
__global__ void add(int a, int b, int *c)
{
    *c = a + b;
}

int main()
{
	int c;
	int *dev_c;
	cudaMalloc((void **)&dev_c,sizeof(int));
	add<<<1,1>>>(10,20,dev_c);
	cudaMemcpy(&c,dev_c,sizeof(int),cudaMemcpyDeviceToHost);
	printf("10+20=%d\n",c);
}

输出结果如下:
在这里插入图片描述
这里有一些要注意的点
1)当设备执行任何有用的操作时,都要分配内存。cudaMalloc非常类似C中的malloc,其目的是在设备中分配某字节大小的空间。
在本例中,dev_c指针就是设备中的分配地址,但是dev_c是存储在主存中的,因此cudaMalloc的第一个参数类型是(void **),指向指针的指针,代表了dev_c在主存中的地址。换个简单的说法就是,这块地址里面放的是dev_c,而dev_c的值是设备中分配的地址。

2)可以将设备指针传递给核函数;可以在核函数中对设备指针进行内存读写;可以将设备指针传递给主机上执行的函数;但一定不能在主机代码中对设备指针进行内存读写(解引用)

3)cudaMemcpy和memcpy类似,是内存拷贝函数。
主机到设备:cudaMemcpy(d_A,h_A,nBytes,cudaMemcpyHostToDevice)
设备到主机:cudaMemcpy(h_A,d_A,nBytes,cudaMemcpyDeviceToHost)

4)主机指针只能访问主机代码中的内存,设备指针只能访问设备代码的内存。这也是为什么调用核函数add()时,要分配dev_c,再将计算好的dev_c中的值传回主机。如果直接是&c作为参数传进核函数,则会出现设备代码访问主机内存的问题,不可。

基本练习

写了几个基本的练练手
1)swap

#include 
__global__ void swap(int *a,int *b)
{
	int t;
	t=*a;
	*a=*b;
	*b=t;
} 
int main()
{
	int a=10;
	int b=20;
	int *dev_a,*dev_b;
	cudaMalloc((void **)&dev_a,sizeof(int));
	cudaMalloc((void **)&dev_b,sizeof(int));
	cudaMemcpy(dev_a,&a,sizeof(int),cudaMemcpyHostToDevice);
	cudaMemcpy(dev_b,&b,sizeof(int),cudaMemcpyHostToDevice);
	swap<<<1,1>>>(dev_a,dev_b);
	cudaMemcpy(&a,dev_a,sizeof(int),cudaMemcpyDeviceToHost);
	cudaMemcpy(&b,dev_b,sizeof(int),cudaMemcpyDeviceToHost);
	printf("After change a is %d b is %d\n",a,b);
}

在这里插入图片描述
2)数组

#include
__global__ void change(int *a)
{
	for(int i=0;i<5;i++)
	{
		a[i]+=10;
	}
}  
int main()
{
	int k[5]={1,2,3,4,5};
	int *dev_k;
	cudaMalloc((void **)&dev_k,sizeof(int)*5);
	cudaMemcpy(dev_k,k,sizeof(int)*5,cudaMemcpyHostToDevice);
	change<<<1,1>>>(dev_k);
	cudaMemcpy(k,dev_k,sizeof(int)*5,cudaMemcpyDeviceToHost);
	for(int i=0;i<5;i++)
	{
		printf("%d\n",k[i]);
	}
}

学习cuda(1)_第1张图片
补充一个自己写的代码

#include
#include
using namespace std;
__global__ void DevAdd(int a[4][4],int b[4][4],int c[4][4])
{
	int i=blockIdx.x*blockDim.x+threadIdx.x;
	int j=blockIdx.y*blockDim.y+threadIdx.y;
	c[i][j]=a[i][j]+b[i][j];
}
int main()
{
	int a[4][4]={{1,2,3,4},{1,2,3,4},{1,2,3,4},{1,2,3,4}};
	int b[4][4]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
	int c[4][4];
	memset(c,0,4*sizeof(int[4]));
	dim3 threadPerB(2,2);
	dim3 numB(4/threadPerB.x,4/threadPerB.y);
	int (*deva)[4];
	int (*devb)[4];
	int (*devc)[4];
	cudaMalloc(&deva,4*sizeof(int[4]));
	cudaMalloc(&devb,4*sizeof(int[4]));
	cudaMalloc(&devc,4*sizeof(int[4]));
	cudaMemcpy(deva,a,4*sizeof(int[4]),cudaMemcpyHostToDevice);
	cudaMemcpy(devb,b,4*sizeof(int[4]),cudaMemcpyHostToDevice);
	DevAdd<<<numB,threadPerB>>>(deva,devb,devc);
	cudaMemcpy(c,devc,4*sizeof(int[4]),cudaMemcpyDeviceToHost);
	for(int i=0;i<4;i++)
	{
		for(int j=0;j<4;j++)
		{
			cout<<c[i][j]<<" ";
		}
		cout<<endl;
	}
	cudaFree(deva);
	cudaFree(devb);
	cudaFree(devc);
	
}

要注意的是,数组传参实际上传的是指针,整型或浮点型是值传递,注意区别!

你可能感兴趣的:(cuda,gpu,c++)