cuda并行编程基础(一)

一、安装cuda
    (一)现在跑windows,unix/linux还没有跑过,暂不提及;
    (二)为编程方便,在windows现安装visual statio 2015,当然也可以不安装,如果你对cmd+notePad操作比较熟的话;
    (三)到官网上下载咯https://developer.nvidia.com/cuda-toolkit-archive,截至2017-12-18,最新的到9.0了;
    (四)安装时,最好选全部安装(需手动选),里面集成了显卡程序等。
二、一些基础
    (一)几个概念

  并行计算:分为任务并行和数据并行,任务并行如C的多线程多任务运算,cuda是主要适合数据并行。
  主机端:即你的CPU,平常程序都在CPU上运行,CPU主要适合处理控制密集型任务,比如从一个函数切换到另外一个函数
  设备端:即你的GPU显卡,GPU程序当然有特殊的接口了,主要适合数据并行计算密集型任务,如矩阵运算等 cuda的主要作用就是优化大运算量的计算,到官网上可以查到与CPU的对比,当然你实际测的时候可能会有差别,一般就23倍吧,你实际体验时,可能超过着个值,有时10-100都有可能,毕竟CPU跑的东西不单有你的程序。
 (二)cuda基础
  1.第一个程序:hello.cu(参考hello.cu程序,下同)

   PS:不多讲,直接糊程序吧,边写边讲,这样节省时间,也方便学习
  2.CUDA一般编程结构
   一般按照结构:程序开始->CPU运行->将CPU数据copy到GPU->GPU运行->将GPU数据copy到CPU->CPU运行->程序结束
   当然程序长了,就不是这么简单了。
  3.线程管理:checkDimension.cu
   (1)从大到小分别为:显卡(GPU)->网格(grid)->线程块(block)->线程(thread),注意从网格开始最大为3维,当然也可以1维了
   (2)网格(grid):一个内核函数就是一个网格,里面所有线程都在这个网格范围内,里面的线程共享全局内存空间
   (3)线程块(block):一个网格可以包含很多个block,block之间可以通过“同步”和“共享内存”进行协作,block之间的区分通过“blockIdx”
   (4)线程(thread):一个线程块可以包含很多个thread,thread之间区分通过threadIdx,当然如果block不一样,threadIdx肯定需要继续区分
   (5)blockIdx/threadIdx:是dim3类型变量(整型),是索引线程的关键,对某个线程的索引:blockIdx.x/y/z,threadIdx.x/y/z
   (6)gridDim/blockDim:也是dim3类型变量,是检查线程维数的光剑,对某个线程所属的网格维数、线程块维数进行检测:gridDim.x/y/z,blockDim.x/y/z
   (7)dim3:一个变量类型
     如:dim3 dd;//dd.x,dd.y,dd.z 默认为1
     dim3 dd(2,3);//dd.x==2,dd.y==3,dd.z==1
    一般我们这样定义:
    dim3 grid(2,3);//就是定义一个网格,里面包含2*3*1个block
    dim3 block(4,5);//就是定义一个线程块,里面包含4*5*1个thread


第一个程序很重要哦,一定要搞懂,后面就可能没有完整的代码啦

/* hello.cu:用CPU和GPU在控制台打印“hello,world” */
/* Authored by alpc40 */

#include <stdio.h>
#include<stdlib.h>
//下面两个头文件基本都会用到,别省了
#include "cuda_runtime.h"
#include "device_launch_parameters.h"

//这个宏还是蛮有用,主要功能是检测cuda函数的错误,以方便检查
/*
  1.cudaError_t:CUDA的错误码,它的错误码太多了,大概有80-90个,具体什么错误碰到了再解释
  2.cudaGetErrorString():将CUDA错误码转换成具体错误语句,方便判断程序员错误
  3.__FILE__,__LINE__:这个就不解释了,虽然我也用的不太熟
*/
#define CHECK(call)                                                  \
{                                                                    \
    const cudaError_t err = call;                                    \
    if (err != cudaSuccess)                                          \
    {                                                                \
        fprintf(stderr, "Error: %s:%d, ", __FILE__, __LINE__);       \
        fprintf(stderr, "code: %d, reason: %s\n", err,               \
                cudaGetErrorString(err));                            \
        exit(1);                                                     \
    }                                                                \
}
//下面是内核函数
/*
  __global__:在设备端执行的函数,但是一般在主机端调用,设备端也能调用,但对GPU计算能力必须>3,什么意思,暂不解释
  __device__:在设备端执行且调用的函数,就是说一般的函数调用不了
  __host__:在主机端调用的程序,就是我们一般的代码啦,这个标识是可以省略的
*/
__global__ void helloFromGPU()
{
    printf("Hello World from GPU!\n");
}
//下面是主函数
/*
  <<<grid,block>>>:三个尖括号是cuda特有,是核函数的执行配置,调用核函数必须用到它
      grid是网格,这个值代表调用多少个block;block是线程块,代表调用多少个线程
  cudaDeviceReset():显示地释放和清空当前进程的GPU资源,别乱用哦,用了的话,GPU数据全没了
*/
int main(int argc, char **argv)
{
    printf("Hello World from CPU!\n");

    helloFromGPU<<<1, 10>>>();
    CHECK(cudaDeviceReset());
    return 0;
}

第二个程序,了解cuda线程组织结构,非常重要

/*checkDimension.cu:显示线程的维度 */
/*Authored by alpc40*/
__global__ void checkIndex(void)
{
    printf("threadIdx:(%d, %d, %d)\n", threadIdx.x, threadIdx.y, threadIdx.z);
    printf("blockIdx:(%d, %d, %d)\n", blockIdx.x, blockIdx.y, blockIdx.z);
    printf("blockDim:(%d, %d, %d)\n", blockDim.x, blockDim.y, blockDim.z);
    printf("gridDim:(%d, %d, %d)\n", gridDim.x, gridDim.y, gridDim.z);
}

int main(int argc, char **argv)
{
    int nElem = 6;//定义总计算量
    dim3 block(3);// 定义grid和block
    dim3 grid((nElem + block.x - 1) / block.x);// 定义grid和block
    printf("grid.x %d grid.y %d grid.z %d\n", grid.x, grid.y, grid.z);// CPU端检测维度
    printf("block.x %d block.y %d block.z %d\n", block.x, block.y, block.z);
    checkIndex<<<grid, block>>>();// GPU端检测维度
    CHECK(cudaDeviceReset());// 恢复GPU
    return 0;
}

想想为何会是这样输出呢?而不是thread\block\grid,然后又是thread\block\grid,很简单啦,因为每个线程都是同时在运行,也可能不按这个顺序哦

猜你喜欢

转载自blog.csdn.net/weixin_39212021/article/details/78838380