*5.1 Global Memory Bandwidth

并行程序的执行速度可能因计算硬件的资源限制而有很大差异。虽然管理并行代码和硬件资源约束之间的交互对于在几乎所有并行编程模型中实现高性能很重要,但这是一种实用技能,最好通过为高性能设计的并行编程模型中的实践练习来学习。在本章中,**我们将讨论CUDA设备中的主要资源约束类型,**以及它们如何影响内核执行性能[Ryoo 2008JICUDA C最佳实践]。为了实现他/她的goals,程序员通常必须找到达到高于应用程序初始版本所需性能水平的方法。在不同的应用中,不同的约束可能会占主导地位,并成为限制因素,通常称为瓶颈。**人们通常可以通过将一个资源使用情况交易给另一个资源来显著提高应用程序在特定CUDA设备上的性能。**如果这样缓解的资源约束实际上是应用战略之前的主要约束,并且因此加剧的约束不会对并行执行产生负面影响,那么这种策略就很有效。如果没有这种理解,性能调整将是工作;似是而非的策略可能会也可能不会导致性能提升。除了对这些资源限制的洞察力外,**本章还提供了原则和案例研究,旨在培养对可能导致高性能执行的算法模式类型的直觉。**它还建立了成语和想法,这些成语和想法可能会在您的性能调整过程中带来良好的性能改进。

5.1 GLOBAL MEMORY BANDWIDTH

CUDA内核性能的最重要因素之一是访问全局内存中的数据。CUDA应用程序利用了海量数据并行性。当然,CUDA应用程序倾向于在短时间内处理来自全局内存的大量数据。在第4章“内存和数据局部性”中,我们研究了利用共享内存来减少每个线程块中的线程集合必须从全局内存访问的数据总量的 tile 技术。在本章中,我们将进一步讨论内存合并技术,这些技术可以更有效地将数据从全局内存移动到共享内存和寄存器中内存合并技术通常与分层技术结合使用,以允许CUDA设备通过更有效地利用全局内存带宽来发挥其性能潜力。

“最近的CUDA设备使用片上缓存来存储全局内存数据。此类缓存会自动合并更多内核访问模式,并在一定程度上减少了程序员手动重新排列其访问模式的需要。然而,即使有缓存,在可预见的未来,合并技术将继续对内核执行性能产生重大影响。

CUDA设备的全局存储器是用DRAM实现的。数据位存储在小电容器的DRAM单元中,其中存在或没有少量电荷可以区分0和1。从DRAM电池读取数据需要小电容器使用其微小的电荷驱动通往传感器的高电容线,并设置其检测机制,该机制确定电容器中是否存在足够的电荷,以符合“1”(请参阅“为什么DRAM如此缓慢?”侧边栏)。在现代DRAM芯片中,这个过程需要10纳秒。这与现代计算设备的亚纳秒时钟周期时间形成鲜明对比。由于相对于所需的数据访问速度(每字节的亚纳秒访问)来说,这是一个非常缓慢的过程,现代DRAM使用并行来提高其数据访问速率,通常称为内存访问吞吐量。

为什么DRAMS这么慢?
下图显示了DRAM单元格及其访问内容的路径。解码器是一个电子电路,它使用晶体管驱动连接到数千个电池出口门的线路。线路可能需要很长时间才能充满电或放电到所需的水平。
在这里插入图片描述
一个更艰巨的挑战是细胞将垂直线驱动到感应放大器,并允许感应放大器检测其内容。这是基于电荷共享。闸门释放出细胞中储存的少量电荷。如果电池含量为“1”,则微小的电荷必须将长位线大电容的电势提高到足够高的水平,从而触发感应放大器的检测机制。一个很好的比喻是,有人在长长的走廊的一端拿着一小杯咖啡,让另一个人闻到走廊上传播的香气,以确定咖啡的味道。
人们可以通过在每个单元中使用更大、更强的电容器来加快这个过程。然而,DRAM一直朝着相反的方向发展。每个电池中的电容器的尺寸都稳步缩小,因此随着时间的推移,其强度会降低,因此每个芯片中可以存储更多的位。这就是为什么DRAM的访问延迟没有随着时间的推移而减少。

每次访问DRAM位置时,都会实际访问一系列连续的位置,包括请求的位置。每个DRAM芯片中都提供了许多传感器,它们并行工作。每个人都在这些连续的位置中感知到一点的内容。一旦被传感器检测到,来自所有这些连续位置的数据可以以非常高的速度传输到处理器。访问和交付的这些连续位置被称为DRAM突发。如果应用程序集中使用这些突发的数据,DRAM可以以比访问真正的随机位置序列更高的速率提供数据。

