CUDA从入门到放弃(六):CUDA内存结构(Memory Hierarchy)

2024-03-27 23:52

本文主要是介绍CUDA从入门到放弃(六):CUDA内存结构(Memory Hierarchy),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

CUDA从入门到放弃(六):CUDA内存结构(Memory Hierarchy)

CUDA线程在执行过程中可以从多个内存空间访问数据。每个线程都有私有的局部内存。每个线程块具有共享内存,该内存对所有线程块内的线程可见,并且与线程块具有相同的生命周期。线程块集群中的线程块可以相互执行对共享内存的读取、写入和原子操作。所有线程都可以访问相同的全局内存。

此外,还有两个所有线程都可以访问的只读内存空间:常量内存空间和纹理内存空间。

对于同一应用程序来说,全局内存、常量内存和纹理内存空间在内核启动之间是持久的。
在这里插入图片描述

1 全局内存 Global Memory

全局内存位于设备内存中,通过32字节、64字节或128字节的内存事务进行访问。这些内存事务必须自然对齐:只有对齐到其大小(即,其首地址是其大小的倍数)的设备内存的32字节、64字节或128字节段才能通过内存事务进行读取或写入。

当warp执行访问全局内存的指令时,它会根据每个线程访问的字的大小以及内存地址在线程之间的分布,将warp内部线程的内存访问合并为一个或多个这些内存事务。一般来说,所需的交易越多,除了线程访问的字之外,传输的未使用字就越多,从而相应地降低了指令吞吐量。例如,如果为每个线程的4字节访问生成一个32字节的内存事务,则吞吐量将减少到原来的八分之一。

大小和对齐要求

全局内存指令支持读写大小为1、2、4、8或16字节的数据。只有当数据类型大小符合这些值,并且数据自然对齐(地址是大小的倍数)时,访问才会编译为单个全局内存指令。

若不满足此要求,访问将编译为多个具有交错访问模式的指令,导致指令无法完全合并。因此,建议使用满足这些要求的类型来处理全局内存中的数据。

内置向量类型会自动满足对齐要求。对于结构体,可以使用__align__(8)或__align__(16)来确保对齐。

struct __align__(8) {float x;float y;
};struct __align__(16) {float x;float y;float z;
};

全局内存中的变量地址或由相关API返回的地址至少对齐到256字节。读取非自然对齐的8或16字节数据会产生错误结果,因此需特别注意保持对齐。特别是在使用自定义的全局内存分配方案时,应确保每个数组的起始地址正确对齐。

2 局部内存 Local Memory

局部内存空间位于设备内存中,因此局部内存访问与全局内存访问具有相同的高延迟和低带宽,并且必须满足与设备内存访问中描述的相同内存合并要求。然而,局部内存的组织方式是,连续的32位字由连续的线程ID访问。因此,只要warp中的所有线程访问相同的相对地址(例如,数组变量中的相同索引,结构变量中的相同成员),访问就会完全合并。

局部内存访问仅发生在某些自动变量上。编译器可能将以下自动变量放置在局部内存中:

  • 它无法确定使用常量索引访问的数组,
  • 会消耗过多寄存器空间的大型结构或数组,
  • 如果内核使用的寄存器数量超过可用数量(这也称为寄存器溢出)时的任何变量。

3 共享内存 Shared Memory

由于共享内存位于芯片上,因此它相比本地内存或全局内存具有更高的带宽和更低的延迟。

为了实现高带宽,共享内存被分割成大小相等的内存模块,称为内存bank,这些bank可以同时访问。因此,任何由n个不同内存bank中的地址组成的内存读或写请求都可以同时得到服务,从而得到比单个模块带宽高出n倍的整体带宽。

然而,如果内存请求的两个地址落在同一个内存银行中,就会发生bank冲突,并且访问必须串行化。硬件会将带有bank冲突的内存请求拆分成尽可能多的单独的无冲突请求,吞吐量将降低一个等于单独内存请求数量的因子。如果单独的内存请求数量是n,那么初始内存请求就被认为是造成了n路bank冲突。

4 常量内存 Constant Memory

常量内存空间位于设备内存中,并缓存在常量缓存中。

然后,请求会根据初始请求中不同内存地址的数量拆分成多个单独的请求,吞吐量将降低一个等于单独请求数量的因子。

在缓存命中的情况下,生成的请求将以常量缓存的吞吐量进行处理;否则,将以设备内存的吞吐量进行处理。

