CUDA编程:执行模型

SM

在SM中,共享内存和寄存器是非常重要的资源。共享内存被分配在SM上的常驻线程
块中,寄存器在线程中被分配。线程块中的线程通过这些资源可以进行相互的合作和通
信。

 

WARP

CUDA采用单指令多线程(SIMT)架构来管理和执行线程,每32个线程为一组,被称
为线程束(warp)。线程束中的所有线程同时执行相同的指令。每个线程都有自己的指
令地址计数器和寄存器状态,利用自身的数据执行当前的指令。每个SM都将分配给它的
线程块划分到包含32个线程的线程束中,然后在可用的硬件资源上调度执行。

一个线程块只能在一个SM上被调度。一旦线程块在一个SM上被调度,就会保存在该
SM上直到执行完成。在同一时间,一个SM可以容纳多个线程块

然而,从硬件的角度来看,所有的线程都被组织成了一维的,线程块可以被配置为一
维、二维或三维的。在一个块中,每个线程都有一个唯一的ID。对于一维的线程块,唯一
的线程ID被存储在CUDA的内置变量threadIdx.x中,并且,threadIdx.x中拥有连续值的线程
被分组到线程束中。例如,一个有128个线程的一维线程块被组织到4个线程束里,如下所
示:

内存管理

cudaMalloc

cudaMalloc(void** devPtr,size_t size):用于执行GPU内存分配,向设备分配一定字节的线性内存,并以devPtr的形式返回指向所分配内存的指针。

cudaMemcpy(void* dst,const void* src,size_t count,cudaMemcpyKind kind):负责主机和设备之间的数据传输,从src指向的源存储区复制一定数量的字节到dst指向的目标存储区,复制方向由kind指定。

kind种类:

cudaMemcpyHostToHost

cudaMemcpyHostToDevice

cudaMemcpyDeviceToHost:将存在GPU上的计算结果复制到主机的数组gpuRef中

cudaMemcpyDeviceToDevice

cudaMemcpy

cudaMemcpy()以同步方式执行,在cudaMemcpy函数返回以及传输操作完成之前主机应用程序是阻塞的。除了内核启动之外的CUDA调用都会返回一个错误的枚举类型cudaErroe_t。如果GPU内存分配成功,函数返回cudaSuccess,否则返回cudaErrorMemoryAllocation。

CUDA程序编写优化步骤

如何完成一个优秀的CUDA程序呢?这里有一份步骤给大家参考:

  • 确定任务中的串行和并行的部分,选择合适的算法(首先将问题分解为几个步骤,确定哪些步骤可以用并行实现,并确定合适的算法);

  • 按照算法确定数据和任务的划分方式,将每个需要实现的步骤映射为一个满足CUDA两层并行模型的内核函数,让每个SM上至少有6个活动warp和至少2个活动block;

  • 编写一个能正确运行的程序作为优化的起点,要确保程序能稳定运行以及其正确性,在精度不足或者发生溢出时必须使用双精度浮点或者更长的整数类型;

  • 优化显存访问,避免显存带宽成为瓶颈。在显存带宽得到完全优化前,其他优化不会产生明显效果。

  • 优化指令流,在误差可接受的情况下,使用CUDA算术指令集中的快速指令;避免多余的同步;在只需要少量线程进行操作的情况下,使用类似“if threaded<N”的方式,避免多个线程同时运行占用更长时间或者产生错误结果;

  • 资源均衡,调整每个线程处理的数据量,shared memory和register和使用量;通过调整block大小,修改算法和指令以及动态分配shared memory,都可以提高shared的使用效率;register的多少是由内核程序中使用寄存器最多的时刻的用量决定的,因此减小register的使用相对困难;节约register方法是使用shared memory存储变量;使用括号明确地表示每个变量的生存周期;使用占用寄存器较小的等效指令代替原有指令;

  • 与主机通信优化,尽量减少CPU与GPU间的传输,使用cudaMallocHost分配主机端存储器,可以获得更大带宽;一次缓存较多的数据后再一次传输,可以获得较高的带宽;需要将结果显示到屏幕的时候,直接使用与图形学API互操作的功能;使用流和异步处理隐藏与主机的通信时间;使用zero-memory技术和Write-Combined memory提高可用带宽;