认识到现代DRAM的突发组织,当前的CUDA设备采用一种技术,允许程序员通过将线程的内存访问组织成有利的模式来实现高全局内存访问效率。这种技术利用了warp中的线程在任何given时间点执行相同的指令这一事实。当warp中的所有线程执行负载指令时,硬件会检测它们是否访问连续的全局内存位置。也就是说,当warp中的所有线程访问连续的global内存位置时,可以实现最有利的访问模式。在这种情况下,硬件将所有这些访问合并或合并为对连续DRAM位置的合并访问。例如,对于warp的给定负载指令,如果线程0访问全局内存位置N,线程1位置N+1,线程2位置N+2等,所有这些访问都将被合并,或者在访问DRAM时合并为连续位置的单个请求。这种合并访问允许DRAM以突发方式交付数据。

不同的CUDA设备也可能对N施加对齐要求。例如,在一些CUDA设备中,N需要对齐到16字的边界。也就是说,N的下6位都应该是0位。由于存在二级缓存,最近的CUDA设备已经放宽了这种对齐要求。
请注意,现代CPU在其缓存内存设计中也能识别DRAM突发组织。CPU缓存行通常映射到一个或多个DRAM突发。在它们触摸的每条缓存行中充分利用字节的应用程序往往比随机访问内存位置的应用程序实现更高的性能。本章介绍的技术可以进行调整,以帮助CPU程序实现高性能。

在这里插入图片描述

为了了解如何有效使用合并硬件,我们需要回顾在访问C多维数组元素时如何形成内存地址。回顾第3章,可扩展并行执行(图3.3,复制为图5.1为方便起见)C和CUDA中的多维数组元素根据行主要约定放置在线性寻址内存空间中。术语行大调是指数据放置保留了行结构的事实:一行中的所有相邻元素都被放置在地址空间中的连续位置。在图中5.1,0行的四个元素首先按其在行中的外观顺序放置。然后放置第1行中的元素,然后是第2行的元素,然后是第3行的元素。应该清楚的是,M0.0和M1.0.虽然在二维矩阵中似乎是连续的,但在线性寻址内存中放置了四个位置。

图5.2说明了用于内存合并的有利与不利的CUDA内核2D行主要数组数据访问模式。从图4.7中召回。 在我们的简单矩阵乘法内核中,每个线程访问M数组的一行和N数组的一列。读者在继续之前应查看第4.3节。图5.2(A)说明了M数组的数据访问模式,其中warp中的线程读取相邻的行。也就是说,在迭代0期间,线程在0到第31行的warp读取元素0中。在迭代1期间,这些相同的线程读取0到31行的元素1。任何访问都不会合并。更有利的访问模式如图5.2(B)所示,其中每个线程读取N的一列。在迭代0期间,warp 0中的线程读取0到31列的元素1。所有这些通道都将合并。
在这里插入图片描述
为了理解为什么图5.2(B)中的模式比图5.2(A)中更有利,我们需要更详细地审查如何访问这些矩阵元素。图5.3显示了访问4×4矩阵的有利访问模式的一个小例子。图5.3顶部的箭头。显示内核代码的访问模式。这种访问模式是由图4.3中对N的访问生成的。

N[k*Width + Col]

在这里插入图片描述
在k循环的给定迭代中,所有线程的kWidth值都是相同的。召回Col=blockIdx.xblockDim.x+threadIdx.x。由于blockIndx.x和 blockDim.x 的值对同一块中的所有线程都具有相同的值,因此k*width+Col中唯一在线程块之间变化的部分是threadldx.x。由于相邻线程具有连续的threadldx.x值,因此其访问的元素将具有连续的地址。例如,在图5.3中,假设我们使用的是4x4块,并且warp大小为4。也就是说,对于这个玩具示例,我们只使用1个块来计算整个P矩阵。Width,blockDim.x,blockIdx.x为4、4, 和0的值, 对于块中的所有线程。在迭代0中,k值为0,每个线程用于访问 N 的索引
在这里插入图片描述
也就是说,在这个线程块中,访问N的索引只是threadldx.x的值。T0、T1、T2、T3访问的N元素是NLO]、N[1]、N[2]和N[3]。图5.3的“加载迭代0”框说明了这一点。.这些元素位于全局内存中的连续位置。硬件检测到这些访问是由warp中的线程和全局内存中的连续位置进行的。它将这些访问合并成一个合并的访问。这允许DRAM以高速率提供数据。

