CUDA安装并配置环境后,使用VS新建工程时会出现对应选项:
CUDA核函数调用
- CUDA核函数必须用限定词 global 修饰,返回类型必须为void,二者次序随意。
- 函数名与()之间用三括号<<<网格大小,线程块大小>>>指明核函数中线程数目与排列情况;
- cudaDeviceSynchronize()函数用于同步主机与设备;
#include <stdio.h>
#include "cuda_runtime.h"
//如何调用cuda核函数
__global__ void first_kernel()
{
printf("Hellow World GPU...\n");
}
int main()
{
printf("Hellow World CPU \n");
first_kernel<<<2, 3>>>();
cudaDeviceSynchronize();
return 0;
}
CUDA核函数线程索引
- 每个核函数允许指派多个线程,线程的组织结构为:<<<grid_size, block_size>>>,乘积为线程总数
- 对于大小为 ( D x , D y ) (D_x , D_y) (Dx,Dy)二维网络,线程的索引为(x,y),则这个线程的ID是 ( x + y ∗ D x ) (x + y * D_x) (x+y∗Dx)
- 对于大小为 ( D x , D y , D z ) (D_x , D_y, D_z) (Dx,Dy,Dz)三维网络,线程的索引为(x,y,z),则这个线程的ID是 ( x + y ∗ D x + z ∗ D x ∗ D y ) (x + y * D_x + z * D_x * D_y) (x+y∗Dx+z∗Dx∗Dy)
一维网络
网格、线程块为一维
- gridDim.x:数值为grid_size的数值
- blockDim.x:数值为block_size的数值
- blockIdx.x:线程在网格中的线程块ID,取值范围 0 ~ gridDim.x - 1;
- threadIdx.x:线程在线程块中的线程ID,取值范围 0 ~ blockDim.x - 1;
例:
dim3 grid_size(4);//定义grid与block尺寸
dim3 block_size(8);
kernel_fun<<<grid_size,block_size>>>(...);//调用核函数
//计算线程索引
int id = blockIdx.x*blockDim.x+threadIdx.x;//线程块索引*线程块中线程的个数+线程在当前线程块中的索引
多维网络
网格、线程块为多维
dim3 grid_size(Gx,Gy,Gz);
dim3 block_size(Bx,By,Bz);
- blockIdx.x:取值范围 0 ~ gridDim.x - 1;
- blockIdx.y:取值范围 0 ~ gridDim.y - 1;
- blockIdx.z:取值范围 0 ~ gridDim.z - 1;
- threadIdx.x:取值范围 0 ~ blockDim.x - 1;
- threadIdx.y:取值范围 0 ~ blockDim.y - 1;
- threadIdx.z:取值范围 0 ~ blockDim.z - 1;
网格大小限制:x、y、z方向最大值为2^31-1、65535、65535
线程块大小限制:x、y、z方向最大值为1024、1024、64
其中,x维度是最内层(变化最快),z维度是最外层(变化最慢)
例:
dim3 grid_size(3,2);// 列优先
dim3 block_size(3,4);// 定义grid和block尺寸
kernel_fun<<< grid_size, block_size>>>(...);//调用核函数
//计算线程索引
int blockId = blockId.x + blockId.y*gridDim.x;//3=0+1*3
int threadId = threadIdx.y*blockDim.x+threadIdx.x;//10=3*3 + 1
//线程在网格中的唯一标识
int id = blockId*(blockDim.x*blockDim.y)+threadId;//46=3*(3*4) + 10
warpSize
warpSize为内建变量,表示线程束大小,对目前所以GPU架构warpSize=32;即一个线程束就是连续的32个线程。
#include <stdio.h>
#include "cuda_runtime.h"
//cuda核函数线程索引
__global__ void first_kernel()
{
int tidx = threadIdx.x;
int tidy = threadIdx.y;
int tidz = threadIdx.z;
int bidx = blockIdx.x;
int bidy = blockIdx.y;
int bidz = blockIdx.z;
printf("GPU Kernel...thread index: (%d,%d), block index: (%d,%d) \n", tidy, tidx, bidy, bidx);
}
int main()
{
first_kernel<<<2, 3>>>();
cudaDeviceSynchronize();
return 0;
}
CUDA核函数要求总结
- 核函数返回类型必须是void;
- 必须使用限定符 _global_ ;
- 核函数支持重载;
- 不支持可变数量参数列表;
- 可向核函数传递非指针变量;
- 核函数不能为类的成员;
- 无论主机调用还是设备调用,核函数都是在设备中执行,调用时需指定执行配置;
- 计算能力3.5之前核函数之间不能相互调用,3.5开始引入动态并行机制,核函数可以相互调用;