cuda是英伟达公司提出的一种并行计算框架,在大数据的今天,数据计算显得尤其重要,尤其是机器学习领域的深度学习,更是离不开高效率的并行计算,如果说使用一般的cpu进行计算需要几天,而使用gpu计算仅仅需要几个小时!!!可见并行计算的前途无量。
以前接触过一段时间cuda,现在需要做笔记,将学习的历程记录下来,以便以后来参考,也给新人一点帮助,欢迎吐槽。。。首先是“hello world”…
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
__global__ void Kernel(void)
{
}
int main()
{
Kernel << <1, 1 >> >();
printf("hello world");
return 0;
}
首先使用__global__
声明一个类型,表示该函数应该在设备也就是显卡处编译,为什么会这么奇怪,我也没有看出来。。。
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
__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 >> >(1,2,dev_c); //调用函数
cudaMemcpy(&c, dev_c, sizeof(int), cudaMemcpyDeviceToHost); //将显卡的结果copy到本地
printf("1+2=%d\n", c);
cudaFree(dev_c); //释放显卡内存
return 0;
}
如果我们想知道一台计算机上gpu的个数,可以使用下面的代码:
int count;
cudaGetDeviceCount(&count);
printf("%d", count);
比如在我的电脑上就是1个,gt635M。
在cuda中,有一个结构体专门来记录显卡的信息的,就是cudaDeviceProp
,使用方法如下:
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
int main()
{
cudaDeviceProp prop;
cudaGetDeviceProperties(&prop, 0);
printf("Name %s\n", prop.name);
printf("Computer capability:%d.%d\n", prop.major, prop.minor);
printf("%d\n", prop.totalGlobalMem/(1024*1024));
printf("%f\n", prop.totalConstMem/(1024.0));
return 0;
}
当然还有很多的信息,需要的话,借助于cuda文档了。
通过前面的学习我们学会了使用关键字__global__
来表示在gpu上执行。也学会了类似于c语言的malloc
、mencpy
、free
API等。我们gpu计算已经入门,下面我们来学习高效使用gpu进行计算。
首先我们来看一下最简单的向量加法运算,C实现:
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#define N 10
void add(int *a, int *b, int *c)
{
int tid = 0;
while (tid < N){
c[tid] = a[tid] + b[tid];
tid++;
}
}
int main()
{
int a[N], b[N], c[N];
for (int i = 0; i < N; i++){
a[i] = -i;
b[i] = i*i;
}
add(a, b, c);
for (int i = 0; i < N; i++)
{
printf("%d + %d = %d\n", a[i], b[i], c[i]);
}
return 0;
}
使用cuda c的并行计算代码如下:
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#define N 10
__global__ void add(int *a, int *b, int *c)
{
int tid = blockIdx.x;
if (tid < N)
{
c[tid] = a[tid] + b[tid];
}
}
int main()
{
int a[N], b[N], c[N];
int *dev_a, *dev_b, *dev_c;
cudaMalloc((void**)&dev_a, N*sizeof(int));
cudaMalloc((void**)&dev_b, N*sizeof(int));
cudaMalloc((void**)&dev_c, N*sizeof(int));
for (int i = 0; i < N; i++)
{
a[i] = -i;
b[i] = i*i;
}
cudaMemcpy(dev_a, a, N*sizeof(int), cudaMemcpyHostToDevice);
cudaMemcpy(dev_b, b, N*sizeof(int), cudaMemcpyHostToDevice);
add << <N, 1 >> >(dev_a,dev_b,dev_c);
cudaMemcpy(c, dev_c, N*sizeof(int), cudaMemcpyDeviceToHost);
for (int i = 0; i < 10; i++)
{
printf("%d+%d=%d\n", a[i], b[i], c[i]);
}
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
return 0;
}
这段代码与我们之前的不一样,别着急,慢慢道来。
首先是类似于kernel<<<N,1>>>
,第一个数字表示需要gpu并行计算的块,比如例子中的N=10,就是10个并行计算的块。但是带来一个问题,在一段时间内,哪一块执行呢?这样带来了第二个问题。
这就是blockIdx.x
的作用了。这个变量是集成在cuda框架中,表示了当前执行的块。但为什么是blockIdx.x
,而不是blockIdx
。
在cuda中,允许定义2维,如矩阵与图像处理。而现在只需要一维,所以不要激动不懂。
在之前的学习中,我们学会了设计并行计算的c语言,但最大的问题就是如何协成合作解决一个问题。这就是线程合作的重要性。通过下面的学习,你将会:
CUDA C
唤醒线程在之前的例题中,add << <N, 1 >> >(dev_a,dev_b,dev_c)
,第二个参数表示在每一块中(block)我们想创建线程的个数
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#define N 10
__global__ void add(int *a, int *b, int *c)
{
int tid = threadIdx.x;
if (tid < N)
c[tid] = a[tid] + b[tid];
}
int main()
{
int a[N], b[N], c[N];
int *dev_a, *dev_b, *dev_c;
cudaMalloc((void**)&dev_a, N*sizeof(int));
cudaMalloc((void**)&dev_b, N*sizeof(int));
cudaMalloc((void**)&dev_c, N*sizeof(int));
for (int i = 0; i < N; i++)
{
a[i] = -i;
b[i] = i*i;
}
cudaMemcpy(dev_a, a, N*sizeof(int), cudaMemcpyHostToDevice);
cudaMemcpy(dev_b, b, N*sizeof(int), cudaMemcpyHostToDevice);
add << <N,1 >> >(dev_a, dev_b, dev_c);
cudaMemcpy(c, dev_c, N*sizeof(int), cudaMemcpyDeviceToHost);
for (int i = 0; i < N; i++)
{
printf("%d+%d=%d\n", a[i], b[i], c[i]);
}
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
return 0;
}
如果我们同时拥有多线程和多个块,怎么办呢?
tid = threadIdx.x + blockIdx.x + blockDim.x;
这段代码使用了新的内置变量 blockDim
,
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#define N (33*1024)
__global__ void add(int *a, int *b, int *c)
{
int tid = threadIdx.x + blockIdx.x * blockDim.x;
while (tid < N)
{
c[tid] = a[tid] + b[tid];
tid += blockDim.x * gridDim.x;
}
}
int main()
{
int a[N], b[N], c[N];
int *dev_a, *dev_b, *dev_c;
cudaMalloc((void**)&dev_a, N*sizeof(int));
cudaMalloc((void**)&dev_b, N*sizeof(int));
cudaMalloc((void**)&dev_c, N*sizeof(int));
for (int i = 0; i < N; i++)
{
a[i] = -i;
b[i] = i*i;
}
cudaMemcpy(dev_a, a, N*sizeof(int), cudaMemcpyHostToDevice);
cudaMemcpy(dev_b, b, N*sizeof(int), cudaMemcpyHostToDevice);
add << <128,128 >> >(dev_a, dev_b, dev_c);
cudaMemcpy(c, dev_c, N*sizeof(int), cudaMemcpyDeviceToHost);
bool success = true;
for (int i = 0; i < N; i++)
{
if ((a[i] + b[i] != c[i]))
{
printf("%d + %d = %d\n", a[i], b[i], c[i]);
success = false;
}
}
if (success)
printf("we did it");
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
return 0;
}
这就是使用了多线程多块的并行计算模型。
寒假在家没有事做,于是就学习了cuda c编程,如有不对,欢迎吐槽。。。