在下一次迭代中,k值为1。每个线程用于访问N的索引为:
在这里插入图片描述
T0、T1、T2、T3在此迭代中访问的N个元素是N[5]、N[6]、N[7]和N[8],如图5.3.中的“加载迭代1”框所示。所有这些访问再次合并成一个统一的访问,以提高DRAM带宽利用率。

图5.4显示了未合并的矩阵数据访问模式示例。图顶部的箭头显示,每个线程的内核代码按顺序访问行的元素。图5.4顶部的箭头显示了一个线程的内核代码的访问模式。此访问模式由图4.3中对M的访问生成。
在这里插入图片描述

M[Row*Width+k]

在k循环的给定迭代中,所有线程的kwidth值都是相同的。从图4.3中召回。该Row=blockIdx.yblockDim.y+threadIdx.y。由于 blockIndx.y 和 blockDim.y 的值对同一块中的所有线程具有相同的值,因此 RowWidth+k 中唯一可以在线程块之间变化的部分是threadldx.y。在图5.4中,我们再次假设我们正在使用4×4块,并且 warp 大小为4。块中所有线程的 Width, blockDim.y, blockIdx.y 的值为4、4和0。在迭代 0 中,k值为 0。每个线程用于访问M的索引为:
在这里插入图片描述
也就是说,访问M的索引只是threadldx.x
4的值。T0、T1、T2、T3访问的M元素是M[0]、M[4]、M[8]和M[12]。图5.4.中的“负载迭代0”框说明了这一点。这些元素不在全局内存中的连续位置。硬件不能将这些访问合并到合并访问中。

在下一次迭代中,k值为1。每个线程用于访问M的索引为:
在这里插入图片描述
T0、T1、T2、T3访问的M元素是M[1]、M[5]、M[9]和M[13],如图5.4.中的“加载迭代1”框所示。同样,这些访问不能合并为合并访问。

对于一个现实的矩阵,每个维度中通常有数百甚至数千个元素。相邻线程在每次迭代中访问的M元素可以相隔数百个甚至数千个元素。底部的“加载迭代0”框显示了线程如何访问 0 th迭代中的这些非连续位置。硬件将确定对这些元素的访问彼此相距甚远,不能合并。因此,当内核循环通过一行遍默时,对全局内存的访问效率比内核通过一列的情况要低得多。

如果算法本质上需要内核代码来沿行方向遍复数据,则可以使用共享内存实现内存聚合。这个技术,称为corner turning,如图5.5所示。用于矩阵乘法。每个线程从M读取一行,这是一个无法合并的模式。幸运的是,可以使用tile算法来实现合并。正如我们在第4章“内存和数据位置”中讨论的那样,块的线程可以首先合作地将tile加载到共享内存中。必须注意确保这些tile以凝聚模式加载。一旦数据在共享内存中,它们可以按行或列访问,性能变化要小得多,因为共享存储器本质上是作为高速片上内存实现的,不需要合并来实现高数据访问率。
在这里插入图片描述
我们复制图4.16 这里如图5.6,其中矩阵乘法内核加载矩阵M的两块,N到共享内存。回想一下,在每个阶段(第9-11行)开始时,线程块中的每个线程负责将一个M元素和一个N元素加载到Mds和Nds中。请注意,每个tile都涉及TILE_WIDTHZ线程。线程使用threadldx.y和threadldx.y来确定要加载的元素。
在这里插入图片描述
M元素加载在第9行,其中每个线程的索引计算使用ph来定位tile的左端。线性化索引计算等价于二维数组访问表达式M[Row][ph*TILE_SIZE+tx]。请注意,线程使用的列索引仅在threadIdx方面有所不同。行索引由blockldx.y和threadldx.y(第5行)确定,这意味着具有相同blockIdx.y/threadIdx.y和相邻threadldx.x值的同一线程块中的线程将访问相邻的M元素。也就是说,tile 的每一行由TILE_WIDTH线程加载,这些线程的线程ldx在y维度上相同,在x维度中是连续的。硬件将聚合这些负载。

在N的情况下,行索引 phTILE_SIZE+ty 对所有具有相同 threadldx.y 值的线程具有相同的值。问题是具有相邻 threadIdx.x 值的线程是否访问一行的相邻N个元素。注意每个线程的列索引计算, Col=bxTILE_SIZE+tx(见第6行)。第一项,bx*TILE_SIZE,对于同一块中的所有线程都是相同的。第二个项,tx,只是threadldx.x值。因此,具有相邻threadldx.x值的线程可以连续访问相邻的N个元素。硬件将凝聚这些负载

