CUDA 12.4文档2 内核线程架构

本博客参考官方文档进行介绍,全网仅此一家进行中文翻译,走过路过不要错过。

官方网址:https://docs.nvidia.com/cuda/cuda-c-programming-guide/

本文档分成多个博客进行介绍,在本人专栏中含有所有内容:

https://blog.csdn.net/qq_33345365/category_12610860.html

CUDA 12.4为2024年3月2日发表,本专栏开始书写日期2024/4/8,当时最新版本4.1

本人会维护一个总版本,一个小章节的版本,总版本会持续更新,小版本会及时的调整错误和不合理的翻译,内容大部分使用chatGPT 4翻译,部分内容人工调整


开始编辑时间:2024/4/8;最后编辑时间:2024/4/10

5.1 内核Kernels

CUDA C++通过允许程序员定义C++函数,称为内核,当被调用时,这些函数由N个不同的CUDA线程并行执行N次,而不是像常规的C++函数那样只执行一次。

内核使用 global 声明说明符定义,并且给定内核调用的执行该内核的CUDA线程数使用新的 <<<...>>>执行配置语法指定。执行内核的每个线程都被赋予一个在内核内通过内置变量可以访问的唯一线程ID。

作为示例,以下样本代码使用内置变量 threadIdx,将两个大小为N的向量A和B相加,并将结果存储到向量C中:

__global__ void VecAdd(float* A, float* B, float* C)
{
    int i = threadIdx.x;
    C[i] = A[i] + B[i];
}
int main()
{
    ...
    ∕∕ Kernel invocation with N threads
    VecAdd<<<1, N>>>(A, B, C);
    ...
}

在这里,执行VecAdd()的N个线程中的每一个都执行一次成对的加法。

5.2 线程架构

为了方便,threadIdx是一个三组件向量,因此可以使用一维、二维或三维的线程索引来标识线程,形成一个一维、二维或三维的线程块,称为线程块。这为在像向量、矩阵或体积等域中的元素之间调用计算提供了一种自然的方式。

线程的索引和线程ID之间的关系很直接:对于一维的块,它们是相同的;对于大小为(Dx, Dy)的二维块,索引为(x, y)的线程的线程ID为(x + y Dx);对于大小为(Dx, Dy, Dz)的三维块,索引为(x, y, z)的线程的线程ID为(x + y Dx + z Dx Dy)。

下面的代码就是一个例子,它将两个NxN大小的矩阵A和B加在一起,并将结果存储到矩阵C中:

__global__ void MatAdd(float A[N][N], float B[N][N],
                       float C[N][N])
{
    int i = threadIdx.x;
    int j = threadIdx.y;
    C[i][j] = A[i][j] + B[i][j];
}
int main()
{
    ...
    ∕∕ Kernel invocation with one block of N * N * 1 threads
    int numBlocks = 1;
    dim3 threadsPerBlock(N, N);
    MatAdd<<<numBlocks, threadsPerBlock>>>(A, B, C);
    ...
}

每个块的线程数量是有限的,因为所有的线程都应该存在于同一个流式多处理器核心上,并且必须共享这个核心的有限的内存资源。在当前的GPU上,一个线程块可能包含多达1024个线程。

然而,一个内核可以被多个形状相同的线程块执行,这样总的线程数量等于每个块的线程数量乘以块的数量。

块被组织成一个一维、二维或三维的线程块网格,如图4所示。网格中线程块的数量通常由被处理的数据的大小决定,这通常超过了系统中的处理器数量。

在这里插入图片描述

图4:线程块的网格

<<<...>>>语法中指定的每个块的线程数量和每个网格的块数量可以是int类型或dim3类型。可以像上面的例子那样指定二维的块或网格。

网格内的每个块都可以通过一个一维、二维或三维的唯一索引来标识,这个索引在内核中可以通过内置的blockIdx变量访问。线程块的维度在内核中可以通过内置的blockDim变量访问。

下面的代码是将前面的MatAdd()示例扩展为处理多个块的情况:

// 内核定义
__global__ void MatAdd(float A[N][N], float B[N][N],
                       float C[N][N])
{
    int i = blockIdx.x * blockDim.x + threadIdx.x;
    int j = blockIdx.y * blockDim.y + threadIdx.y;
    if (i < N && j < N)
        C[i][j] = A[i][j] + B[i][j];
}
int main()
{
    ...
    ∕∕ Kernel invocation
    dim3 threadsPerBlock(16, 16);
    dim3 numBlocks(N ∕ threadsPerBlock.x, N ∕ threadsPerBlock.y);
    MatAdd<<<numBlocks, threadsPerBlock>>>(A, B, C);
    ...
}

