CUDA笔记2:概念理解

原创 2014年12月29日 11:08:05
CUDA基本概念:

CUDA全称是ComputeUnified Device Architecture,中文名称即统一计算设备架构,它是NVIDIA公司提出了一种通用的并行计算平台和编程模型。使用CUDA,我们可以开发出同时在CPUGPU上运行的通用计算程序,更加高效地利用现有硬件进行计算。并行编程的中心思想是分而治之:将大问题划分为一些小问题,再把这些小问题交给相应的处理单元并行地进行处理。在CUDA中,这一思想便体现在Grid, Block, Thread等层次划分上。

 

GPU并行架构:

GPU编程中CPU被称为Host, GPU被称为Device.

Kernel函数在Host中被调用,在Device中被执行。

一个Kernel对应一个Grid;

一个Grid包含一组Block,BlockGrid中的分布可以是一维,二维或三维的,具体由GridDim定义,每个Block都有各自的ID,blockIdx.xyz;

一个Block包含一组Thread,ThreadBlock中的分布有BlockDim定义,每个Thread都有各自的ID,记threadIdx.xyz;

CUDA笔记2:概念理解


Kernel函数调用方式为kernel<<<AB>>>(parameters),在尖括号中,A代表线程格(grid)的尺寸gridDim,它可以是三维的,用类型dim3表示,也可以是一维的,用int类型表示。B代表线程块(block)的尺寸blockDimk,它与A类似,也可分别用dim3int类型表示。在内核函数内部,CUDA为我们内建了一些变量用于访问GridBlock的尺寸和索引等信息,它们是:

1. gridDim:代表线程格(grid)的尺寸,gridDim.xx轴尺寸,gridDim.ygridDim.z类似。如下图,它的gridDim.x = 3gridDim.y = 2gridDim.z = 1

2. blockIdx:代表线程块(block)在线程格(grid)中的索引值,如下图,Block1,1)的索引值为:blockIdx.x = 1blockIdx.y = 1    

3. blockDim:代表线程块(block)的尺寸,blockDIm.xx轴尺寸,其它依此类推。如下图,注意到Block1,1)包含了4 * 3个线程,因此blockDim.x = 4, blockDim.y = 3

4. threadIdx:线程索引,同block索引。

CUDA笔记2:概念理解

GPU硬件角度,它的基本单元为StreamingProcessor(SP),即流水处理器,每个SP执行一个Thread;多个SP组成一个Streamming MultiProcessor(SM),即流水多处理器,每个SM执行一个Block.GPU通常包含多个SM

CUDA笔记2:概念理解


GPU存储层次:

每个 thread都有自己的一份 register  local memory的空间。一组thread构成一个 block,这些thread则共享有一份shared memory__syncthreads()可以同步一个Block内的所有线程,不同Block内的Thread不能同步。此外,所有的 thread(包括不同 block  thread)都共享一份global memoryconstant memory、和 texture memory。不同的 grid则有各自的 global memoryconstant memory texture memorycudaMalloccudaFree用于内存分配及释放,它们分配的是global memorycudaMemcpy用于Hose-Device数据交换。

CUDA笔记2:概念理解



一个Thread被执行过程:

GridGPU上启动;

block被分配到SM上;

SM把线程组织为warp

SM调度执行warp

执行结束后释放资源;

block继续被分配....