**在 tile 算法中,对 M 和 N 元素的负载都是合并的。**因此,与简单的矩阵乘法相比,tile 矩阵乘法算法有两个优势。**首先,由于共享内存中数据的重用,内存负载的数量减少了。其次,剩余的内存负载被合并,从而进一步提高DRAM带宽利用率。**这两个改进彼此具有倍增效应,并显著提高了内核的执行速度。在当前一代设备上,平铺内核的运行速度比简单内核快30多倍。

图5.6中的第5、6、9、10行。形成了一个常用的编程模式,用于在tile算法中将矩阵元素加载到共享内存中。我们还想鼓励读者通过第12行和第13行的点积循环来分析数据访问模式。请注意,warp中的线程不会访问Mds的连续位置。这不是问题,因为Mds在共享内存中,不需要合并即可实现高速数据访问。

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

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

相关文章

Springboot3(一、lambda、::的应用)

文章目录 一、使用lambda简化实例创建1.语法:2.示例:3.Function包3.1 有入参,有返回值【多功能函数】3.2 有入参,无返回值【消费者】3.3 无入参,有返回值【提供者】3.4 无入参,无返回值 二、类::方法的使用…

如何彻底卸载Edge

要彻底卸载Edge浏览器,你可以按照以下几种方法操作: 方法一:使用控制面板 点击任务栏的“开始”按钮,打开“控制面板”。在控制面板中,选择“程序和功能”。在程序列表中找到Edge浏览器,右键点击它并选择…

web左侧伸缩菜单栏/导航栏

效果展示&#xff1a; 百度网盘链接下载全部资源&#xff1a; http://链接&#xff1a;https://pan.baidu.com/s/1ZnKdWxTH49JhqZ7Xd-cJIA?pwd4332 提取码&#xff1a;4332 html/JQuery代码&#xff1a; <!DOCTYPE html> <html lang"zh"> <head&g…

网络通信(11)-C#TCP服务端封装帮助类实例

本文使用Socket在C#语言环境下完成TCP服务端封装帮助类的实例。 实例完成的功能: 服务器能够连接多个客户端显示在列表中,实现实时刷新。 服务器接收客户端的字符串数据。 选中列表中的客户端发送字符串数据。 在VS中创建C# Winform项目,编辑界面,如下: UI文件 name…

Java中SpringBoot组件集成接入【MQTT中间件】

Java中SpringBoot组件集成接入【MQTT中间件】 1.MQTT介绍2.搭建MQTT服务器1.Windows2.Ubuntu3.Docker4.其他方式3.mqtt可视化客户端MQTTX及快速使用教程4.SpringBoot接入MQTT1、maven依赖2、MQTT配置3、MQTT组件具体代码1.定义通道名字2.消息发布器3.MQTT配置、生产者、消费者4…

.NET学习教程一——.net基础定义+VS常用设置

一、定义 .NET分为.NET平台和.NET框架。 .NET平台&#xff08;厨房&#xff09;.NET FrameWork 框架&#xff08;柴米油盐酱醋茶&#xff09; .NET平台&#xff08;中国移动联通平台&#xff09;.NET FrameWork 框架&#xff08;信号塔&#xff09; .NET平台基于.NET Fra…

强化学习的数学原理学习笔记 - 值函数近似(Value Function Approximation)

文章目录 概览&#xff1a;RL方法分类值函数近似&#xff08;Value function approximation&#xff09;Basic idea目标函数&#xff08;objective function&#xff09;优化算法&#xff08;optimization algorithm&#xff09; Sarsa / Q-learning with function approximati…

学生备考哪款护眼台灯好?2024五款知名品牌强力推荐

最近应后台小伙伴要求&#xff0c;给大家测评一些护眼台灯产品&#xff0c;毕竟现在的孩子近视人数真的非常多&#xff0c;每五个孩子戴眼镜的就有三个了&#xff0c;日常学习中保护视力&#xff0c;由于很多学习时间都是在晚上&#xff0c;台灯成为了为陪伴学习不可或缺的搭档…

深度学习:图神经网络——在推荐系统中的应用

PinSage是工业界应用图神经网络完成推荐任务的第一个成功案例&#xff0c;其从用户数据中构造图&#xff08;graph&#xff09;的方法和应对大规模图而采取的实现技巧都值得我们学习。PinSage被应用在图片推荐类Pinterest上。在Pinterest中&#xff0c;每个用户可以创建并命名图…

TikTok电商年度洞察:出海到底“卖什么”?各国多类目爆款洞察,迅速掌握市场领先优势

