首页 > 编程语言 >CUDA程序优化-1.基础介绍

CUDA程序优化-1.基础介绍

时间:2024-06-06 19:55:13浏览次数:19  
标签:__ kernel int 程序 cuda CUDA 优化 size

简介

本合集主要介绍我在开发分布式异构训练框架时的CUDA编程实践和性能优化的相关内容。主要包含以下几个部分:

  1. 介绍CUDA的基本概念和架构,帮助读者建立对CUDA的初步认识,包括硬件架构/CUDA基础等内容
  2. 介绍一些性能优化技巧和工具,帮助读者优化CUDA程序的执行效率
  3. 结合具体的代码示例来说明一个cuda程序的优化思路和结果, 帮助读者更好地理解和掌握CUDA编程和性能优化的实践方法

希望通过本文档,能够帮助大家写出更高效的CUDA程序。下面我们就开始吧~

1. 硬件架构

要说清楚为什么GPU比CPU更适合大规模并行计算, 要从硬件层面开始说起

image

以当前较主流的硬件i9-14900k和A100为例:

i9-14900k: 24核心, 32线程(只能在16个能效核上进行超线程), L2: 32MB, L3: 36MB, 内存通信带宽 89.6GB/s

A100: 108 SM, 6912 CUDA core, 192KB L1, 60MB L2, 40GB DRAM.

我个人的理解, GPU的运算核心之所以远多于CPU, 是因为远少于CPU的控制逻辑. GPU每个core内不需要考虑线程调度的情况, 不需要保证严格一致的运算顺序, 另外每个sm都有自己独立的寄存器和L1, 对线程的切换重入非常友好, 所以更适合大规模数据的并行运算. 而这种设计方式也会对程序员提出更高的要求, 纯CPU程序可能写的最好的代码和最差的情况有个2/3倍的性能差距就很大了, 而CUDA kernel可能会相差几十倍甚至几百倍.

image

HBM(High-Bandwidth Memory) :HBM是高带宽内存,也就是常说的显存, 这张图里的DRAM。 带宽: 1.5TB/s

L2 Cache:L2 Cache是GPU中更大容量的高速缓存层,可以被多个SM访问。L2 Cache还可以用于协调SM之间的数据共享和通信。 带宽: 4TB/s

SM(Streaming Multiprocessor) :GPU的主要计算单元,负责执行并行计算任务。每个SM都包含多个CUDA core,也就是CUDA里Block执行的地方, 关于block_size如何设置可以参考block_size设置, 跟随硬件不同而改变, 通常为128/256

L1 Cache/SMEM:, 也叫shared_memory, 每个SM独享一个L1 Cache,CUDA里常用于单个Block内部的临时计算结果的存储, 比如cub里的Block系列方法就经常使用, 带宽: 19TB/s

SMP(SM partition): A100中有4个. 每个有自己的wrap调度器, 寄存器等.

CUDA Core: 图里绿色的FP32/FP64/INT32等就是, 是thread执行的基本单位

Tensor Core: Volta架构之后新增的单元, 主要用于矩阵运算的加速

WARP(Wavefront Parallelism) :WARP指的是一组同时执行的Thread,固定32个, 不够32时也会按32分配. wrap一个线程对内存操作后, 其他wrap内的线程是可见的.

Dispatch Unit: 从指令队列中获取和解码指令,协调指令的执行和调度

Register File: 寄存器用于存储临时数据、计算中间结果和变量。GPU的寄存器比CPU要多很多

2. cuda基础

cuda基础语法上和c/c++是一致的. 引入了host/device定义, host指的是cpu端, device指的是gpu端

个人感觉最难的部分在于并行的编程思想和cpu编程的思想差异比较大. 我们以一个向量相加的demo程序举例:

__global__ void add_kernel(int *a, int *b, int *c, int n) {
    int index = threadIdx.x + blockIdx.x * blockDim.x;
    if (index < n) {
        c[index] = a[index] + b[index];
    }
}

int main() {
    int *a, *b, *c;
    int *d_a, *d_b, *d_c;
		int n = 10000;
    int size = n * sizeof(int);
    cudaMalloc((void**)&d_a, size);
    cudaMalloc((void**)&d_b, size);
    cudaMalloc((void**)&d_c, size);
    a = (int*)malloc(size);
    random_ints(a, n);
    b = (int*)malloc(size);
    random_ints(b, n);
    c = (int*)malloc(size);
    cudaMemcpy(d_a, a, size, cudaMemcpyHostToDevice);
    cudaMemcpy(d_b, b, size, cudaMemcpyHostToDevice);
    //cuda kernel
    add_kernel<<<(n + threads_per_block - 1)/threads_per_block, threads_per_block>>>(d_a, d_b, d_c, n);
    cudaMemcpy(c, d_c, size, cudaMemcpyDeviceToHost);

    cudaFree(d_a);
    cudaFree(d_b);
    cudaFree(d_c);

    return 0;
}

描述符

cuda新增了三个描述符:

__global__: 在device上运行, 可以从host/device上调用, 返回值必须是void, 异步执行.

__device__: 在device上运行和调用

__host__: 只能在host上执行和调用

CUDA Kernel

cuda_kernel是由<<<>>>围起来的, 里面主要有4个参数用来配置这个kernel <<<grid_size, block_size, shared_mem_size, stream>>>

grid_size: 以一维block为例, grid_size计算以 (thread_num + block_size - 1) / block_size 计算大小

block_size: 见上面SM部分介绍

shared_mem_size: 如果按 __shared__ int a[] 方法声明共享内存, 需要在这里填需要分配的共享内存大小. 注意不能超过硬件限制, 比如A100 192KB