由此我们可以看到我们的优化之路还很漫长,这个优化步骤中的每一步都对应了大量可以去做的优化,上面这个只是个概述,不过我们可以看到有一句非常重要的话:

在显存带宽得到完全优化前,其他优化不会产生明显效果。

所以我们就先不要想其他的了,先完成最基本的优化,去尽可能的使用显卡的内存带宽~

线程束分化

控制流是高级编程语言的基本构造中的一种。GPU支持传统的、C风格的、显式的控
制流结构,例如,if…then…else、for和while。
CPU拥有复杂的硬件以执行分支预测,也就是在每个条件检查中预测应用程序的控制
流会使用哪个分支。如果预测正确,CPU中的分支只需付出很小的性能代价。如果预测不
正确,CPU可能会停止运行很多个周期,因为指令流水线被清空了。我们不必完全理解为
什么CPU擅长处理复杂的控制流。这个解释只是作为对比的背景。
GPU是相对简单的设备,它没有复杂的分支预测机制。一个线程束中的所有线程在同
一周期中必须执行相同的指令,如果一个线程执行一条指令,那么线程束中的所有线程都
必须执行该指令。如果在同一线程束中的线程使用不同的路径通过同一个应用程序,这可
能会产生问题。

因为同一线程束(warp)中的32个线程是严格并行执行相同指令的,那么如果cuda程序中出现分支,导致32个线程无法在同一时刻执行相同指令就会出现线程束分化的问题。比如在一个线程束中16个线程满足条件cond,而剩余16个线程的不满足,所以当前者在执行指令1时,后者则被禁用只能陪跑,反之亦然。所以,就降低了程序的并行性,在实际开发中应尽量避免

if (cond)
{指令1
}
else
{指令2
}

编译器对线程分支的优化能力有限,只有当分支下的代码量很少是优化才会起作用

注意线程束分化研究的是一个线程束中的线程不同线程束中的分支互不影响。

减少线程束分化的方法:线程束内的线程是可以被我们控制的,那么我们就把都执行if的线程塞到一个线程束中,或者让一个线程束中的线程都执行if,另外线程都执行else的这种方式可以将效率提高很多

/******* 假设只配置一个x=64的一维线程块,那么只有两个线程束 *****/
// 1. 这个kernel可以产生一个比较低效的分支
__global__ void mathKernel1(float *c)
{int tid = blockIdx.x* blockDim.x + threadIdx.x;float a = 0.0;float b = 0.0;if (tid % 2 == 0){a = 100.0f;}else{b = 200.0f;}c[tid] = a + b;
}// 2. 进行优化:
//    第一个线程束内的线程编号tid从0到31,tid/warpSize都等于0,那么就都执行if语句。
//    第二个线程束内的线程编号tid从32到63,tid/warpSize都等于1,执行else
//    线程束内没有分支,效率较高。
__global__ void mathKernel2(float *c)
{int tid = blockIdx.x* blockDim.x + threadIdx.x;float a = 0.0;float b = 0.0;if ((tid/warpSize) % 2 == 0){a = 100.0f;}else{b = 200.0f;}c[tid] = a + b;
}

nvprof

nvprof --query-metrics

nvprof --metrics branchefficiency ./sumArray

nvcc -g -G -O2 -arch=sm_70 -o

-g:去除对主机端代码的优化

-G:去除对GPU端代码的优化

线程束分支会降低GPU实际的计算能力

线程束分支对程序性能影响通过分支效率(branch efficiency)衡量

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HarmonyOS4.0——ArkUI应用说明

一、ArkUI框架简介 ArkUI开发框架是方舟开发框架的简称&#xff0c;它是一套构建 HarmonyOS / OpenHarmony 应用界面的声明式UI开发框架&#xff0c;它使用极简的UI信息语法、丰富的UI组件以及实时界面语言工具&#xff0c;帮助开发者提升应用界面开发效率 30%&#xff0c;开发…

8年经验分享:想要成为一名合格的软件测试工程师,你得会些啥?

对于很多新入行或者打算入行&#xff0c;成为软件测试工程师的小伙伴来说&#xff0c;刚开始接触这行&#xff0c;不知道自己究竟该学些什么&#xff0c;或者不知道必须掌握哪些知识&#xff0c;才能成为一名合格的测试工程师。 根据笔者观点&#xff0c;如果你能在学习过程中&…

