CUDA 基础 01 - 概念

2023-11-08

最近在GPU编译器测试方面遇到一些瓶颈,准备学习下cuda 相关的基础知识。

warp/sm/index/grid等。

CPU VS GPU

GPU最重要的一点是可以并行的实现数据处理。

这一点在数据量大、运算复杂度不高的条件下极为适用。可以简单地把一块GPU想象成一个超多核的CPU运算部件。这些CPU有自己的寄存器,还有供数据交换用的共享内存、缓存,同时周围还有取指部件和相应的调度机制,保证指令能够在之上执行。

这里有一张典型的CPU和GPU的对比图片,CPU和GPU就呈现出非常不同的架构

图片

  • 鲜绿色:计算单元ALU(Arithmetic Logic Unit)
  • 橙红色:存储单元(cache)
  • 橙黄色:控制单元(control)

GPU:数量众多的计算单元和超长的流水线,只有简单的控制逻辑并省去了Cache
CPU:被Cache占据了大量空间,而且还有有复杂的控制逻辑和诸多优化电路。

图片

这个比喻就很恰当:

GPU的工作大部分就是这样,计算量大,而且要重复很多很多次。就像你有个工作需要算几亿次一百以内加减乘除一样,最好的办法就是雇上几十个小学生一起算,一人算一部分

CPU就像老教授,积分微分都会算,就是工资高,一个老教授资顶二十个小学生,你要是富士康你雇哪个

CPU和GPU因为最初用来处理的任务就不同,所以设计上有不小的区别,而某些任务和GPU最初用来解决的问题比较相似,所以用GPU来算了。

软件

grid 概念

CUDA 采用异构编程模型,用于运行主机设备应用程序。它有一个类似于 OpenCL 的执行模型。在这个模型中,我们开始在主机设备上执行一个应用程序,这个设备通常是 CPU 核心。该设备是一个面向吞吐量的设备,也就是说,一个 GPU 核心执行并行计算。内核函数用于执行这些并行执行。一旦执行了这些内核函数,控制就被传递回继续执行串行操作的主机设备。

图片

为了方便定位threadidx等,用多维数据来表示,就有了维度。

由于许多并行应用程序涉及多维数据,因此可以很方便地将线程块组织成一维、二维或三维线程数组。grid中的块必须能够独立执行,因为grid中的块之间不可能进行通信或合作。当启动一个内核时,每个线程块的线程数量,并且指定了线程块的数量,这反过来又定义了所启动的 CUDA 线程的总数。

块的最大 x、 y 和 z 维分别为1024、1024和64,其分配应使 x × y × z ≤1024,即每个块的最大线程数。

扩展理解:float4, int4, long4 又是什么?有什么好处?

index 索引

CUDA 中的每个线程都与一个特定的索引相关联,因此它可以计算和访问数组中的内存位置。

举个例子:

其中有一个512个元素的数组。其中一种组织结构是使用一个包含512个线程的单个块的grid。假设有一个由512个元素组成的数组 C,它由两个数组 A 和 B 的元素相乘构成,这两个数组都是512个元素。每个线程都有一个索引 i,它执行 A 和 B 的第 i 个元素的乘法运算,然后将结果存储在 C 的第 i 个元素中。 i 是通过使用 blockIdx (在这种情况下是0,因为只有一个块)、 blockDim (在这种情况下是512,因为块有512个元素)和 threadIdx 计算得到的,每个块的值从0到511不等。

图片

线程索引 i 按以下公式计算:

int i = blockIdx.x * blockDim.x + threadIdx.x;

因此,i的值范围从0到511,覆盖整个数组。但是不一定是连续的,3,4,1,2。。。。

再来:

考虑一个大于1024的数组的计算,我们可以有多个块,每个块有1024个线程。考虑一个包含2048个数组元素的示例。在这种情况下,我们有2个线程块,每个线程有1024个线程。因此线程标识符的值将从0到1023不等,块标识符将从0到1不等,块维度将为1024。因此,第一个块将获得从0到1023的索引值,最后一个块将获得从1024到2047的索引值。

每个线程将首先计算它必须访问的内存索引,然后继续进行计算。举个实际的例子,其中数组 A 和 B 的元素通过使用线程并行添加,结果存储在数组 C 中。线程中相应的代码如下所示