stream: 异步多流执行时的cuda操作队列, 在这个流上的所有kernel是串行执行的, 多个流之间是异步执行的. 后续会在异步章节里详细介绍

整个过程如下图, 先通过cudaMemcpy 把输入数据copy到显存->cpu提交kernel->gpu kernel_launch->结果写回线程->DeviceToHost copy回内存.

image

add_kernel 相当于我们将for循环拆分为了每个线程只处理一个元素的相加的并行执行. 通过nvcc编译后就完成了第一个kernel的编写. 下一篇会以一个具体的例子来讲如何进行kernel的性能分析和调优.

常用库

thrust: cuda中类似于c++ STL的定位, 一些类似于STL的常见算法可以在这里找到现成的实现, 比如sort/reduce/unique/random 等. 文档: https://nvidia.github.io/cccl/thrust/api/namespace_thrust.html

cudnn: 神经网络加速的常用库. 包含卷积/pooling/softmax/normalization 等常见op的优化实现.

cuBlas: 线性代数相关的库. 进行矩阵运算时可以考虑使用, 比如非常经典的矩阵乘法实现cublasSgemm

Cub: wrap/block/device级的编程组件, 非常常用. 文档: https://nvidia.github.io/cccl/cub/

nccl: 集合通信库. 用于卡间通信/多机通信

相关资料

cuda编程指导手册: https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#programming-model

性能分析工具Nsight-System & Nsight-Compute: https://docs.nvidia.com/nsight-systems/index.html

标签:__,kernel,int,程序,cuda,CUDA,优化,size
From: https://www.cnblogs.com/sunstrikes/p/18235920

相关文章

  • 环境配置·Ubuntu1804安装CUDA和Pytorch
    InitUbuntuandchangedeb&pipsourcewgethttps://github.com/blueflylabor/blueflylabor.github.io/blob/main/toolbox/initUbuntu/initUbuntu.shbash./initUbuntu.shCUDA11.6wgethttps://developer.download.nvidia.com/compute/cuda/repos/wsl-ubuntu/x86_64......
  • C语言:详解gcc驱动程序完成编译、汇编、链接的过程
    相关阅读C语言https://blog.csdn.net/weixin_45791458/category_12423166.html?spm=1001.2014.3001.5482    gcc是一个命令,严格意义上说,它只是一个驱动程序,而不是一个编译器。gcc负责调用GNU工具链中的预处理器、编译器、汇编器、链接器等工具,通过传递不同的选项给g......
  • 程序员为什么要学习AI大模型?
    前言在科技浪潮的推动下,人工智能(AI)技术已经成为推动软件行业发展的核心动力。而在AI技术的众多分支中,AI大模型以其巨大的潜力和广泛的应用场景,逐渐成为了程序员们关注的焦点。本文将从程序员的角度出发,探讨AI大模型的定义、应用,以及为何程序员需要深入了解大模型的相关知识......
  • <编译器> 7. 中间代码 | 5. 程序设计
    IR代码中符号代码(label)沿用不变int调用T_Const(inti)Tree模块:1.patchList:真值/假值回填表这里是patchList的生成,至于具体怎么回填后面才会讲structpatchList_{Temp_label*head;patchListtail};//生成stmstm=T_Cjump(T_ge,unEx(......
  • Day19 待办事项功能页面完善以及显示优化
    本章节完善了待办事项增删改查功能,及优化打开待办事项页面时,如果无数据则显示默认的背景图片,否则显示数据等细节优化 由于待办事项功能页,数据已正常渲染出来了。但页面新增,查询,修改,删除等功能还未实现。接下来实现待办事项的请求WebApi接口实现CURD(增删改查)的功能......
  • 电子合同签署小程序,最新源码分享
    获取最新源码 添加我为微信好友一合通源码是一款开源的在线电子合同签署工具,其背后由重庆弈联数聚科技有限公司开发,从公司的商业化产品“一合通”中剥离出来。以下是关于一合通源码的详细介绍:核心功能:智能合同模板:提供智能模板、智能起草、智能审批功能,帮助企业迅速高效......
  • 内存优化:Boxing
    dotMemory如今,许多开发人员都熟悉性能分析的工作流程:在分析器下运行应用程序,测量方法的执行时间,识别占用时间较多的方法,并致力于优化它们。然而,这种情况并没有涵盖到一个重要的性能指标:应用程序多次GC所分配的时间。当然,你可以评估GC所需的总时间,但是它从哪里来,如何减少呢?“普通......
  • 001__C语言程序入门
    一、第一个程序:helloworld配置部署好vsCode之后,就可以直接在上面写代码了,新建一个新的C程序文件,向屏幕输出一串字符“HelloWorld!”下面,从整体上来分析一下这个最简单的C语言程序,将这个最简程序的各个部分剖析清楚,明白我们写下的每一个字符的具体含义。二、C语言的基本结......
  • 短剧小程序剧场短剧APP定制开发付费短剧之为什么自建?
    在当今数字时代,拥有一个属于自己的小剧场短剧影视小程序不仅是追求创作梦想的新途径,也是与观众建立紧密联系的有效方式。这种新兴的平台为创作者提供了前所未有的自由和机会,使他们能够直接与广大观众交流和分享作品。1、源码分享的重要性(1)易于访问和修改:源码的共享让创作者......
  • Xenium In Situ数据的质量评估及优化方案(试用版)
    作者,EvilGenius作为公司的分析人员,多方法比较和优化也是必修课。今天我们来看看Xenium的一些分析点及可能得优化方案Xenium本身的细胞分割更加适合于规整的、圆形或者其他形状不太奇怪的细胞,这一点得到了上海10X技术支持的确认,不过对于大多数样本,这个方法就够用了。这一篇......