线程块的大小为16x16(256个线程),尽管在这种情况下是任意的,但这是一个常见的选择。如前所述,创建足够的块,每个矩阵元素有一个线程。为了简单起见,这个例子假设每个维度的网格线程数可以被该维度的块线程数整除,尽管并非一定是这种情况。

线程块需要独立执行:它们必须能够按任何顺序执行,可以并行也可以串行。这种独立性要求允许线程块按任何顺序在任何数量的核心上调度,如图3所示,使程序员能写出随核心数量扩展的代码。

块内的线程可以通过共享一些共享内存和同步它们的执行来协调内存访问来合作。更精确地说,可以在内核中通过调用__syncthreads()内在函数来指定同步点;__syncthreads()充当一个屏障,所有的块内线程都必须在这里等待,直到允许任何线程继续。共享内存章节给出了一个使用共享内存的例子。除了__syncthreads(),协作组API章节还提供了一整套丰富的线程同步原语。

为了有效的合作,预计共享内存是接近每个处理器核心的低延迟内存(很像L1缓存),并且__syncthreads()预计是轻量级的。

5.2.1 线程块集群 Thread Block Clusters

设计线程数:共享内存上同步 < 线程块集群内同步 < 全局同步

随着NVIDIA计算能力9.0的引入,CUDA编程模型引入了一个叫做线程块群集的可选等级层次,这些都是由线程块构成的。与线程块中的线程保证在流式多处理器上被并行调度类似,线程块群集中的线程块也保证在GPU处理集群(GPC)上进行并行调度。

与线程块类似,群集也以一维、二维或三维的方式组织,如图5所示。群集中的线程块数量可以由用户定义,CUDA中支持以8个线程块为单位的群集大小作为最大限制。注意,在GPU硬件或MIG配置中,如果太小以致不能支持8个多处理器,那么最大群集大小将相应减小。识别这些较小的配置,以及支持线程块群集大小超过8的较大配置,是架构特定的,并可以使用cudaOccupancyMaxPotentialClusterSize API进行查询。

在这里插入图片描述

图5:线程块集群的网格

在使用群集支持启动的内核中,为了兼容性,gridDim变量仍然表示线程块数量的大小。可以通过使用Cluster Group API找到群集中块的等级。

线程块群集可以通过使用__cluster_dims__(X,Y,Z)的编译器时间内核属性或使用CUDA内核启动API cudaLaunchKernelEx在内核中启用。下面的例子展示了如何使用编译器时间内核属性启动一个群集。使用内核属性的群集大小在编译时固定,然后可以使用经典的<<<,>>>来启动内核。如果内核使用编译时群集大小,那么在启动内核时,群集大小不能被修改。

∕∕ 内核定义, Compile time cluster size 2 in X-dimension and 1 in Y and Z dimension
__global__ void __cluster_dims__(2, 1, 1) cluster_kernel(float *input, float* output)
{ }
int main()
{
    float *input, *output;
    ∕∕ Kernel invocation with compile time cluster size
    dim3 threadsPerBlock(16, 16);
    dim3 numBlocks(N ∕ threadsPerBlock.x, N ∕ threadsPerBlock.y);
    ∕∕ The grid dimension is not affected by cluster launch, and is still enumerated
    ∕∕ using number of blocks.
    ∕∕ The grid dimension must be a multiple of cluster size.
    cluster_kernel<<<numBlocks, threadsPerBlock>>>(input, output);
}

线程块群集大小也可以在运行时设置,并通过CUDA内核启动API cudaLaunchKernelEx启动内核。下面的代码示例展示了如何使用可扩展API启动一个群集内核。

∕∕ 内核定义
∕∕ No compile time attribute attached to the kernel
__global__ void cluster_kernel(float *input, float* output)
{ }
int main()
{
    float *input, *output;
    dim3 threadsPerBlock(16, 16);
    dim3 numBlocks(N ∕ threadsPerBlock.x, N ∕ threadsPerBlock.y);
    ∕∕ Kernel invocation with runtime cluster size
    {
        cudaLaunchConfig_t config = {0};
        ∕∕ The grid dimension is not affected by cluster launch, and is still enumerated
        ∕∕ using number of blocks.
        ∕∕ The grid dimension should be a multiple of cluster size.
        config.gridDim = numBlocks;
        config.blockDim = threadsPerBlock;
        cudaLaunchAttribute attribute[1];
        attribute[0].id = cudaLaunchAttributeClusterDimension;
        attribute[0].val.clusterDim.x = 2; ∕∕ Cluster size in X-dimension
        attribute[0].val.clusterDim.y = 1;
        attribute[0].val.clusterDim.z = 1;
        config.attrs = attribute;
        config.numAttrs = 1;
        cudaLaunchKernelEx(&config, cluster_kernel, input, output);
    }
}