5 纹理和表面内存 Texture and Surface Memory

纹理和表面内存空间位于设备内存中,并被缓存在纹理缓存中。因此,只有在缓存未命中的情况下,纹理获取或表面读取才会从设备内存中进行一次内存读取,否则仅从纹理缓存中进行一次读取。纹理缓存针对二维空间局部性进行了优化,因此,在二维空间中读取纹理或表面地址相近的同一warp中的线程将实现最佳性能。此外,它还设计用于具有恒定延迟的流式获取;缓存命中可以减少对DRAM带宽的需求,但不会减少获取延迟。

通过纹理或表面获取读取设备内存具有一些优势,这使得它成为从全局或常量内存读取设备内存的有利替代方案:

如果内存读取不遵循全局或常量内存读取必须遵循的访问模式以获得良好性能,那么只要纹理获取或表面读取中存在局部性,就可以实现更高的带宽;

寻址计算由专用单元在内核外部执行;

可以通过单个操作将打包的数据广播到单独的变量中;

8位和16位整数输入数据可以选择性地转换为范围在[0.0, 1.0]或[-1.0, 1.0]内的32位浮点数值。

参考资料
1 CUDA编程入门
2 CUDA编程入门极简教程
3 CUDA C++ Programming Guide
4 CUDA C++ Best Practices Guide
5 NVIDIA CUDA初级教程视频
6 CUDA专家手册 [GPU编程权威指南]
7 CUDA并行程序设计:GPU编程指南
8 CUDA C编程权威指南

这篇关于CUDA从入门到放弃(六):CUDA内存结构(Memory Hierarchy)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/853826

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

NameNode内存生产配置

Hadoop2.x 系列,配置 NameNode 内存 NameNode 内存默认 2000m ,如果服务器内存 4G , NameNode 内存可以配置 3g 。在 hadoop-env.sh 文件中配置如下。 HADOOP_NAMENODE_OPTS=-Xmx3072m Hadoop3.x 系列,配置 Nam

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

数论入门整理(updating)

一、gcd lcm 基础中的基础,一般用来处理计算第一步什么的,分数化简之类。 LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; } <pre name="code" class="cpp">LL lcm(LL a, LL b){LL c = gcd(a, b);return a / c * b;} 例题:

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多

【IPV6从入门到起飞】5-1 IPV6+Home Assistant(搭建基本环境)

【IPV6从入门到起飞】5-1 IPV6+Home Assistant #搭建基本环境 1 背景2 docker下载 hass3 创建容器4 浏览器访问 hass5 手机APP远程访问hass6 更多玩法 1 背景 既然电脑可以IPV6入站,手机流量可以访问IPV6网络的服务,为什么不在电脑搭建Home Assistant(hass),来控制你的设备呢?@智能家居 @万物互联

poj 2104 and hdu 2665 划分树模板入门题

题意: 给一个数组n(1e5)个数,给一个范围(fr, to, k),求这个范围中第k大的数。 解析: 划分树入门。 bing神的模板。 坑爹的地方是把-l 看成了-1........ 一直re。 代码: poj 2104: #include <iostream>#include <cstdio>#include <cstdlib>#include <al

MySQL-CRUD入门1

文章目录 认识配置文件client节点mysql节点mysqld节点 数据的添加(Create)添加一行数据添加多行数据两种添加数据的效率对比 数据的查询(Retrieve)全列查询指定列查询查询中带有表达式关于字面量关于as重命名 临时表引入distinct去重order by 排序关于NULL 认识配置文件 在我们的MySQL服务安装好了之后, 会有一个配置文件, 也就

自定义类型:结构体(续)

目录 一. 结构体的内存对齐 1.1 为什么存在内存对齐? 1.2 修改默认对齐数 二. 结构体传参 三. 结构体实现位段 一. 结构体的内存对齐 在前面的文章里我们已经讲过一部分的内存对齐的知识,并举出了两个例子,我们再举出两个例子继续说明: struct S3{double a;int b;char c;};int mian(){printf("%zd\n",s

音视频入门基础:WAV专题(10)——FFmpeg源码中计算WAV音频文件每个packet的pts、dts的实现

一、引言 从文章《音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道,通过FFprobe命令可以打印WAV音频文件每个packet(也称为数据包或多媒体包)的信息,这些信息包含该packet的pts、dts: 打印出来的“pts”实际是AVPacket结构体中的成员变量pts,是以AVStream->time_base为单位的显