申请ZeroSSL泛域名域名证书 并部署阿里云测试

安装acme.sh 安装过程中可能会失败 多试几次就会成功 wget -O - https://raw.githubusercontent.com/acmesh-official/acme.sh/master/acme.sh | sh -s -- --install-online -m 你的邮箱gmail.com安装完成后重新加载 Bash&#xff1a; source ~/.bashrc然后也可以开启自动更…

UCB Data100:数据科学的原理和技巧:第十三章到第十五章

十三、梯度下降 原文&#xff1a;Gradient Descent 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 学习成果 优化复杂模型 识别直接微积分或几何论证无法帮助解决损失函数的情况 应用梯度下降进行数值优化 到目前为止&#xff0c;我们已经非常熟悉选择模型和相应损…

生产数据不备份,用时两行泪

背景&#xff1a;项目使用pg一主一从&#xff0c;因慢sql导致查询慢&#xff0c;所以想从原本的4核加到16核&#xff0c;联系好运维后&#xff0c;打算先从从库开始操作&#xff0c;机器上的pgsql都正常关闭&#xff0c;然后停止&#xff0c;关机&#xff0c;扩容一切都很顺利&…

Maya参考图的导入和层的应用

参考视频&#xff1a;08.参考图的导入和层的应用_哔哩哔哩_bilibili 前视图/右视图模式下导入图形 创建图层 锁定后可以避免图片位置的移动 前视图和右视图要根据参照物对齐 与模型保持一定距离&#xff0c;同时把该参照图添加到图层中 模型可以添加到图层2中

PLC控制脉冲轴绝对位置往复运动(三菱FX系列简单状态机编程)

有关状态机的具体介绍,专栏有很多文章,大家可以通过下面的链接查看: https://rxxw-control.blog.csdn.net/article/details/125488089https://rxxw-control.blog.csdn.net/article/details/125488089三菱FX系列回原功能块介绍 https://rxxw-control.blog.csdn.net/article…

Google推出Telecom Jetpack库,让Android通话应用创建更简单

Google推出Telecom Jetpack库&#xff0c;让Android通话应用创建更简单 Telecom Jetpack库的最新Alpha版本已经推出。该库提供了多个API&#xff0c;以简化Android开发者创建语音和/或视频通话应用程序的过程&#xff0c;支持常见功能&#xff0c;例如接听/拒绝、音频路由等等…

Python+Selenium做自动化测试(超详细整理)

一、项目介绍 目的 测试某官方网站登录功能模块可以正常使用【文末有配套视频教程和免费的资料文档领取】 用例 1.输入格式正确的用户名和正确的密码&#xff0c;验证是否登录成功&#xff1b; 2.输入格式正确的用户名和不正确的密码&#xff0c;验证是否登录失败&#xff…

蓝牙音视频远程控制协议(AVRCP) AV/C command格式介绍

零.声明 本专栏文章我们会以连载的方式持续更新&#xff0c;本专栏计划更新内容如下&#xff1a; 第一篇:蓝牙综合介绍 &#xff0c;主要介绍蓝牙的一些概念&#xff0c;产生背景&#xff0c;发展轨迹&#xff0c;市面蓝牙介绍&#xff0c;以及蓝牙开发板介绍。 第二篇:Trans…

C++ 开发 + VSCode 调试

C 开发 VSCode 调试 MSYS2 安装 gcc、make下载安装MSMYS2pacman 添加镜像源 GCC1. 安装2. 查看结果3. 环境变量 GDB VSCode 调试所需插件创建项目调试代码1. tasks.json 配置任务2. launch.json 配置调试3. 运行 更进一步的 C/C 设置 参考资料 MSYS2 安装 gcc、make 下载 官…

【数据分析】数据分析方法 | A/B测试与多变量分析

【数据分析】数据分析方法 | A/B测试与多变量分析 上一次与大家讨论了数据分析方法中的市场细分与同期群分析&#xff0c;此次仍然是对数据分析方法的讨论&#xff0c;讨论A/B测试与多变量分析的应用。 如果撇开统计性数据分析不谈&#xff0c;数据分析的最终目的是为了对具体…