cuda学习

CUDA学习系列

首先我们从最简单的hello开始

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语言的mallocmencpyfreeAPI等。我们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语言,但最大的问题就是如何协成合作解决一个问题。这就是线程合作的重要性。通过下面的学习,你将会:

  1. 学会CUDA C唤醒线程
  2. 学会不同线程之间的通信
  3. 学会在不同线程之间的通过机制

在之前的例题中,add << <N, 1 >> >(dev_a,dev_b,dev_c)第二个参数表示在每一块中(block)我们想创建线程的个数

example 向量加法

#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编程,如有不对,欢迎吐槽。。。

你可能感兴趣的:(CUDA,并行计算)