*5.1 Global Memory Bandwidth

news2024/11/17 13:37:54

并行程序的执行速度可能因计算硬件的资源限制而有很大差异。虽然管理并行代码和硬件资源约束之间的交互对于在几乎所有并行编程模型中实现高性能很重要,但这是一种实用技能,最好通过为高性能设计的并行编程模型中的实践练习来学习。在本章中,**我们将讨论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.coloradmin.cn/o/1368366.html

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

相关文章

探索大模型时代下的文档识别与分析【GPT4-V带来的挑战与机遇】

中国图象图形学学会青年科学家会议是由中国图象图形学学会青年工作委员会发起的学术会议。本会议面向国际学术前沿与国家战略需求,致力于支持图象图形领域的优秀青年学者,为青年学者们提供学术交流与研讨的平台,促进学者之间的交流与合作。会…

FreeRTOS学习总结(二)FreeRTOS任务创建和删除API函数

实现动态创建任务流程 任务控制块结构体成员介绍 typedef struct tskTaskControlBlock {volatile StackType_t * pxTopOfStack; /* 任务栈栈顶,必须为TCB第一个成员 */ListItem_t xStateListItem; /* 任务状态列表项 */ Li…

Mobile Aloha 【软硬件原理+代码解析】

1. Mobile ALOHA Hardware2. Imitation Learning3. Co-training with Static ALOHA Data4. Task Setting5. Experiments5.1 ACT5.2 对比ACT、Diffusion Policy和VINN 6. Software Code Analyze Mobile ALOHA: 利用低成本全身远程操作系统学习复杂的双手移动操作技能 [译] 硬件代…

SAP BAPI_OUTB_DELIVERY_CONFIRM_DEC 交货单过账提示 VL602 为交货的发货已经计帐

原因 如果尝试从交货处理的初始屏幕过账交货的货物移动,并且已为交货执行此步骤,则系统会正确发出消息 VL602(“已针对交货过账发货”)和/或 VL636(“已过账此入库交货的收货”)。 之后,无法再…

前端入门教程:学完即可单独完成前端项目

目录 目录 1.HTML: 1.1概念 1.2结构 1.3常见的标签使用分类: 2.CSS: 2.1概念 2.2样式实践: 以下的举例都来自于博客: 2.3css选择器: 什么是css选择器: 举例如下: 2.4Demo 3.JavaScript&#…

什么台灯最好学生晚上用?学生晚上用的护眼台灯推荐

随着人们对健康生活的追求日益增加,越来越多的人开始关注眼睛健康问题。而台灯作为人们日常生活和工作中常用的照明设备之一,护眼台灯的出现成为了人们关注的焦点。那么,作为课业负担比较重的学生群体,有什么护眼台灯是适合他们晚…

echarts - xAxis.type设置time时该如何使用formatter的分级模板

echarts 文档中描述了x轴的多种类型 一、type: ‘value’ ‘value’ 数值轴,适用于连续数据。 此时x轴数据是从零开始,有数据大小的区分。 【注意】 因为xAxis.data是为category服务的,所以xAxis.data里面设置的数据无效。 二、type: ‘ca…

2023回顾

今年遇到最大的问题: 屏幕无故卡死,原因各种各样,至今虽说已排查了大部分的原因,也规避掉了一些可能问题,但随着新功能的添加,还是有可能不小心引入。 期间的解决方案也发布在Qt 屏幕偶发性失灵_qt 虚拟键盘…

Springboot+RocketMQ通过事务消息优雅的实现订单支付功能

目录 1. 事务消息 1.1 RocketMQ事务消息的原理 1.2 RocketMQ订单支付功能设计 1. 事务消息 RocketMQ的事务消息,是指发送消息事件和其他事件需要同时成功或同时失败。比如银行转账, A银行的某账户要转一万元到B银行的某账户。A银行发送“B银行账户增加…

如何让GPT支持中文

上一篇已经讲解了如何构建自己的私人GPT,这一篇主要讲如何让GPT支持中文。 privateGPT 本地部署目前只支持基于llama.cpp 的 gguf格式模型,GGUF 是 llama.cpp 团队于 2023 年 8 月 21 日推出的一种新格式。它是 GGML 的替代品,llama.cpp 不再…

记一次JSF异步调用引起的接口可用率降低

前言 本文记录了由于JSF异步调用超时引起的接口可用率降低问题的排查过程,主要介绍了排查思路和JSF异步调用的流程,希望可以帮助大家了解JSF的异步调用原理以及提供一些问题排查思路。本文分析的JSF源码是基于JSF 1,7.5-HOTFIX-T6版本。 起因 问题背景…

强化学习的数学原理学习笔记 - Actor-Critic

文章目录 概览:RL方法分类Actor-CriticBasic actor-critic / QAC🟦A2C (Advantage actor-critic)Off-policy AC🟡重要性采样(Importance Sampling)Off-policy PGOff-policy AC 🟦DPG (Deterministic AC) 本…

使用fs.renameSync(oldPath,newPath)方法,报错Error: ENOENT: no such file or directory

报错翻译:由于文件或目录不存在导致的。 解决方法:查看给定的路径,确保路径和文件名正确,并且文件或目录确实存在。

C语言--结构体详解

C语言--结构体详解 1.结构体产生原因2.结构体声明2.1 结构体的声明2.2 结构体的初始化2.3结构体自引用 3.结构体内存对齐3.1 对齐规则3.2 为什么存在内存对齐3.3 修改默认对⻬数 4. 结构体传参 1.结构体产生原因 C语言将数据类型分为了两种,一种是内置类型&#xf…

Spring学习 Spring事务控制

7.1.事务介绍 7.1.1.什么是事务? 当你需要一次执行多条SQL语句时,可以使用事务。通俗一点说,如果这几条SQL语句全部执行成功,则才对数据库进行一次更新,如果有一条SQL语句执行失败,则这几条SQL语句全部不…

2.SPSS数据文件的建立和管理

文章目录 数据文件的特点建立SPSS数据文件步骤 数据文件的结构变量的规则 数据的录入和保存录入数据保存文件 数据的编辑数据定位 数据文件的特点 SPSS数据库文件包括文件结构和数据两部分 SPSS数据文件中的一列数据称为一个变量。每个变量都应有一个名称,即&…

面试算法100:三角形中最小路径之和

题目 在一个由数字组成的三角形中,第1行有1个数字,第2行有2个数字,以此类推,第n行有n个数字。例如,下图是一个包含4行数字的三角形。如果每步只能前往下一行中相邻的数字,请计算从三角形顶部到底部的路径经…

centos7新建普通用户并设置分组和密码

sudo -i获取root权限 添加分组group1 groupadd group1 添加用户并设置分组为group1密码为password1 useradd user1 -g group1 -p password1 su user1 切换到 user1

第7章-第6节-Java中的Map集合

1、HashMap: 1)、 引入 如果业务需要我们去用姓名的拼音手写字母匹配完整姓名,那么如果用单列数据,我们可能需要两个集合才能存储,而且两个集合之间没有关联不好操作,这种时候双列数据就会起很大作用 2&…

Mysql : command not found

1.Mysql : command not found 安装成功的mysql,并且服务已经启动,查看进行是可以看到的,但是使用命令登录操作,却抛出错误:command not found。 2.解决方案 2.1 查看/usr/bin目录下是否有mysql服务连接 ls /usr/bin…