CUDA从入门到放弃(四):CUDA 编程模式 CUDA Programming Model

CUDA从入门到放弃(四):CUDA 编程模式 CUDA Programming Model

1 Kernels

CUDA C++ 扩展了 C++,允许定义名为内核的函数,这些函数可以被不同的 CUDA 线程并行执行多次,而不是像普通 C++ 函数那样只执行一次。内核通过 global 声明符定义,执行内核的 CUDA 线程数通过特殊的执行配置语法指定。每个执行内核的线程都有一个唯一的线程 ID,可在内核内部通过内置变量获取。

// Kernel definition
__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);
    ...
}

2 Thread Hierarchy 线程结构

为了方便起见,threadIdx 是一个三分量向量,因此可以使用一维、二维或三维线程索引来识别线程,形成一个一维、二维或三维的线程块,称为线程块。

每个线程块内的线程数有上限,因为所有线程需共享同一流式多处理器核心的有限内存资源。目前GPU上,线程块最多包含1024个线程。 尽管如此,一个内核可以由多个相同形状的线程块执行,总线程数等于每个块的线程数乘以块的数量。
在这里插入图片描述

线程块组织成一维、二维或三维网格,由数据大小决定,通常超出系统处理器数量。在执行配置语法中指定的线程数和块数可以是int或dim3类型。每个块通过内置的blockIdx变量在内核中按唯一索引识别,线程块维度通过内置的blockDim变量获取。

∕∕ Kernel definition
__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);
	...
}

线程块需能独立执行,可任意顺序并行或串行执行。这允许在多个核心上灵活调度线程块,使代码能随核心数扩展。

块内线程通过共享内存和执行同步来协作,使用__syncthreads()函数设置同步点,作为所有线程必须等待的屏障。共享内存应为低延迟内存,类似于L1缓存,且__syncthreads()操作应轻量级。

2-1 Thread Block Clusters 线程块集群

NVIDIA计算能力9.0引入了一个新的层级结构——线程块集群,由线程块组成。线程块集群中的线程块保证在GPU的处理集群上共同调度。集群可以是一维、二维或三维结构,用户可自定义集群中的线程块数量,CUDA中推荐的最大集群大小为8个线程块。对于小于8个多处理器的GPU硬件或MIG配置,最大集群大小会相应减少。可以通过cudaOccupancyMaxPotentialClusterSize API查询特定架构支持的集群大小。
在这里插入图片描述
线程块集群可以在内核中通过使用编译时内核属性 cluster_dims(X,Y,Z) 或者使用CUDA内核启动API cudaLaunchKernelEx 来启用。

2-1-1 编译时内核属性启动集群

使用内核属性的集群大小在编译时固定,然后可以使用传统的 <<< , >>> 语法启动内核。如果一个内核使用了编译时集群大小,那么在启动内核时不能修改集群大小。

∕∕ Kernel definition
∕∕ 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);
}
2-1-2 cudaLaunchKernelEx 来启动内核

使用CUDA内核启动API cudaLaunchKernelEx 来启动内核

∕∕ Kernel definition
∕∕ 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);
	}
}

3 Memory Hierarchy 内存结构

CUDA线程在执行过程中可能会访问多个内存空间。每个线程都有私有的本地内存。每个线程块都有共享内存,对块内的所有线程可见,并且与块的生命周期相同。线程块集群中的线程块可以对彼此的共享内存执行读、写和原子操作。所有线程都可以访问相同的全局内存。
在这里插入图片描述

4 Heterogeneous Programming

CUDA编程模型假定CUDA线程在物理上独立的设备上执行,作为运行C++程序的主机的协处理器,如GPU和CPU的组合使用。主机和设备各自维护独立的DRAM内存空间。程序通过CUDA运行时管理内核可见的内存空间,包括内存分配、释放和主机与设备间的数据传输。统一内存提供托管内存,实现主机与设备内存空间的统一管理,简化了应用程序的移植过程。
在这里插入图片描述

