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

相关文章

从入门到精通MySQL联合查询

《从入门到精通MySQL联合查询》:本文主要介绍从入门到精通MySQL联合查询,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下... 目录摘要1. 多表联合查询时mysql内部原理2. 内连接3. 外连接4. 自连接5. 子查询6. 合并查询7. 插入查询结果摘要前面我们学习了数据库设计时要满

怎样通过分析GC日志来定位Java进程的内存问题

《怎样通过分析GC日志来定位Java进程的内存问题》:本文主要介绍怎样通过分析GC日志来定位Java进程的内存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、GC 日志基础配置1. 启用详细 GC 日志2. 不同收集器的日志格式二、关键指标与分析维度1.

Java内存分配与JVM参数详解(推荐)

《Java内存分配与JVM参数详解(推荐)》本文详解JVM内存结构与参数调整,涵盖堆分代、元空间、GC选择及优化策略,帮助开发者提升性能、避免内存泄漏,本文给大家介绍Java内存分配与JVM参数详解,... 目录引言JVM内存结构JVM参数概述堆内存分配年轻代与老年代调整堆内存大小调整年轻代与老年代比例元空

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

MySQL中的索引结构和分类实战案例详解

《MySQL中的索引结构和分类实战案例详解》本文详解MySQL索引结构与分类,涵盖B树、B+树、哈希及全文索引,分析其原理与优劣势,并结合实战案例探讨创建、管理及优化技巧,助力提升查询性能,感兴趣的朋... 目录一、索引概述1.1 索引的定义与作用1.2 索引的基本原理二、索引结构详解2.1 B树索引2.2

从入门到精通MySQL 数据库索引(实战案例)

《从入门到精通MySQL数据库索引(实战案例)》索引是数据库的目录,提升查询速度,主要类型包括BTree、Hash、全文、空间索引,需根据场景选择,建议用于高频查询、关联字段、排序等,避免重复率高或... 目录一、索引是什么?能干嘛?核心作用:二、索引的 4 种主要类型(附通俗例子)1. BTree 索引(

如何使用Maven创建web目录结构

《如何使用Maven创建web目录结构》:本文主要介绍如何使用Maven创建web目录结构的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录创建web工程第一步第二步第三步第四步第五步第六步第七步总结创建web工程第一步js通过Maven骨架创pytho

Python循环结构全面解析

《Python循环结构全面解析》循环中的代码会执行特定的次数,或者是执行到特定条件成立时结束循环,或者是针对某一集合中的所有项目都执行一次,这篇文章给大家介绍Python循环结构解析,感兴趣的朋友跟随... 目录for-in循环while循环循环控制语句break语句continue语句else子句嵌套的循

Redis 配置文件使用建议redis.conf 从入门到实战

《Redis配置文件使用建议redis.conf从入门到实战》Redis配置方式包括配置文件、命令行参数、运行时CONFIG命令,支持动态修改参数及持久化,常用项涉及端口、绑定、内存策略等,版本8... 目录一、Redis.conf 是什么?二、命令行方式传参(适用于测试)三、运行时动态修改配置(不重启服务