CUDA编程笔记(6)

news2025/1/12 11:58:16

文章目录

  • 前言
  • 全局内存的访问模式
    • 合并访问和非合并访问
  • 使用全局内存进行矩阵转置
    • 矩阵复制
    • 矩阵转置
  • 总结


前言

全局内存的合理使用

全局内存的访问模式

合并访问和非合并访问

    合并访问指的是一个线程束(同一个线程块中相邻的wrapSize个线程。现在GPU的内建变量wrapSize都是32)对全局的一次性访问请求(读或写)导致最少数据量的传输。
    定量的说,可以定义一个合并度,它等于线程束请求的字节数除以由该请求导致的所有数据传输处理的字节数。若所有数据传输中处理的数据都是线程束所需要的,那么合并度就是100%,即对应合并访问,否则为非合并访问。
    需要注意的是为了保证一次数据传输中内存片段的首地址是最小粒度()的整数倍,cuda运行cudaMalloc函数时分配的内存首地址至少是256字节的整数倍。
通过例子来看几种常见的内存访问模式及其和合并度。
(1)顺序合并

__global__ void add(float *x,float *y,float *z)
{
	int n = threadIdx.x + blockIdx.x * blockDim.x;
	z[n] = x[n] + y[n];
}
add<<<128,32>>>(x,y,z);

从上面的代码可知,核函数线程块大小为blockDim.x=32,int类型,对应128个字节,线程块中的每个线程束可以访问这么多的连续内存。首地址一定是256的整数倍,这样根据前面的概念,在合并度100%的情况下,一个线程束将请求32*4=128个字节的数据。访问只需要128/32=4次数据传输即可完成。

(2)不对齐的非合并访问

__global__ void add_offset(float *x,float *y,float *z)
{
	int n = threadIdx.x + blockIdx.x * blockDim.x + 1;
	z[n] = x[n] + y[n];
}
add_offset<<<128,32>>>(x,y,z);

    第一个线程块中的线程数将访问数组x中的第1-32个元素。假设数组x的首地址是256字节,该线程数将访问设备内存的260-387字节。将触发5次数据传输,对应的内存地址分别是256-287,288-319,320-351,352-383和384-415字节。这样的访问属于不对齐的非合并访问,合并度为( 32 ∗ 4 32*4 324)/( 32 ∗ 5 32*5 325)=4/5=0.8,即80%。

(3)跨越式的非合并访问

__global__ void add_stride(float *x,float *y,float *z)
{
	int n = blockIdx.x + threadIdx.x * gridDim.x ;
	z[n] = x[n] + y[n];
}
add_offset<<<128,32>>>(x,y,z);

    上面的代码第一个线程块中的线程束将访问数组x中指标为0,128,256,384等元素,不在一个连续的32字节的内存片段,所以将触发32次数据传输,假设首地址为256,256-287,384-415等32个不连续字节段。合并度为( 32 ∗ 4 32*4 324)/( 32 ∗ 32 32*32 3232)=4/32=0.125,即12.5%。这样的访问属于跨越式的非合并访问。

使用全局内存进行矩阵转置

矩阵复制

首先考虑矩阵复制问题,如将B = A

// const real *A, real *B是全局内存,const int N是常量内存
__global__ void copy(const real *A, real *B, const int N)
{
	// 二维,TILE_DIM宏定义为32,可以在核函数里直接调用宏定义和const的整型和浮点型变量
    const int nx = blockIdx.x * TILE_DIM + threadIdx.x;  // 寄存器内存
    const int ny = blockIdx.y * TILE_DIM + threadIdx.y;
    // 将多维索引转换成一维的索引
    const int index = ny * N + nx;  // 寄存器内存
    if (nx < N && ny < N)
    {
        B[index] = A[index];
    }
}
// 定义网格和线程块大小
const int grid_size_x = (N+TILE_DIM-1)/TILE_DIM;
const int grid_size_y = grid_stride_y;
// 定义多维网格和线程块,第三个维度默认为1
const dim3 block_size(TILE_DIM,TILE_DIM);
const dim3 gride_size(grid_size_x,grid_size_y);
copy<<<gride_size,block_size>>>(d_A,d_B,N);

矩阵转置

在上面的复制操作中,定义的索引变量和读写操作代码为:

    const int index = ny * N + nx;
    if (nx < N && ny < N) B[index] = A[index];

两条语句写成一条:

    if (nx < N && ny < N) B[ny * N + nx] = A[ny * N + nx];

数学角度看,相当于做了 B i j B_{ij} Bij = A i j A_{ij} Aij。所以要转置的话,就是 B i j B_{ij} Bij = A j i A_{ji} Aji的操作。
代码替换成:

    if (nx < N && ny < N) B[nx * N + nx] = A[ny * N + nx];
    // or
    if (nx < N && ny < N) B[ny * N + nx] = A[nx * N + ny];

    在上面的第一条语句中,矩阵A读取是顺序的,矩阵B中写入不是顺序的。根据全局内存的访问模式的划分规则,可以说核函数对矩阵A的读取是非合并的,对矩阵B的写入是合并的。第二条语句正好反过来,矩阵A读取不是顺序的,矩阵B中写入是顺序的,核函数对矩阵A的读取是合并的,对矩阵B的写入是非合并的。