参考资料
1 CUDA编程入门
2 CUDA编程入门极简教程
3 CUDA C++ Programming Guide
4 CUDA C++ Best Practices Guide
5 NVIDIA CUDA初级教程视频
6 CUDA专家手册 [GPU编程权威指南]
7 CUDA并行程序设计:GPU编程指南
8 CUDA C编程权威指南

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

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

相关文章

Python数据结构实验 递归算法设计

一、实验目的 1&#xff0e;掌握递归程序设计的基本原理和方法&#xff1b; 2&#xff0e;熟悉数据结构中顺序表和单链表下的递归算法设计思想&#xff1b; 3&#xff0e;掌握并灵活运用递归算法解决一些较复杂的应用问题。 二、实验环境 1&#xff0e;Windows操作系统的计…

使用JMeter进行梯度压测

使用JMeter进行梯度压测 梯度压测配置如下&#xff1a; 使用线程:5&#xff0c;然后循环5000次&#xff0c;共2.5万个样本使用线程:10&#xff0c;然后循环5000次&#xff0c;共5万个样本使用线程:15&#xff0c;然后循环5000次&#xff0c;共7.5万个样本使用线程:20&#xff…

投资现货黄金有持仓时间限制吗?

投资现货黄金是否有持仓时间限制&#xff1f;这是许多投资者在进入黄金市场前都想要了解的一个问题。实际上&#xff0c;现货黄金交易并没有严格的持仓时间限制。换句话说&#xff0c;投资者可以按照个人的投资策略和市场情况自由决定持有黄金的时间长度。 以下是影响现货黄金持…

数据结构(四)顺序表与链表的深层次讲解

我们在数据结构&#xff08;二&#xff09;&#xff0c;对链表和顺序表已经讲解过了。但很多同学表示有点晦涩难懂那我就出一篇深层次讲解&#xff0c;一步一步来带领大家学习。 我们从头&#xff08;数据结构&#xff09;开始完整的来为大家讲解&#xff0c;大家好好看好好学。…

c语言中函数声明注意点都在这里了

C语言中函数声明主要分为三个大点&#xff1a;函数返回值类型、函数名和参数列表。 一、函数返回值类型 1. 无返回值的函数声明 无返回值的函数声明使用关键字void表示&#xff0c;表示该函数不返回任何值。例如&#xff1a; void print_hello(); // 声明一个无返回值的函数…

【Emgu CV教程】10.5、轮廓之凸包

文章目录 一、什么叫轮廓的凸包二、凸包函数三、二维点集寻找凸包四、绘制物体轮廓的凸包1.原始素材2.代码3.运行结果 一、什么叫轮廓的凸包 凸包是一个更加简化的多边形&#xff0c;是轮廓最外层的“凸”多边形&#xff0c;与前一篇多边形近似拟合不同的是&#xff0c;凸包组…

学生宿舍智能控电柜安装调试技术

学生宿舍智能控电柜安装调试石家庄光大远通电器有限公司宿舍控电限电管理系统是一种用于管理学生宿舍用电的智能系统&#xff0c;主要功能包括: 1.实时监控和控制:该系统能够实时监测和记录宿舍的用电情况&#xff0c;包括电器使用情况、电量消耗等。管理人员可以通过电脑或手机…

数据结构(五)——树与二叉树的应用

5.5 树与二叉树的应用 5.5.1 哈夫曼树 结点的权&#xff1a;有某种现实含义的数值。 结点的带权路径长度&#xff1a;从树的根到该结点的路径长度&#xff08;经过的边数&#xff09;与该结点上权值的乘积。 树的带权路径长度&#xff1a;树中所有叶结点的带权路径长度之和…

FPGA电平标准

1.LVTTL&#xff1a;&#xff08;3.3v&#xff09; 2.LVCOMS&#xff1a;&#xff08;1.8v&#xff09; 3.LVDS&#xff08;1.8v&#xff09;&#xff1a;LVDS_25&#xff08;2.5v&#xff09; 4&#xff1a;如果是ddr3与fpga相连接fpga的vcco推荐&#xff08;1.5v&#xff09;…

【Linux】进程的基本概念(进程控制块,ps命令,top命令查看进程)