很多卖家在尝试出海时&#xff0c;常面临两大核心痛点&#xff1a;一是“卖什么”&#xff0c;即选择何种商品进行销售&#xff1b;二是“怎么卖”&#xff0c;即如何通过有效的营销策略将商品销售出去。TikTok主打的内容电商模式&#xff0c;通过短视频和直播等形式&#xff0…

StampedLock锁探究

该锁提供了三种模式的读写控制&#xff0c;当调用获取锁的系列函数时&#xff0c;会返回一个long型的变量&#xff0c;我们称之为戳记(stamp),这个戳记代表了锁的状态。 其中try系列获取锁的函数&#xff0c;当获取锁失败后会返回为0的stamp 值。 当调用释放锁和转换锁的方法…

汽车中的ECU、VCU、MCU、HCU

一、ECU是汽车电脑&#xff0c;刷汽车电脑可以提高动力&#xff0c;也可以减低动力&#xff0c;看需求。 简单原理如下。 1.汽车发动机运转由汽车电脑&#xff08;即ECU&#xff09;控制。 2.ECU控制发动机的进气量&#xff0c;喷油量&#xff0c;点火时间等&#xff0c;从而…

成功解决使用git clone下载失败的问题: fatal: 过早的文件结束符(EOF) fatal: index-pack 失败

一.使用 http 可能出现的问题和解决 1.问题描述 ~$ git clone https://github.com/oKermorgant/ecn_baxter_vs.git 正克隆到 ecn_baxter_vs... remote: Enumerating objects: 13, done. remote: Counting objects: 100% (13/13), done. remote: Compressing objects: 100% (…

强直性脊柱炎=“不死的癌症”?这些常识你不可不知→

对强直性脊柱炎这个疾病&#xff0c;大家最常听说的是&#xff1a;强直性脊柱炎症状重、治疗难&#xff0c;会逐渐引发关节畸形、功能丧失&#xff0c;甚至残疾&#xff0c;被称为「不死的癌症」。 然而&#xff0c;近来越来越多患有强直性脊柱炎的明星活跃在荧幕上&#xff0c…

材料表征的微观探测器——台阶高度测量技术概述

一、引言 表面特征是材料、化学等领域的不可或缺的主要研究内容&#xff0c;合理地评价表面形貌、表面特征等&#xff0c;对于相关材料的评定、性能的分析和加工条件的改善都具有重要的意义。 表面台阶高度测量在材料表面研究中有十分重要的作用。一方面&#xff0c;表面测量…

x-cmd pkg | busybox - 嵌入式 Linux 的瑞士军刀

目录 简介首次用户功能特点竞品和相关作品 进一步阅读 简介 busybox 是一个开源的轻量级工具集合&#xff0c;集成了一批最常用 Unix 工具命令&#xff0c;只需要几 MB 大小就能覆盖绝大多数用户在 Linux 的使用&#xff0c;能在多款 POSIX 环境的操作系统&#xff08;如 Linu…

避免重复扣款:分布式支付系统的幂等性原理与实践

这是《百图解码支付系统设计与实现》专栏系列文章中的第&#xff08;6&#xff09;篇。 本文主要讲清楚什么是幂等性原理&#xff0c;在支付系统中的重要应用&#xff0c;业务幂等、全部幂等这些不同的幂等方案选型带来的收益和复杂度权衡&#xff0c;幂等击穿场景及可能的严重…

k8s源码阅读环境配置

源码阅读环境配置 k8s代码的阅读可以让我们更加深刻的理解k8s各组件的工作原理&#xff0c;同时提升我们Go编程能力。 IDE使用Goland&#xff0c;代码阅读环境需要进行如下配置&#xff1a; 从github上下载代码&#xff1a;https://github.com/kubernetes/kubernetes在GOPATH目…

CTF-PWN-沙箱逃脱-【seccomp和prtcl-2】

文章目录 沙箱逃脱prtcl题HITCON CTF 2017 Quals Impeccable Artifactflag文件对应prctl函数检查源码思路exp 沙箱逃脱prtcl题 HITCON CTF 2017 Quals Impeccable Artifact flag文件 此时的flag文件在本文件夹建一个即可 此时的我设置的flag为 对应prctl函数 第一条是禁止…

JavaScript解构赋值完全手册

&#x1f9d1;‍&#x1f393; 个人主页&#xff1a;《爱蹦跶的大A阿》 &#x1f525;当前正在更新专栏&#xff1a;《VUE》 、《JavaScript保姆级教程》、《krpano》 ​ 目录 ✨ 前言 第一节:解构赋值的基本用法 第二节:对象解构赋值 第三节:数组解构赋值 第四节:参数…