__global__ void vectorAdd (float 

*A , float *B , float * C , int n)
{
int index = blockIdx.x *

blockDim.x + threadIdx.x;
    if (index < n)
    {
        C[index] = A[index] + 

B[index] ;
}
}


除了一维还有2/3维度,计算index可以参考公式,也是一样不一定连续, 234,235,200,201......

硬件
==

SM stream Multiprocessor: 流多处理器
-------------------------------

每个SM内又包括了多个SP(streaming processor)。而SP正是实现算数功能的核心部件,可以类比CPU之中的ALU单元,只不过其计算能力要差很多。

![图片](https://img-blog.csdnimg.cn/img_convert/083fc45aefe44f987f017e1416c622c3.png)

可以看到,每个SM内部的SP之间,可以共享一块shared memory。

以及一块指令缓存用于存放指令、一块常量缓存(c-cache)用来存放常量数据,两个SFU(特殊运算单元,special function unit)用来做三角函数等较复杂运算,MT issue用来实现多线程下的取指,以及DP(Double Precision Unit)用来做双精度数。 除去一些运算单元之外,最重要的就是c-cache与shared memory两块数据存储区。`注意这两个位置的数据只能由SM内部的SP进行访问`,SM之间也有用于数据交换的区域。最主要的是global memory。

硬件将线程块调度到一个 SM。一般来说,SM 可以同时处理多个线程块。一个 SM 可能总共包含多达8个线程块。线程 ID 由其各自的 SM 分配给线程。

每当 SM 执行一个线程块时,线程块中的所有线程都同时执行。因此,为了释放 SM 内部线程块的内存,关键是该块中的整个线程集都已结束执行。每个线程块被划分为预定的单元,称为warp。

warp (wave、wavefront)
---------------------

不同GPU vendor叫法不一样,A卡叫wave,N卡叫warp/卧铺/,我司的也叫wave。我个人理解的就是一波波的相同指令的线程执行,wave好记。

Warp:warp是SM调度和执行的基础概念,通常一个SM中的SP(thread)会分成几个warp(也就是SP在SM中是进行分组的,物理上进行的分组),一般每一个WARP中有32个thread.这个WARP中的32个thread(sp)是一起工作的,执行相同的指令,如果没有这么多thread需要工作,那么这个WARP中的一些thread(sp)是不工作的,叫inactive。

我们应该注意,`线程、线程块和grid本质上是编程的视角`。为了得到一个完整的线程块要点,从硬件的角度了解它是至关重要的。硬件将执行相同指令的线程分组为 `warps` 。几个warps组成一个线程块。几个线程块被分配给一个流式多处理器(SM)。几个 SM 组成了整个 GPU 单元(执行整个内核grid)。

编程的视角与 GPU 中线程块的硬件视角之间的图形关联。

![图片](https://img-blog.csdnimg.cn/img_convert/46bb19fa0941ba3a01ce0bd9542e6b8a.png)

在硬件方面,线程块由“warp”组成。warp是一个线程块中的32个线程的集合,使得warp中的所有线程执行相同的指令。这些线程由 SM 连续选择。

假设有32个执行指令的线程。如果其中一个或两个操作数都没有准备好(例如还没有从全局内存中获取) ,就会发生一个称为“上下文切换”的过程,将控制权转移到另一个指定的操作数上。

当从一个特定的warp切换时,warp的所有数据都保留在寄存器文件中,以便在其操作数准备就绪时能够迅速恢复。当一条指令没有突出的数据依赖关系时,也就是说,它的两个操作数都准备好了,就认为各自的偏差已经准备好可以执行了。如果有多个warp符合执行条件,则父 SM 使用一个warp调度策略来决定哪个warp获取下一个提取指令。

> warp调度有不同的策略,这个有点深入,先不看,加个#TODO。比如RR、LRF、FAIR、CAWS。

Read more
---------

https://en.wikipedia.org/wiki/Thread\_block\_(CUDA\_programming)

https://www.nvidia.com/content/PDF/fermi\_white\_papers/NVIDIA\_Fermi\_Compute\_Architecture\_Whitepaper.pdf

http://www.uml.org.cn/embeded/201809034.asp?artid=21130

https://www.cnblogs.com/maomaozi/p/15939275.html

> github博客\[1\]
> 
> 微信公众号:cdtfug, 欢迎关注一起吹牛逼,也可以加微信号「xiaorik」朋友圈围观。

### 参考:


 github博客: https://chasays.github.io/
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CUDA 基础 01 - 概念 的相关文章

  • CUDA:如何在设备上填充动态大小的向量并将其内容返回到另一个设备函数?

    我想知道哪种技术可以填充设备上的动态大小数组 int row 在下面的代码中 然后返回其内容 以供另一个设备函数使用 为了将问题置于上下文中 下面的代码尝试使用在 GPU 上运行的高斯 勒让德求积来跨越勒让德多项式基组中的任意函数 incl
  • cudaMemcpyToSymbol 的问题

    我正在尝试复制到恒定内存 但我不能 因为我对 cudaMemcpyToSymbol 函数的用法有误解 我正在努力追随this http developer download nvidia com compute cuda 4 1 rel t
  • cudaMallocManaged() 返回“不支持的操作”

    在 CUDA 6 0 中尝试托管内存给了我operation not supported打电话时cudaMallocManaged include cuda runtime h include
  • 寻找 CUDA 中的最大值

    我正在尝试在 CUDA 中编写代码来查找最大值 对于给定的一组数字 假设您有 20 个数字 并且内核在 2 个块 每块 5 个线程 上运行 现在假设 10 个线程同时比较前 10 个值 并且thread 2找到最大值 因此线程 2 正在更新
  • 在 cuda 的 nvcc 编译器中使用 C++20

    我正在尝试使用std countr zero 函数从
  • 如何确定完整的 CUDA 版本 + 颠覆版本?

    Linux 上的 CUDA 发行版曾经有一个名为version txt例如 CUDA Version 10 2 89 这非常有用 但是 从 CUDA 11 1 开始 该文件不再存在 我如何在 Linux 上通过命令行确定并检查 path t
  • CUDA Visual Studio 2010 Express 构建错误

    我正在尝试在 64 位 Windows 7 上使用 Visual Studio 2010 Express 在 Windows 上开始 CUDA 编程 我花了一段时间来设置环境 然后我刚刚编写了我的第一个程序 helloWorld cu 目前
  • 设置最大 CUDA 资源

    我想知道是否可以设置 CUDA 应用程序的最大 GPU 资源 例如 如果我有一个 4GB GPU 但希望给定的应用程序只能访问 2GB 如果它尝试分配更多 就会失败 理想情况下 这可以在进程级别或 CUDA 上下文级别上设置 不 目前没有允
  • 使用 CUDA 进行逐元素向量乘法

    我已经在 CUDA 中构建了一个基本内核来执行逐元素两个复向量的向量 向量乘法 内核代码插入如下 multiplyElementwise 它工作正常 但由于我注意到其他看似简单的操作 如缩放向量 在 CUBLAS 或 CULA 等库中进行了
  • CUDA 矩阵加法时序,按行与按行比较按栏目

    我目前正在学习 CUDA 并正在做一些练习 其中之一是实现以 3 种不同方式添加矩阵的内核 每个元素 1 个线程 每行 1 个线程和每列 1 个线程 矩阵是方阵 并被实现为一维向量 我只需用以下命令对其进行索引 A N row col 直觉
  • 在 cudaFree() 之前需要 cudaDeviceSynchronize() 吗?

    CUDA 版本 10 1 帕斯卡 GPU 所有命令都发送到默认流 void ptr cudaMalloc ptr launch kernel lt lt lt gt gt gt ptr cudaDeviceSynchronize Is th
  • cuda中内核的并行执行

    可以说我有三个全局数组 它们已使用 cudaMemcpy 复制到 GPU 中 但 c 中的这些全局数组尚未使用 cudaHostAlloc 分配 以便分配页面锁定的内存 而不是简单的全局分配 int a 100 b 100 c 100 cu
  • cudaMemcpy() 与 cudaMemcpyFromSymbol()

    我试图找出原因cudaMemcpyFromSymbol 存在 似乎 symbol func 可以做的所有事情 nonSymbol cmd 也可以做 symbol func 似乎可以轻松移动数组或索引的一部分 但这也可以使用 nonSymbo
  • 如何为 CUDA 内核选择网格和块尺寸?

    这是一个关于如何确定CUDA网格 块和线程大小的问题 这是对已发布问题的附加问题here https stackoverflow com a 5643838 1292251 通过此链接 talonmies 的答案包含一个代码片段 见下文 我
  • 内联 PTX 汇编代码强大吗?

    我看到一些代码示例 人们在 C 代码中使用内联 PTX 汇编代码 CUDA工具包中的文档提到PTX很强大 为什么会这样呢 如果我们在 C 代码中使用这样的代码 我们会得到什么好处 内联 PTX 使您可以访问未通过 CUDA 内在函数公开的指
  • 最小化 MC 模拟期间存储的 cuRAND 状态数量

    我目前正在 CUDA 中编写蒙特卡罗模拟 因此 我需要生成lots使用随机数cuRAND图书馆 每个线程处理一个巨大的元素floatarray 示例中省略 并在每次内核调用时生成 1 或 2 个随机数 通常的方法 参见下面的示例 似乎是为每
  • “gld/st_throughput”和“dram_read/write_throughput”指标之间有什么区别?

    在 CUDA 可视化分析器版本 5 中 我知道 gld st requested throughput 是应用程序请求的内存吞吐量 然而 当我试图找到硬件的实际吞吐量时 我很困惑 因为有两对似乎合格的指标 它们是 gld st throug
  • CUDA 中指令重放的其他原因

    这是我从 nvprof CUDA 5 5 获得的输出 Invocations Metric Name Metric Description Min Max Avg Device Tesla K40c 0 Kernel MyKernel do
  • cuda-gdb 错误消息

    我尝试使用 cuda gdb 调试我的 CUDA 应用程序 但遇到了一些奇怪的错误 我设置了选项 g G O0构建我的应用程序 我可以在没有 cuda gdb 的情况下运行我的程序 但没有得到正确的结果 因此我决定使用 cuda gdb 但
  • CUDA:获取数组中的最大值及其索引

    我有几个块 每个块在整数数组的单独部分上执行 举个例子 块一从 array 0 到 array 9 块二从 array 10 到 array 20 我可以获得每个块的数组最大值的索引的最佳方法是什么 示例块一 a 0 到 a 10 具有以下

随机推荐

  • MMC、SD、TF、SDIO、SDMMC简介

    MMC 概念 MMC的全称是 MultiMediaCard 所以也通常被叫做 多媒体卡 是一种小巧大容量的快闪存储卡 特别应用于移动电话和数字影像及其他移动终端中 外形及接口定义 如上图所示 MMC存贮卡只有7pin 可以支持MMC和SPI
  • 如何将ChatGPT培养成「私人助理」

    让她先懂你 然后再AI你 人类的爱建立在相互理解的基础上 而人工智能也是如此 因此 使用ChatGPT并不仅仅是一种训练 而更是一种相互理解的过程 与许多介绍如何使用ChatGPT进行编程 翻译 信息查找或闲聊的文章不同 本文旨在介绍如何在
  • (附源码)计算机毕业设计ssm大学生网络安全题库系统

    项目运行 环境配置 Jdk1 8 Tomcat7 0 Mysql HBuilderX Webstorm也行 Eclispe IntelliJ IDEA Eclispe MyEclispe Sts都支持 项目技术 SSM mybatis Ma
  • 武汉腾讯前端一面

    腾讯文档前端开发工程师 1 自我介绍 2 项目难点及解决方案 3 Vue双向数据绑定原理 4 diff算法 5 递归实现方式 6 深浅拷贝 object assign 7 跨域原因及解决方式 你公司项目是怎么解决的 8 webpack 9
  • JSON与String字符串相互转换的方法

    首先创建一个简单的类 package com wei demo pojo Author wei Date 2022 6 2 9 24 Version 1 0 public class Teacher private int id priva
  • ASP精华[转]

  • Linux命令:ps

    ps命令 查看系统中的进程状态 ps命令的参数以及作用 参数 作用 a 显示所有进程 包括其他用户的进程 u 用户及其他详细信息 x 显示没有控制终端的进程 Linux系统中时刻运行许多进程 如果能够合理的管理它们 则可以优化系统性能 si
  • js中使用DES加解密解决方案总结

    js中使用DES加解密解决方案总结 1 需求背景 最近开发vue项目中 对于用户手机号码需要进行DES加解密操作 简介 DES加密 是一种比较传统的加密方式 其加密运算 解密运算使用的是同样的密钥 信息的发送者和信息的接收者在进行信息的传输
  • 【MLOps】第 1 章 : 为什么选择它以及现在面临的挑战

    大家好 我是Sonhhxg 柒 希望你看完之后 能对你有所帮助 不足请指正 共同学习交流 个人主页 Sonhhxg 柒的博客 CSDN博客 欢迎各位 点赞 收藏 留言 系列专栏 机器学习 ML 自然语言处理 NLP 深度学习 DL fore
  • 常用数组方法总结

    添加 删除元素 push items 从结尾添加元素 pop 从结尾弹出 提取元素 unshift items 从开头添加元素 shift 从开头提取元素 splice pos deleteCount items 从index开始 删除de
  • win10 安装 python报错-已安装这个产品的另一版本

    尝试清理干净电脑上关于之前安装的Python3 在 输入win R 输入cmd 回车 输入 python 回车 却看到 C Users 86136 gt python python 不是内部或外部命令 也不是可运行的程序 或批处理文件 但是
  • Python pd.merge()函数介绍(全)

    目录 1 前言 2 参数介绍 参数如下 3 基础案例 3 1on关键字演示 3 2left on 和 right on 关键字 3 3left index 和 right index 关键字 3 4数据连接的类型 3 4 1 1 前言 在数
  • 4.3 Verilog练习(2)

    目录 练习五 用always块实现较复杂的组合逻辑电路 练习六 在Verilog HDL中使用函数 练习七 在Verilog HDL中使用任务 task 练习八 利用有限状态机进行复杂时序逻辑的设计 练习五 用always块实现较复杂的组合
  • leveldb注释7–key与value

    作为一个kv的系统 key的存储至关重要 在leveldb中 主要涉及到如下几个key user key InternalKey与LookupKey memtable key 其关系构成如下图 user key就是用户输入的key 而Int
  • 华为OD机试 - 第k个排列(Java )

    题目描述 给定参数n 从1到n会有n个整数 1 2 3 n 这n个数字共有n 种排列 按大小顺序升序列出所有排列的情况 并一一标记 当n 3时 所有排列如下 123 132 213 231 312 321 给定n和k 返回第k个排列 输入描
  • 关于校园招聘的感受(汇总)

    对招聘会的法想法 今天春季招聘会在我校的西苑体育馆拉开了序幕 我作为大二的一名学生去看了此次招聘会 进到馆内 第一反应就是一个人 多 人多 单位多 感觉到以后大四毕业就业的压力 那么多学长学姐把自己简历送到各个用人单位 开始面试 考官出的题
  • java 动态代理

    动态代理 这里讲解jdk 动态代理 不讲解cglib动态代理 使用jdk 的InvocationHandler接口与Proxy类实现动态代理 自定义InvocationHandler接口与Proxy类 自定义实现 分析 我们想要实现动态代理
  • dcdc升压计算器excel_优秀DCDC升压

    Figure 1 Basic Application Circuit GENERAL DESCRIPTION The MT3608 is a constant frequency 6 pin SOT23 current mode step
  • pycharm简单使用(Mac):创建一个helloWord

    说明 VSCode是一款轻量级的开发工具 可以支持多款插件这个学习使用确实是一个好的工具 PyCharm是一款Python专门支持的IDE 为什么这里要使用PyCharm呢 PyCharm支持断点调试 1 第一步 创建一个项目 2 第二步
  • CUDA 基础 01 - 概念

    最近在GPU编译器测试方面遇到一些瓶颈 准备学习下cuda 相关的基础知识 warp sm index grid等 CPU VS GPU GPU最重要的一点是可以并行的实现数据处理 这一点在数据量大 运算复杂度不高的条件下极为适用 可以简单