CUDA编程:执行模型

news2024/11/17 5:44:14

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.coloradmin.cn/o/1372096.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器学习中的隐马尔可夫模型及Python实现示例

隐马尔可夫模型&#xff08;HMM&#xff09;是一种统计模型&#xff0c;用于描述观测序列和隐藏状态序列之间的概率关系。它通常用于生成观测值的底层系统或过程未知或隐藏的情况&#xff0c;因此它被称为“隐马尔可夫模型”。 它用于根据生成数据的潜在隐藏过程来预测未来的观…

跟我学java|Stream流式编程——并行流

什么是并行流 并行流是 Java 8 Stream API 中的一个特性。它可以将一个流的操作在多个线程上并行执行&#xff0c;以提高处理大量数据时的性能。 在传统的顺序流中&#xff0c;所有的操作都是在单个线程上按照顺序执行的。而并行流则会将流的元素分成多个小块&#xff0c;并在多…

【Java集合篇】 ConcurrentHashMap在哪些地方做了并发控制

ConcurrentHashMap在哪些地方做了并发控制 ✅典型解析✅初始化桶阶段&#x1f7e2;桶满了会自动扩容吗&#x1f7e0;自动扩容的时间频率是多少 ✅put元素阶段✅扩容阶段&#x1f7e0; 拓展知识仓&#x1f7e2;ConcurrentSkipListMap和ConcurrentHashMap有什么区别☑️简单介绍一…

2024年第九届计算机与通信系统国际会议(ICCCS2024) ,邀您相约西安!

会议官网: ICCCS2024 | Xian China 时间: 2024年4月19-22日 地点: 中国西安 会议简介&#xff1a; 近年来&#xff0c;信息通信在不断发展&#xff0c;为计算机网络的进步与发展提供了先进可靠的技术支持。随着计算机网络与通信技术的深入发展&#xff0c;计算机通信技术、数…

报错解决:RuntimeError: Error building extension ‘bias_act_plugin‘

系统&#xff1a; Ubuntu22.04&#xff0c; nvcc -V&#xff1a;11.8 &#xff0c; torch&#xff1a;2.0.0cu118 一&#xff1a;BUG内容 运行stylegan项目的train.py时遇到报错&#x1f447; Setting up PyTorch plugin "bias_act_plugin"... Failed! /home/m…

docker+jmeter实现windows作为主控机,linux作为负载机的分布式压测环境搭建

dockerjmeter实现windows作为主控机&#xff0c;linux作为负载机的分布式压测环境搭建 1、搭建环境说明2、windows主控机安装Jmeter3、linux负载机安装Jmeter3.1、安装docker环境3.2、使用docker安装jmeter 4、windows主控机分发测试任务 1、搭建环境说明 准备一台windows主机…

京东(天猫淘宝)数据分析工具-鲸参谋系统全功能解析——行业大盘、红蓝海市场、品牌分析、店铺分析、商品分析、竞品监控(区分自营和POP)

作为第三方电商数据平台&#xff0c;鲸参谋电商大数据系统能够为品牌方和商家提供包括行业趋势、热门品牌、店铺分析、单品分析在内的多个层面数据分析&#xff0c;帮助商家做出更加准确的经营决策&#xff0c;提升经营效率&#xff0c;实现精准营销。 下面&#xff0c;我们针…

YOLOv8优化策略:轻量化改进 | 超越RepVGG!浙大阿里提出OREPA:在线卷积重参数化

🚀🚀🚀本文改进:在线卷积重参数化巧妙的和YOLOV8结合,并实现轻量化 🚀🚀🚀YOLOv8改进专栏:http://t.csdnimg.cn/hGhVK 学姐带你学习YOLOv8,从入门到创新,轻轻松松搞定科研; 1.OREPA介绍 论文:https://arxiv.org/pdf/2204.00826.pdf 摘要:结构重新参数化在…

软件测试|Python Selenium 库安装使用指南

简介 Selenium 是一个用于自动化浏览器操作的强大工具&#xff0c;它可以模拟用户在浏览器中的行为&#xff0c;例如点击、填写表单、导航等。在本指南中&#xff0c;我们将详细介绍如何安装和使用 Python 的 Selenium 库。 安装 Selenium 库 使用以下命令可以通过 pip 安装…

内网渗透之CobaltStrike(CS)

