nvidia-cuda 手册:https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#kernels
nvidia cuda 教学视频 https://www.nvidia.cn/object/cuda_education_cn_old.html
介绍:
CUDA编程模型是一个异构模型,需要CPU和GPU协同工作。在CUDA中,host和device是两个重要的概念,我们用host指代CPU及其内存,而用device指代GPU及其内存。
典型的CUDA程序的执行流程如下:
- 分配host内存,并进行数据初始化;
- 分配device内存,并从host将数据拷贝到device上;
- 调用CUDA的核函数在device上完成指定的运算;
- 将device上的运算结果拷贝到host上;
- 释放device和host上分配的内存。
1.hello world
#include <stdio.h>
#include <cuda_runtime.h> //头文件//核函数声明,前面的关键字__global__
__global__ void kernel( void ) {
}int main( void ) {//核函数的调用,注意<<<1,1>>>,第一个1,代表线程格里只有一个线程块;第二个1,代表一个线程块里只有一个线程。kernel<<<1,1>>>();printf( "Hello, World!\n" );return 0;
}
上面流程中最重要的一个过程是调用CUDA的核函数来执行并行计算,kernel是CUDA中一个重要的概念,kernel是在device上线程中并行执行的函数,核函数用__global__
符号声明,在调用时需要用<<<grid, block>>>
来指定kernel要执行的线程数量,在CUDA中,每一个线程都要执行核函数,并且每个线程会分配一个唯一的线程号thread ID,这个ID值可以通过核函数的内置变量threadIdx
来获得。
要深刻理解kernel,必须要对kernel的线程层次结构有一个清晰的认识。首先GPU上很多并行化的轻量级线程。kernel在device上执行时实际上是启动很多线程,一个kernel所启动的所有线程称为一个网格(grid),同一个网格上的线程共享相同的全局内存空间,grid是线程结构的第一层次,而网格又可以分为很多线程块(block),一个线程块里面包含很多线程,这是第二个层次
nvcc hello.cu -o hello.o
./hello.o
2.查看gpu信息
#include <stdio.h>
int main() {int nDevices;cudaGetDeviceCount(&nDevices);for (int i = 0; i < nDevices; i++) {cudaDeviceProp prop;cudaGetDeviceProperties(&prop, i);printf("Device Num: %d\n", i);printf("Device name: %s\n", prop.name);printf("Device SM Num: %d\n", prop.multiProcessorCount);printf("Share Mem Per Block: %.2fKB\n", prop.sharedMemPerBlock / 1024.0);printf("Max Thread Per Block: %d\n", prop.maxThreadsPerBlock);printf("Memory Clock Rate (KHz): %d\n",prop.memoryClockRate);printf("Memory Bus Width (bits): %d\n",prop.memoryBusWidth);printf("Peak Memory Bandwidth (GB/s): %.2f\n\n",2.0 * prop.memoryClockRate * (prop.memoryBusWidth / 8) / 1.0e6);}return 0;
}
nvcc hello.cu -o hello.o
./hello.o
参考:https://zhuanlan.zhihu.com/p/34587739