例如GTX760, 6SM 192SP/SM,一个SM一次执行一个Block,假设一个Warp32Thread,一个Block线程数量应该远远大于192(6warp),为的是GPU执行长延时操作。(CUDA处理器需要高效地执行长延时操作,如果warp中的线程执行一个条指令需要等待前面启动的长延时操作的结果,那么不会选择执行该warp,而是选择执行另一个不用等待结果的驻留的warp,这样,如果有了多个warp准备执行,则总可以选择不产生延时的线程先执行,达到所谓的延时隐藏。



函数类型:

[cpp] view plain copy
  1. __device__ // 执行于Device,仅能从Device调用。限制,不能用&取地址;不支持递归;不支持static variable;不支持可变长度参数  
  2.     __global__ // void: 执行于Device,仅能从Host调用。此类函数必须返回void  
  3.     __host__ // 执行于Host,仅能从Host调用,是函数的默认类型  
  4. // 在执行kernel函数时,必须提供execution configuration,即<<<....>>>的部分。  
  5. //   例如:  
  6. __global__ void KernelFunc(...);  
  7. dim3 DimGrid(100, 50); // 5000 thread blocks  
  8. dim3 DimBlock(4, 8, 8); // 256 threads per block  
  9. size_t SharedMemBytes = 64; // 64 bytes of shared memory  
  10. KernelFunc<<< DimGrid, DimBlock, SharedMemBytes >>>(...);  

数据结构:

[cpp] view plain copy
  1. // 内建矢量类型:  
  2. int1,int2,int3,int4,float1,float2, float3,float4 ...  
  3. // 纹理类型:  
  4. texture<Type, Dim, ReadMode>texRef;  
  5. // 内建dim3类型:定义grid和block的组织方法。例如:  
  6. dim3 dimGrid(2, 2);  
  7. dim3 dimBlock(4, 2, 2);  
  8. // CUDA函数CPU端调用方法  
  9. kernelFoo<<<dimGrid, dimBlock>>>(argument);  
  10. __device__   // GPU的global memory空间,grid中所有线程可访问  
  11. __constant__ // GPU的constant memory空间,grid中所有线程可访问  
  12. __shared__   // GPU上的thread block空间,block中所有线程可访问  
  13. local        // 位于SM内,仅本thread可访问  
  14. // 在编程中,可以在变量名前面加上这些前缀以区分。  

CUDA计时:

CPU代码和CUDA函数是异步执行的,即CUDA函数完成任务之前控制权有可能已经交给了CPU. cudaDeviceSynchronize()能够阻塞当前CPU线程,直到CUDAkernel函数调用运行完毕后才继续执行CPU线程。所以如果需要对HostDevice代码进行联合计时,通常在CUDA Kernel函数和结果拷贝cudaMemcpy函数之间增加一句同步代码cudaDeviceSynchronize()。除了在CPU主程序中设置定时函数外,CUDAAPI也提过了毫秒级的GPU计时方法:

[cpp] view plain copy
  1. cudaEvent_t start, stop;  
  2.     float time;  
  3. cudaEventCreate(&start);  
  4. cudaEventCreate(&stop);  
  5. cudaEventRecord(start, 0);  
  6. kernel<<<grid, threads>>>(d_odata, d_idata, size_x, size_y, NUM_REPS);  
  7. cudaEventRecord(stop, 0);  
  8. cudaEventSynchronize(stop);  
  9. cudaEventElapsedTime(&time, start, stop);  
  10. cudaEventDestroy(start);  
  11. cudaEventDestroy(stop);  

这里cudaEventRecord()用于将startstop事件放置到默认流(stream0),当设备运行到事件处时,将会为该事件记录一个时间戳(timestamp)。cudaEventElapsedTime()函数返回记录中startstop事件之间的毫秒级时间差。由于记录是发生在GPU上的,其时钟是独立的,因此时钟分辨率也是操作系统无关的



CUDA代码调试:

CUDA Toolkit安装时会自动安装VS插件Nsight。打开VS,device code上设置断点,VS菜单栏选择Nsight-> Start CUDA Debugging,即可调试CUDA代码。




参考:

CUDA学习笔记:http://luofl1992.is-programmer.com/posts/38830.html

CUDA编程指南阅读笔记:http://blog.csdn.net/csgxy123/article/details/9704461

大规模并行处理器编程实战笔记:http://blog.csdn.net/linyingzhan/article/details/8265088

相关文章:

  • 2021-10-29
  • 2021-07-24
  • 2021-07-18
  • 2021-11-29
  • 2021-09-10
  • 2021-07-12
  • 2021-06-08
  • 2021-06-16
猜你喜欢
  • 2022-01-06
  • 2021-09-16
  • 2021-08-28
  • 2021-06-30
  • 2022-12-23
  • 2021-10-10
相关资源
相似解决方案