那么这两个语句都能正确进行矩阵转置的代码用起来性能会有什么差别呢?

    从帕斯卡架构的GPU开始,编译器如果能判断一个全局内存变量在整个核函数的范围都是只读的,会自动用上篇讲的__ldg()只读数据缓存加载函数读取,它能缓解非合并访问带来的影响。而对于全局内存的写入,则没有类似的函数。所以,对只读的可以是合并和非合并的读取,但是可以写入数据的最好是合并访问。

在2080Ti上,给定N=10000,通过代码例子来看看性能的影响:
代码:https://github.com/brucefan1983/CUDA-Programming/blob/master/src/07-global-memory/matrix.cu
在这里插入图片描述

总结

cuda全局内存通过选择访问模式的合理使用,对性能有较大的提升。
参考:
如博客内容有侵权行为,可及时联系删除!
CUDA 编程:基础与实践
https://docs.nvidia.com/cuda/
https://docs.nvidia.com/cuda/cuda-runtime-api
https://github.com/brucefan1983/CUDA-Programming

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

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

相关文章

Linux系统之网络客户端工具

Linux系统之网络客户端工具一、Links工具1.Links工具介绍2.安装Links软件3.Links工具的使用4.打印网页源码输出5.打印url版本到标准格式输出二、wget工具1.wget工具介绍2.安装wget软件3.wget工具的使用三、curl工具1.curl工具的介绍2.curl的常用参数3.curl的基本使用四、scp工具…

机器学习(二)--NumPy

本篇文章介绍了一些Numpy的基础操作。NumPy 是Python语言的一个扩充程序库。支持高级大量的维度数组与矩阵运算&#xff0c;此外也针对数组运算提供大量的数学函数库。&#x1f4d9;参考&#xff1a;NumPy 数据类型 | 菜鸟教程 (runoob.com)1.Numpy ndarray对象Numpy最重要的一…

Introduction to Multi-Armed Bandits——04 Thompson Sampling[2]

Introduction to Multi-Armed Bandits——04 Thompson Sampling[2] 参考资料 Russo D J, Van Roy B, Kazerouni A, et al. A tutorial on thompson sampling[J]. Foundations and Trends in Machine Learning, 2018, 11(1): 1-96. ts_tutorial 项目代码地址: https://githu…

蓝桥杯刷题014——求阶乘(二分法)

求阶乘 蓝桥杯2022省赛题目 问题描述 满足 N ! 的末尾恰好有 K 个 0 的最小的 N 是多少? 如果这样的 N 不存在输出 −1 。 输入格式 一个整数 K 。 输出格式 一个整数代表答案。 样例输入 2样例输出 10评测用例规模与约定 对于 30% 的数据, 1≤K≤10^6. 对于 100% 的数据, …

新瑞鹏冲刺上市:持续亏损,旗下宠物医院屡被罚,彭永鹤为董事长

家门口的宠物医院所属集团也要上市了。 1月24日&#xff0c;新瑞鹏宠物医疗集团有限公司&#xff08;New Ruipeng Pet Group Inc.&#xff0c;下称“新瑞鹏”或“新瑞鹏集团”&#xff09;在美国证监会&#xff08;SEC&#xff09;公开提交招股书&#xff0c;准备在美国纳斯达…

LabVIEW什么时候需要实时系统

LabVIEW什么时候需要实时系统实时计算系统能够非常可靠地执行具有非常具体时序要求的程序&#xff0c;这对于许多科学和工程项目来说都很重要。构建实时系统所需的关键组件是实时操作系统&#xff08;RTOS&#xff09;。精确计时对于许多工程师和科学家来说&#xff0c;在安装了…

C 语言零基础入门教程(十)

C 作用域规则 任何一种编程中&#xff0c;作用域是程序中定义的变量所存在的区域&#xff0c;超过该区域变量就不能被访问。C 语言中有三个地方可以声明变量&#xff1a; 1、函数或块内部的局部变量 2、在所有函数外部的全局变量 3、在形式参数的函数参数定义中 让我们来看看什…

返回值的理解

前言 我们写的函数是怎么返回的&#xff0c;该如何返回一个临时变量&#xff0c;临时变量不是出栈就销毁了吗&#xff0c;为什么可以传递给调用方&#xff1f;返回对象的大小对使用的方式有影响吗&#xff1f;本文将带你探究这些问题&#xff0c;阅读本文需要对函数栈帧有一定…

Win10+GTX3060+Python+PyTorch+Tensorflow安装

