cuda编程以及GPU基本知识

  • Post author:
  • Post category:其他




CPU与GPU的基本知识


GPU

:吞吐导向内核


CPU

:延迟导向内核

  • 延迟:一条指令从发出到发出结果的时间间隔
  • 吞吐量:单位时间内处理指令的数量



CPU特点

  • 内存大:多级缓存结构提高访存速度

    • 处理运算速度远高于访问存储速度 -> 空间换时间
    • 经常访问的内容放到低级缓存(L1),不常访问的内容放到高级缓存
  • 控制复杂

    • 分支预测机制 (if-else/break/continue等 在硬件端的机制)
    • 流水线数据前送
  • 运算单元强大

    • 整型浮点型复杂运算速度快

请添加图片描述



GPU特点

  • 缓存小

    • 提高内存吞吐
  • 控制简单

    • 没有分支预测
    • 没有数据转发
    • (-> 复杂指令效率不高,简单指令吞吐显著提高)
  • 精简运算单元

    • 多长延时流水线以实现高吞吐量 (下图每一行绿色块)
    • 需要大量的线程来容忍延迟

      在这里插入图片描述

      如图中所示,每一行的运算单元只有一个控制器,所以每一行的运算单元执行的是同一个指令,只不过是使用不同的数据。



GPU vs. CPU

  • CPU:连续计算部分,延迟优先;相比GPU,单条指令延迟快十倍以上
  • GPU:并行计算部分,吞吐优先;相比CPU,单位时间内执行指令数量10倍以上



什么样的问题适合GPU?

  • 计算密集:数值计算比例远大于内存操作,因此内存访问的延时可以被计算覆盖
  • 数据并行:大任务可以拆解为相同指令的小人物,因此对复杂流程的控制需求较低



GPU编程



CUDA编程并行计算的整体流程

void GPUkernel(float* A, float* B, float* C, int n)
{
1. // Allocate device memory for A, B, and C
   // copy A and B to device memory
	
2. // Kernel launch code – to have the device
   // to perform the actual vector addition
	
3. // copy C from the device memory
   // Free device vectors
}

在这里插入图片描述



CUDA编程术语:硬件

  • Device = GPU
  • Host = CPU
  • Kernel = GPU上运行的函数

请添加图片描述



CUDA编程术语:内存模型

CUDA中的内存模型分为一下几个层次:

  • 每个

    线程处理器

    (Thread Processor, PS)都有自己的

    寄存器

    (register)
  • 每个SP都有自己的

    局部内存

    (local memory),register和local memory只能被线程自己访问
  • 每个

    多核处理器

    (SM)内都有自己的

    共享内存

    (shared memory),其可被

    线程块

    (Thread Block)内所有线程访问
  • 一个GPU的所有SM共有一块

    全局内存

    (global memory),不同线程块的线程都可以使用



CUDA编程术语:软件

  • 分为以下几个层次

    • 线程处理器(SP)对应线程(thread)
    • 多核处理器(SM)对应线程块(thred block)
    • 设备端(device)对应线程块组合体(grid)
  • 一个kernel其实由一个grid来执行
  • 一个kernel一次只能在一个GPU上执行
    请添加图片描述



线程块(Thread Block)

线程块:可扩展的集合体;将线程数组分成多个块

  • 块内的线程通过共享内存、原子操作和屏障同步进行协作(shared memory, atomic operations and barrier synchronization)
  • 不同块中的线程不能协作,即线程的操作是互相独立的互不影响的

在这里插入图片描述

如图,该线程块包含256个线程,所执行的任务为向量相加的操作。其中,i = … 为确定线程在显存中位置的计算公式。



网格(grid)

网格:并行线程块组合

  • CUDA核函数由线程网格(数组)执行
  • 每个线程都有一个索引,用于计算内存地址和做出决策控制
  • 每个线程块互不影响
  • 最后将N个线程块的结果进行融合

    在这里插入图片描述



线程块id & 线程id

  • 每个线程要使用索引来决定要处理的数据
  • 无论是线程块id或是线程id,都可以是1维、2维或者3维的,如下图所示:

请添加图片描述

• dim3 dimGrid(M, N);
• dim3 dimBlock(P, Q, S);

• threadId.x = blockIdx.x * blockDim.x + threadIdx.x;
• threadId.y = blockIdx.y * blockDim.y + threadIdx.y;



线程束(warp)

  • 多核处理器(SM)采用

    单指令多线程架构 SIMT

    (Single-Instruction, Multiple-Thread),其中warp(线程束)是最基本的执行单元,一个warp包含32个并行thread,这些thread以

    不同数据

    资源执行

    相同的指令

    。warp本质上是线程在GPU上运行的最小单元。
  • 当一个kernel被执行时,grid中的线程块被分配到SM上,一个线程块的thread只能在一个SM上调度,SM一般可以调度多个线程块,大量的thread可能被分到不同的SM上。每个线程拥有它自己的程序计数器和状态寄存器,并且用该线程自己的数据执行指令,这就是所谓的Single Instruction Multiple Thread(SIMT)。
  • 由于warp的大小为32,所以block所含的thread的大小一般要设置为

    32的倍数

    。(或者可以说,每个线程块要包含N个整行的计算单元,而不能是一半)

在这里插入图片描述



版权声明:本文为Bro_Jun原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。