在具有9.0计算能力的GPU中,群集中的所有线程块都保证在单个GPU处理集群(GPC)上进行协同调度,并允许群集中的线程块使用Cluster Group API cluster.sync()执行硬件支持的同步。群集组还提供成员函数,使用num_threads()num_blocks()API分别查询群集组大小,以线程数量或块数量表示。群集组中的线程或块的排名可以使用dim_threads()dim_blocks()API分别进行查询。

属于群集的线程块可以访问分布式共享内存。群集中的线程块具有读取、写入和执行分布式共享内存中任何地址的原子操作的能力。分布式共享内存章节给出了在分布式共享内存中执行直方图的示例。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/530895.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网络学习学习笔记

NETEBASE学习笔记 一.VRP系统1.四种视图模式2.基础命令 二.TCP/IP1.五层模型 一.VRP系统 1.四种视图模式 (1)< Huawei > 用户视图 【查看运行状态】 (2)[Huawei] 系统视图 【配置设备的系统参数】 system-view /sys 进入系统视图 CtrlZ/return 直接返回用户视图 (3)[Hua…

AR远程空间标注Vuforia+WebRTC音视频通话和空间标注功能

AR远程空间标注VuforiaWebRTC音视频通话和空间标注功能 视频学习地址&#xff1a;https://www.bilibili.com/video/BV1ZT4y187mG/?vd_sourcefc4b6cdd80b58c93a280fd74c37aadbf

李沐23_LeNet——自学笔记

手写的数字识别 知名度最高的数据集&#xff1a;MNIST 1.训练数据&#xff1a;50000 2.测试数据&#xff1a;50000 3.图像大小&#xff1a;28✖28 4.10类 总结 1.LeNet是早期成功的神经网络 2.先使用卷积层来学习图片空间信息 3.使用全连接层来转换到类别空间 代码实现…

学习记录:bazel和cmake运行终端指令

Bazel和CMake都是用于构建软件项目的工具&#xff0c;但它们之间有一些重要的区别和特点&#xff1a; Bazel&#xff1a; Bazel是由Google开发的构建和测试工具&#xff0c;用于构建大规模的软件项目。它采用一种称为“基于规则”的构建系统&#xff0c;它利用构建规则和依赖关…

Android 属性动画及自定义3D旋转动画

Android 动画框架 其中包括&#xff0c;帧动画、视图动画&#xff08;补间动画&#xff09;、属性动画。 在Android3.0之前&#xff0c;视图动画一家独大&#xff0c;之后属性动画框架被推出。属性动画框架&#xff0c;基本可以实现所有的视图动画效果。 视图动画的效率较高…

第十届蓝桥杯大赛个人赛省赛(软件类) CC++ 研究生组-RSA解密

先把p&#xff0c;q求出来 #include<iostream> #include<cmath> using namespace std; typedef long long ll; int main(){ll n 1001733993063167141LL, sqr sqrt(n);for(ll i 2; i < sqr; i){if(n % i 0){printf("%lld ", i);if(i * i ! n) pri…

关于VMware安装win系统的磁盘扩容与缩减

使用VMware虚拟机安装虚拟windows系统时&#xff0c;如果创建虚拟磁盘的空间预留不足&#xff08;特别是C判空间&#xff09;&#xff0c;安装win系统后&#xff0c;由于默认win系统在安装时分配的healthy健康盘位于系统C盘临近区域&#xff0c;此时如果需要增加C盘虚拟空间&am…

张驰咨询:深圳六西格玛绿带培训5天专业能力提升课程

张驰咨询即将在深圳开设的六西格玛绿带5天培训班&#xff0c;是针对希望在质量管理、项目管理等领域提升自己能力的专业人士的一次重要机会。六西格玛作为一种旨在减少缺陷、提高效率和质量的方法论&#xff0c;已经被全球众多企业采用。绿带认证作为进入这一领域的门槛之一&am…

【产品】ADW300 无线计量仪表 用于计量低压网络的三相有功电能

1 概述 ADW300 无线计量仪表主要用于计量低压网络的三相有功电能&#xff0c;具有体积小、精度高、功能丰富等优点&#xff0c;并且可选通讯方式多&#xff0c;可支持 RS485 通讯和 Lora、2G、NB、4G 等无线通讯方式&#xff0c;增加了外置互感器的电流采样模式&#xff0c;从…

利用AI开源引擎平台:构建文本、图片及视频内容审核系统|可本地部署

网络空间的信息量呈现出爆炸式增长。在这个信息多元化的时代&#xff0c;内容审核系统成为了维护网络秩序、保护用户免受有害信息侵害的重要工具。本文将探讨内容审核系统的核心优势、技术实现以及在不同场景下的应用。 开源项目介绍(可本地部署&#xff0c;支持国产化) 思通数…

法拉电容Farad capacitor与锂电池的区别和对比!

法拉电容也称为超级电容。超级电容器是介于传统电容器和充电电池之间的一种新型环保储能装置&#xff0c;其容量可达0.1F至>10000F法拉&#xff0c;与传统电容器相比&#xff1a;它具有较大的容量、较高的能量、较宽的工作温度范围和极长的使用寿命&#xff1b;而与蓄电池相…

linux网络知识

七层模型 应用层 为操作系统或者网络应用程序提供网络服务的接口 表示层 解决不同系统之间的通信问题&#xff0c;负责数据格式的转换 会话层 自动收发包&#xff0c;自动寻址&#xff0c;负责建立和断开连接 传输层 将上层数据分段并提供端到端的…

机器学习 —— 使用机器学习进行情感分析 演示版

机器学习 —— 使用机器学习进行情感分析 详细介绍版 机器学习 —— 使用机器学习进行情感分析 演示版 一、项目构想 在现代互联网时代里&#xff0c;人们的意见、评论和建议已成为政治科学和企业的宝贵资源。借助现代技术&#xff0c;我们现在能够最有效地收集和分析此类数据。…

第十五届蓝桥杯测试组模拟赛两期

文章目录 功能测试一期-场景法-登录功能一期-等价类-边界值-添加用户账号输入框一期-登录-缺陷报告一期- UI自动化测试一期-单元测试-路径覆盖二期-正交法-搜索条件组合二期-测试用例二期-缺陷报告二期-自动化测试二期-单元测试-基本路径覆盖 功能测试 一期-场景法-登录功能 …

什么是 DNS 记录?

DNS记录是存储在DNS服务器上的文本指令。它们表明与一个域名相关的IP地址&#xff0c;也可以提供其他信息。DNS记录是计算机用语&#xff0c;指域名系统&#xff08;Domain Name System&#xff0c;简称DNS&#xff09;中的一条记录&#xff0c;这条记录存储于DNS服务器中。每一…

html基础(2)(链接、图像、表格、列表、id、块)

1、链接 <a href"https://www.example.com" target"_blank" title"Example Link">Click here</a> 在上示例中&#xff0c;定义了一个链接&#xff0c;在网页中显示为Click here&#xff0c;鼠标悬停指示为Example Link&#xff0c…

Bootstrap 5 保姆级教程(一):容器 网格系统

一、容器 1.1 固定宽度&#xff08;.container&#xff09; .container 类用于固定宽度并支持响应式布局的容器。 以下实例中&#xff0c;我们可以尝试调整浏览器窗口的大小来查看容器宽度在不同屏幕中等变化&#xff1a; <!doctype html> <html lang"en&quo…

4.2.4 理解路由器数据包过程

1、实验目的 通过本实验可以掌握&#xff1a; 了解IP路由原理了解数据包封装和解封装的概念了解路由器路由和交换过程 2、实验拓扑 观察路由器路由数据包过程的实验拓扑如图4-3所示&#xff0c;设备接口地址信息如表4-2所示。 图4-3 观察路由器路由数据包过程的实验拓扑 本…

文件批量重命名,繁体中文秒变简体中文,轻松实现高效翻译

在数字化时代&#xff0c;我们的工作、学习和生活都离不开电脑文件。随着时间的推移&#xff0c;文件数量不断增加&#xff0c;管理起来变得越来越困难。你是否曾经为如何高效、有序地管理文件而烦恼&#xff1f;现在&#xff0c;有一款强大的文件批量重命名工具&#xff0c;它…

CAXA3D工艺图表2019版 下载地址及安装教程

CAXA 3D工艺图表是CAXA 3D软件中的一个功能模块&#xff0c;专门用于创建和展示工艺流程和工艺图。它为工程师和设计师提供了一种直观和清晰的方式来表示和记录产品的工艺过程。 使用CAXA 3D工艺图表&#xff0c;用户可以创建具有层次结构的工艺流程图&#xff0c;显示产品的各…