cuda相关

137 阅读2分钟

cuda,利用GPU来实现高速计算。对程序中一些函数含义的记录

cudaSetDevice(0);
//一个设备必须在任何__global__函数或者所有来自附录D 的任何函数调用之前选择;
//否则,device 0 自动地被选择,并且所有随后的设备选择将是无效的。
//0表示能搜索到的第一个设备号,如果有多个设备,则编号为0,1,2...

cudaDeviceSynchronize()
//该方法将停止CPU端线程的执行,直到GPU端完成之前CUDA的任务;

//主机和设备之间传递数据
//注意:该函数是同步执行函数,
//在未完成数据的转移操作之前会锁死井一直占有CPU进程的控制权,
//所以不用再添加cudaDeviceSynchronize()函数
cudaMemcpy(d_A,h_A,nBytes,cudaMemcpyHostToDevice) //主机到设备
cudaMemcpy(h_A,d_A,nBytes,cudaMemcpyDeviceToHost) //设备到主机

cuda里的打印输出

  • cuda里不能用c++的cout;
  • 使用printf,打印某个线程下的输出信息
    #include <cstdio>  //printf函数所需头文件
    const int tid = blockIdx.x*blockDim.x+ threadIdx.x;// 计算当前执行的线程id
    if (tid == 99)
    {
      printf("curctpos: %f %f %f\n", curPos.x, curPos.y, curPos.z);
    }

GPU的线程管理

参考:谭升的博客(face2ai.com/CUDA-F-2-0-…)

一个核函数只能有一个grid,一个grid可以有很多个块(block),每个块可以有很多的线程(thread),这种分层的组织结构使得并行过程更加自如灵活。

企业微信截图_16751340354134.png

线程编号

  • blockIdx(线程块在线程网格内的位置索引,即当前 block 在 grid 中的坐标,可能从1维到3维)
    • blockIdx.x
    • blockIdx.y
    • blockIdx.z
  • threadIdx(线程在线程块内的位置索引,当前 thread 在 block 中的坐标,可能从1维到3维)
    • threadIdx.x
    • threadIdx.y
    • threadIdx.z
  • blockDim(范围,即每个block中有多少thread)
    • blockDim.x
    • blockDim.y
    • blockDim.z
  • gridDim(范围,即每个grid有多少block)

线程的id计算:

  • 1 grid, 1 block -blockSize = blockDim.x
    • blockId = blockIdx.x
    • threadId = threadIdx.x
    Id = blockIdx.x * blockDim.x + threadIdx.x

核函数

kernel_name<<<grid,block>>>(argument list);

kernel_name<<<4,8>>>(argument list)指令的线程布局为:blockIdx.x 0,1,2,3;threadIdx.x,0,1,2,3,4,5,6,7

当主机启动了核函数,控制权马上回到主机,而不是主机等待设备完成核函数的运行

想要主机等待设备端执行可以用下面这个指令: cudaDeviceSynchronize(void);