本文是个备忘录&#xff0c;是折腾半个下午的成果&#xff0c;记下来免得忘记了。 0. 安装Win10&#xff0c;安装显卡驱动程序。 1. 弄清楚目前版本的PyTorch和Tensorflow支持哪个版本的Python。截至本文编写时&#xff0c;PyTorch需要Python的3.7~3.9&#xff0c;Tensorflow…

【NI Multisim 14.0虚拟仪器设计——放置虚拟仪器仪表(字发生器)】

目录 序言 &#x1f34d;放置虚拟仪器仪表 &#x1f349;字发生器 &#xff08;1&#xff09;“控件”选项组 &#xff08;2&#xff09;“显示”选项组 &#xff08;3&#xff09;“触发”选项组 &#xff08;4&#xff09;“频率”选项组 &#xff08;5&#xff09;字符…

CSS 艺术之暗系魔幻卡牌

CSS 艺术之暗系魔幻卡牌参考描述效果支线HTML图片主线去除元素的部分默认属性定义 CSS 变量body#card自定义属性定义动画#card::before#card::afterimg代码总汇参考 项目描述MDNWeb 文档搜索引擎Bing 描述 项目描述Edge109.0.1518.61 (正式版本) (64 位) 效果 注&#xff1a;…

DaVinci:HDR 调色

调色页面&#xff1a;HDR 调色Color&#xff1a;HDR GradeHDR 调色 HDR Grade调板不仅可用于 HDR 视频的调色&#xff0c; 也可用于 SDR 视频。其调色功能与标准色轮类似&#xff0c;但能调整的区域却要细致很多&#xff0c;同时&#xff0c;它还是可感知色彩空间的工具。高动态…

41.Isaac教程--使用DOPE进行3D物体姿态估计

使用DOPE进行3D物体姿态估计 ISAAC教程合集地址: https://blog.csdn.net/kunhe0512/category_12163211.html 深度对象姿态估计 (DOPE:Deep Object Pose Estimation) 从单个 RGB 图像执行已知对象的检测和 3D 姿态估计。 它使用深度学习方法来预测对象 3D 边界框的角点和质心的…

【数据结构】单调栈、单调队列

单调栈 单调栈 单调 栈 模拟单调递增栈的操作&#xff1a; 如果栈为 空 或者栈顶元素 大于 入栈元素&#xff0c;则入栈&#xff1b;否则&#xff0c;入栈则会破坏栈内元素的单调性&#xff0c;则需要将不满足条 件的栈顶元素全部弹出后&#xff0c;将入栈元素入栈。 单调…

研究分析如何设计高并发下的弹幕系统

一、需求背景为了更好的支持直播业务&#xff0c;产品设计为直播业务增加弹幕功能,但是最初的弹幕设计使用效果并不理想&#xff0c;经常出现卡顿、弹幕偏少等需要解决的问题。二、问题分析按照背景来分析&#xff0c;系统主要面临以下问题&#xff1a;带宽压力&#xff1b;弱网…

[基础]qml基础控件

TextText元素可以显示纯文本或者富文本(使用HTML标记修饰的文本)。它有font,text,color,elide,textFormat,wrapMode,horizontalAlignment,verticalAlignment等属性。主要看下clip&#xff0c;elide&#xff0c;textFormat&#xff0c;warpMode属性clipText 项目是可以设置宽度的…

Apache Spark 机器学习 特征抽取 4-2

Word2Vec 单词向量化是一个估算器&#xff0c;将文档转换成一个按照固定顺序排列的单词序列&#xff0c;然后&#xff0c;训练成一个Word2VecModel单词向量化的模型&#xff0c;该模型将每个单词映射成一个唯一性的、固定大小的向量集&#xff0c;对每个文档的所有单词进行平均…

【数据结构和算法】实现线性表中的静态、动态顺序表

本文是数据结构的开篇&#xff0c;上文学习了关于使用C语言实现静态、动态、文件操作的通讯录&#xff0c;其中使用到了结构体这一类型&#xff0c;实际上&#xff0c;是可以属于数据结构的内容&#xff0c;接下来我们来了解一下顺序表的相关内容。 目录 前言 一、线性表 一…

流批一体计算引擎-6-[Flink]的Python DataStream API程序

参考官方Python API文档 1 IDEA中运行Flink 从Flink 1.11版本开始, PyFlink 作业支持在 Windows 系统上运行&#xff0c;因此您也可以在 Windows 上开发和调试 PyFlink 作业了。 1.1 环境配置 pip3 install apache-flink1.15.3 CMD>set PATH查看环境变量 CMD>set JAV…

对JDBC驱动注册--DriverManager.registerDriver和Class.forName(driverClass)的理解

对JDBC驱动注册–DriverManager.registerDriver和Class.forName(driverClass)的理解 JDBC提供了独立于数据库的统一API&#xff0c;MySQL、Oracle等数据库公司都可以基于这个标准接口来进行开发。包括java.sql包下的Driver&#xff0c;Connection&#xff0c;Statement&#x…