目录 01.进程的基本概念 程序与进程 进程的属性 02.进程控制块&#xff08;PCB&#xff09; task_struct的内容分类 组织进程 03.查看进程 ps命令 top指令 在计算机科学领域&#xff0c;进程是一项关键概念&#xff0c;它是程序执行的一个实例&#xff0c;是操作系统的…

【Linux C | 多线程编程】线程的退出

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a; 本文未经允许…

第九届蓝桥杯大赛个人赛省赛(软件类)真题C 语言 A 组-乘积尾零

solution 找末尾0的个数&#xff0c;即找有多少对2和5 >问题等价于寻找所给数据中&#xff0c;有多少个2和5的因子&#xff0c;较少出现的因子次数即为0的个数 #include <iostream> using namespace std; int main() {// 请在此输入您的代码printf("31");…

项目3-留言板

1.创建项目 记得将project type改为maven 将需要的包引入其中 更改版本号 引入MYSQL相关包记得进行配置&#xff01;&#xff01;&#xff01; spring:datasource:url: jdbc:mysql://127.0.0.1:3306/mycnblog?characterEncodingutf8&useSSLfalseusername: rootpassword:…

MySQL将id相同的两行数据合并group_concat

MySQL将id相同的两行数据合并 group_concat这个函数能将相同的行组合起来&#xff0c;省老事了。 MySQL中group_concat函数 完整的语法如下&#xff1a; group_concat([DISTINCT] 要连接的字段 [Order BY ASC/DESC 排序字段] [Separator ‘分隔符’]) 1.基本查询 Sql代码 2.…

力扣热门算法题 89. 格雷编码,92. 反转链表 II,93. 复原 IP 地址

89. 格雷编码&#xff0c;92. 反转链表 II&#xff0c;93. 复原 IP 地址&#xff0c;每题做详细思路梳理&#xff0c;配套Python&Java双语代码&#xff0c; 2024.03.24 可通过leetcode所有测试用例。 目录 89. 格雷编码 解题思路 完整代码 Python Java 92. 反转链表…

SOC 子模块---中断控制器

中断控制器对soc 中的各个外设进行中断管理&#xff0c;进行优先权排队&#xff0c;并送出IQR信号给CPU&#xff1b; 中断控制器在整个系统中的结构&#xff1a; IRQ<n>来源于不同的中断源&#xff0c;比如&#xff1a;I2C,SPI等&#xff0c;INTC收集这些中断&#xff0…

从人工智能入门到理解ChatGPT的原理与架构的第一天(First)

目录 一.ChatGPT的发展历程 二.Attention is all you need 三.对于GPT-4的智能水平评估 四.大语言模型的技术演化 1.从符号主义到连接主义 2.特征工程 2.1数据探索 2.2数据清洗 2.3数据预处理 2.3.1无量纲化 2.3.1.1标准化 2.3.1.2区间缩放法 2.3.1.3标准化与归一…

Numpy使用中的十大经典routines函数

1.np.ones(shape, dtypeNone, order‘C’) np.ones(shape(3, 4, 3), dtypenp.int32)array([[[1, 1, 1],[1, 1, 1],[1, 1, 1],[1, 1, 1]],[[1, 1, 1],[1, 1, 1],[1, 1, 1],[1, 1, 1]],[[1, 1, 1],[1, 1, 1],[1, 1, 1],[1, 1, 1]]])2.np.zeros(shape, dtypefloat, order‘C’) …

P1835 素数密度题解

题目 给定区间[L,R]&#xff08;1≤L≤R<&#xff0c;R−L≤&#xff09;&#xff0c;请计算区间中素数的个数。 输入输出格式 输入格式 第一行&#xff0c;两个正整数L和R。 输出格式 一行&#xff0c;一个整数&#xff0c;表示区间中素数的个数。 输入输出样例 输…

Python库xarray:强大的多维数据处理工具

Python库xarray&#xff1a;强大的多维数据处理工具 在数据科学和科学计算领域&#xff0c;处理多维数据是一项常见而重要的任务。Python库xarray是一个功能强大的工具&#xff0c;专门用于处理、分析和可视化多维数据集。本文将深入介绍xarray库的特性、用法和优势&#xff0c…