目录 一、Cobalt Strike简介 二、Cobalt Strike基本用法 1、启动服务端 2、客户端连接 3、设置监听器&#xff08;Listeners&#xff09; 4、脚本管理器&#xff08;Script Manager&#xff09; 5、攻击&#xff08;最常用的是生成后门&#xff09; 6、CS上线 7、Beaco…

图神经网络 7大高效创新思路分享,附17篇最新顶会论文和代码

2024年了&#xff0c;图神经网络方向还好发论文吗&#xff1f;答案当然是能。 图神经网络在处理非欧空间数据和复杂特征方面具有明显的优势&#xff0c;且已成为了深度学习领域的热点&#xff0c;在学术界和工业界都有着广泛的研究和应用。不仅如此&#xff0c;图神经网络与CV…

如何在集简云中调用GPTs(Assistant) API

我们在OpenAI中创建了GPTs(Assistant)后&#xff0c;希望放到其它软件中使用&#xff0c;比如 抖音私信&#xff0c;抖音评论&#xff0c;微信公众号&#xff0c;钉钉&#xff0c;飞书&#xff0c;企业微信...... 要如何实现这样的功能呢&#xff1f; 您可以使用集简云的 “数…

科研上新 | 第3期:大模型推进科研边界;大模型的道德价值对齐;优化动态稀疏深度学习模型;十亿规模向量搜索的高效更新

者按&#xff1a;欢迎阅读“科研上新”栏目&#xff01;“科研上新”汇聚了微软亚洲研究院最新的创新成果与科研动态。在这里&#xff0c;你可以快速浏览研究院的亮点资讯&#xff0c;保持对前沿领域的敏锐嗅觉&#xff0c;同时也能找到先进实用的开源工具。 本期内容速览 01…

JavaScript日期和时间处理手册

&#x1f9d1;‍&#x1f393; 个人主页&#xff1a;《爱蹦跶的大A阿》 &#x1f525;当前正在更新专栏&#xff1a;《VUE》 、《JavaScript保姆级教程》、《krpano》 ​ ​ ✨ 前言 日期和时间在应用开发中是非常常用的功能。本文将全面介绍JavaScript中处理日期和时间的方…

vscode设置python脚本运行参数

1 添加配置文件 点击到你要配置的python文件&#xff0c;然后右上角点击 运行 &#xff0c;再点击 添加配置 再点击 “Pyhton文件” 选项&#xff08;其实就是在选择 当前的python文件 进行配置&#xff09; 接着就生成了配置文件 lanunch.json 2 参数配置 再上面代码的基础上…

1月10号代码随想录左叶子之和

404.左叶子之和 给定二叉树的根节点 root &#xff0c;返回所有左叶子之和。 示例 1&#xff1a; 输入: root [3,9,20,null,null,15,7] 输出: 24 解释: 在这个二叉树中&#xff0c;有两个左叶子&#xff0c;分别是 9 和 15&#xff0c;所以返回 24示例 2: 输入: root [1]…

206. 反转链表(Java)

题目描述&#xff1a; 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 输入&#xff1a; head [1,2,3,4,5] 输出&#xff1a; [5,4,3,2,1] 代码实现&#xff1a; 1.根据题意创建一个结点类&#xff1a; public class ListNode {int val…

【详细】双系统 Ubuntu 如何给根目录扩容

1.分配出一块未分配空间&#xff08;需要和Ubuntu系统存储分区位于同一个硬盘上&#xff09; 这一步我直接利用windows系统自带的“创建并格式化硬盘分区”功能进行的。 如图&#xff0c;在想要切割出来一部分空间的卷上右键&#xff0c;选择压缩卷选项&#xff0c;之后输入空…

使用Windbg动态调试目标进程的一般步骤详解

目录 1、概述 2、将Windbg附加到已经启动起来的目标进程上&#xff0c;或者用Windbg启动目标程序 2.1、将Windbg附加到已经启动起来的目标进程上 2.2、用Windbg启动目标程序 2.3、Windbg关联到目标进程上会中断下来&#xff0c;输入g命令将该中断跳过去 3、分析实例说明 …

leetcode:1716. 计算力扣银行的钱(python3解法)

难度&#xff1a;简单 Hercy 想要为购买第一辆车存钱。他 每天 都往力扣银行里存钱。 最开始&#xff0c;他在周一的时候存入 1 块钱。从周二到周日&#xff0c;他每天都比前一天多存入 1 块钱。在接下来每一个周一&#xff0c;他都会比 前一个周一 多存入 1 块钱。 给你 n &am…