了解cuda的统一内存

1. CUDA 6中的统一内存

在CUDA 6中,从Kepler GPU架构(计算能力3.0或更高)开始,在64位Windows 7、8和Linux操作系统(内核2.6.18+)上开始支持统一内存.
在这里插入图片描述
从CUDA 6开始,NVIDIA推出了CUDA平台历史上最引人注目的编程模型改进之一 ---- 统一内存
在当今典型的PC或集群节点中,CPU和GPU的内存在物理上是不同的,并由PCI Express总线分隔。
在CUDA 6之前,程序员必须这样看待事物。CPU和GPU之间共享的数据必须在两个内存中分配,并由程序在它们之间明确复制。这给CUDA程序增加了很多复杂性。

在这里插入图片描述
统一内存创建了一个在CPU和GPU之间共享的托管内存池,弥合了CPU-GPU的鸿沟。
CPU和GPU都可以使用单个指针访问托管内存。关键在于,系统会自动在主机和设备之间迁移统一内存中分配的数据,使其看起来像CPU内存当在CPU上运行代码时,而在GPU上运行代码时像是GPU内存。

在这篇文章中,我将向您展示统一内存如何大大简化GPU加速应用程序中的内存管理。
下图显示了一个非常简单的例子。这两个代码都从磁盘加载文件,对其中的字节进行排序,然后在释放内存之前在CPU上使用排序后的数据。右侧的代码使用CUDA和统一内存在GPU上运行.
两个代码的唯一的区别是GPU版本启动内核函数(并在启动后进行同步),并使用新的API cudaMallocManaged()为加载的文件在统一内存中分配空间.

在这里插入图片描述
如果你以前用过CUDA C/C++编程,你无疑会被右边代码的简洁性所打动。请注意,我们只分配了一次内存,并且我们有一个指向主机和设备都可以访问的数据的指针。我们可以直接从文件读取内容到分配的内存,然后将指针直接传递给在设备上运行的CUDA内核。然后,在等待内核完成之后,我们可以再次从CPU访问数据。CUDA运行时隐藏了所有的复杂性,自动将数据迁移到访问它的地方。

2 统一内存提供了什么

程序员从统一内存中受益的主要方式有两种。

2.1 更简单的编程和内存模型

统一内存降低了CUDA平台上并行编程的门槛,通过使设备内存管理成为一种优化,而不是一种要求
有了统一内存,现在程序员可以直接开发并行CUDA内核,而不会陷入分配和复制设备内存的细节中。
这将使学习CUDA平台的编程和将现有代码移植到GPU更简单。但这不仅仅适用于初学者。
本文后面的示例展示了统一内存如何使复杂的数据结构更容易与设备代码一起使用,以及它与C++结合时的强大功能。

2.2 通过数据本地化提升性能

通过在CPU和GPU之间按需迁移数据,统一内存可以在GPU上提供本地数据的性能,同时提供全局共享数据的易用性。此功能的复杂性被隐藏在CUDA驱动程序和运行时的保护之下,确保应用程序代码更易于编写。迁移的目的是实现每个处理器的全带宽;250 GB/s的GDDR5内存对于提升开普勒GPU的计算吞吐量至关重要。

一个重要的点是,一个经过精心调优的CUDA程序,它使用流和cudaemcpyAsync来有效地将执行与数据传输重叠,可能会比只使用统一内存的CUDA软件表现得更好。容易理解的是:CUDA运行时永远不会像程序员那样了解需要数据的位置和时间!CUDA程序员仍然可以访问显式设备内存分配和异步内存副本,以优化数据管理和CPU-GPU并发性。统一内存首先是一种生产力功能,它为并行计算提供了更平滑的入口,而不会剥夺CUDA为高级用户提供的任何功能。

3 统一内存还是统一虚拟寻址?

CUDA自CUDA 4以来一直支持统一虚拟寻址(UVA),虽然统一内存依赖于UVA,但它们不是一回事。UVA为系统中的所有内存提供了一个单一的虚拟内存地址空间,并允许从GPU代码访问指针,无论它们位于系统的哪个位置,无论是设备内存(在相同或不同的GPU上)、主机内存还是片上共享内存。它还允许使用cudaMemcpy,而无需指定输入和输出参数的确切位置。UVA支持“零拷贝”内存,即设备代码可以直接通过PCI Express访问的固定主机内存,无需memcpy。Zero Copy提供了统一内存的一些便利,但没有提供任何性能,因为它总是使用PCI Express的低带宽和高延迟进行访问。

UVA不会像统一内存那样自动将数据从一个物理位置迁移到另一个。由于统一内存能够在主机和设备内存之间自动迁移单个页面级别的数据,因此需要大量的工程来构建,因为它需要CUDA运行时、设备驱动程序甚至操作系统内核中的新功能。以下示例旨在让您了解其功能。

3.1 例子:消除深拷贝

统一内存的一个关键好处是简化了异构计算内存模型,因为在访问GPU内核中的结构化数据时不需要深度副本。将包含指针的数据结构从CPU传递到GPU需要进行“深度复制”,如下图所示。
在这里插入图片描述
dataElem结构如下

struct dataElem {int prop1;int prop2;char *name;
}

要在设备上使用此结构,我们必须复制结构本身及其数据成员,然后复制结构指向的所有数据,然后更新结构副本中的所有指针。这导致了以下复杂的代码,只是为了将数据元素传递给内核函数。

void launch(dataElem *elem) {dataElem *d_elem;char *d_name;int namelen = strlen(elem->name) + 1;// Allocate storage for struct and namecudaMalloc(&d_elem, sizeof(dataElem));cudaMalloc(&d_name, namelen);// Copy up each piece separately, including new “name” pointer valuecudaMemcpy(d_elem, elem, sizeof(dataElem), cudaMemcpyHostToDevice);cudaMemcpy(d_name, elem->name, namelen, cudaMemcpyHostToDevice);cudaMemcpy(&(d_elem->name), &d_name, sizeof(char*), cudaMemcpyHostToDevice);// Finally we can launch our kernel, but CPU & GPU use different copies of “elem”Kernel<<< ... >>>(d_elem);
}

可以想象,在CPU和GPU代码之间共享复杂数据结构所需的额外主机端代码对生产率有重大影响。在统一内存中分配我们的dataElem结构消除了所有多余的设置代码,只剩下内核启动,它与宿主代码在同一指针上运行。这是一个很大的进步!

void launch(dataElem *elem) {kernel<<< ... >>>(elem);
}

但这不仅仅是代码复杂性的一大改进。统一内存还可以做以前无法想象的事情。让我们来看另一个例子:

3.2 例子: CPU/GPU之间共享链表

在这里插入图片描述
链表是一种非常常见的数据结构,但由于它们本质上是由指针组成的嵌套数据结构,在内存空间之间传递它们非常复杂。如果没有统一内存,CPU和GPU之间共享链表是无法管理的。唯一的选择是在零拷贝内存(固定主机内存)中分配列表,这意味着GPU访问仅限于PCI express性能。通过在统一内存中分配链表数据,设备代码可以在GPU上正常跟随指针,并具有设备内存的全部性能。该程序可以维护一个链表,可以在主机或设备上添加和删除列表元素.

将具有现有复杂数据结构的代码移植到GPU曾经是一项艰巨的任务,但统一内存使这变得更加容易。我预计统一内存将为CUDA程序员带来巨大的生产力提升。

4. c++中使用统一内存

统一内存在C++数据结构中大放异彩。C++通过使用带有复制构造函数的类简化了深度复制问题。复制构造函数是一个函数,它知道如何创建类的对象,为其成员分配空间,并从另一个对象复制它们的值。C++还允许重载new和delete内存管理运算符。这意味着我们可以创建一个基类,我们称之为Managed,它在重载的new运算符中使用cudaAllocManaged(),如下代码所示。

class Managed {
public:void *operator new(size_t len) {void *ptr;cudaMallocManaged(&ptr, len);cudaDeviceSynchronize();return ptr;}void operator delete(void *ptr) {cudaDeviceSynchronize();cudaFree(ptr);}
};

然后,我们可以让String类从Managed类继承,并实现一个复制构造函数,为复制的字符串分配统一内存。

// Deriving from “Managed” allows pass-by-reference
class String : public Managed {int length;char *data;public:// Unified memory copy constructor allows pass-by-valueString (const String &s) {length = s.length;cudaMallocManaged(&data, length);memcpy(data, s.data, length);}// ...
};

同样,我们使dataElem类继承Managed。

// Note “managed” on this class, too.
// C++ now handles our deep copies
class dataElem : public Managed {
public:int prop1;int prop2;String name;
};

通过这些更改,C++类在统一内存中分配存储,并自动处理深度副本。我们可以像任何C++对象一样在统一内存中分配dataElem。

dataElem *data = new dataElem;

请注意,您需要确保继承树中的每个类都继承自Managed,否则您的内存映射中会出现漏洞。实际上,您可能需要在CPU和GPU之间共享的所有内容都应该继承Managed。如果你更喜欢简单地使用统一内存来处理所有事情,你可以在全局范围内重载new和delete,但这只有在没有仅CPU数据的情况下才有意义,否则数据将不必要地迁移。
现在,当我们将对象传递给内核函数时,我们有一个选择;与C++中的正常情况一样,我们可以按值传递或按引用传递,如下面的示例代码所示。

// Pass-by-reference version
__global__ void kernel_by_ref(dataElem &data) { ... }// Pass-by-value version
__global__ void kernel_by_val(dataElem data) { ... }int main(void) {dataElem *data = new dataElem;...// pass data to kernel by referencekernel_by_ref<<<1,1>>>(*data);// pass data to kernel by value -- this will create a copykernel_by_val<<<1,1>>>(*data);
}

得益于统一内存,深度拷贝、按值传递和按引用传递都能正常工作。这为在GPU上运行C++代码提供了巨大的价值。
这篇文章中的例子可以在Github上找到。

5. 统一内存的光明未来

CUDA 6中统一内存最令人兴奋的事情之一是它只是一个开始。cuda围绕统一内存计划了一个漫长的改进和功能路线图。
统一内存的第一个版本旨在使CUDA编程更容易,特别是对于初学者。从CUDA 6开始,cudaemcpy()不再是必需的。通过使用cudaAllocManaged(),您可以有一个指向数据的指针,并且可以在CPU和GPU之间共享复杂的C/C++数据结构。这使得编写CUDA程序变得更加容易,因为您可以直接编写内核,而不是编写大量数据管理代码并维护所有数据的重复主机和设备副本。您仍然可以自由地使用cudaemcpy()(特别是cudamemppyAsync())来提高性能,但这不是一项要求,而是一种优化。

CUDA的未来版本可能会通过添加数据预取和迁移提示来提高使用统一内存的应用程序的性能。统一内存还将增加对更多操作系统的支持。nv的下一代GPU架构将带来一系列硬件改进,以进一步提高性能和灵活性.

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

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

相关文章

Pytorch | 从零构建MobileNet对CIFAR10进行分类

Pytorch | 从零构建MobileNet对CIFAR10进行分类 CIFAR10数据集MobileNet设计理念网络结构技术优势应用领域 MobileNet结构代码详解结构代码代码详解DepthwiseSeparableConv 类初始化方法前向传播 forward 方法 MobileNet 类初始化方法前向传播 forward 方法 训练过程和测试结果…

Electronjs+Vue如何开发PC桌面客户端(Windows,Mac,Linux)

electronjs官网 https://www.electronjs.org/zh/ Electron开发PC桌面客户端的技术选型非常适合已经有web前端开发人员的团队。能够很丝滑的过渡。 Electron是什么&#xff1f; Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 嵌入 Chromium 和 Node.…

【1.排序】

排序 笔记记录 1.排序的基本概念1.1 排序的定义 2. 插入排序2.1 直接插入排序2.2 折半插入排序2.3 希尔排序 3. 交换排序3.1 冒泡排序3.2 快速排序 4. 选择排序4.1 简单选择排序4.2 堆排序 5. 归并排序、基数排序和计数排序5.1 归并排序4.2 基数排序4.3 计数排序 6. 各种内部排…

Linux Swap: 深入解析 mkswap, mkfs.swap, 和 swapon

文章目录 Linux Swap: 深入解析 mkswap, mkfs.swap, 和 swapon什么是 Swap&#xff1f;主要命令介绍1. mkswap2. mkfs.swap3. swapon 创建和管理 Swap 的步骤1. 创建 Swap 分区2. 初始化 Swap3. 激活 Swap4. 持久化配置5. 查看 Swap 状态 删除 Swap 分区或文件1. 停用 Swap2. 删…

取子串(指针)

#include <stdio.h> #include <string.h>char* substr(char *s, int startloc, int len) {static char result[51]; // 定义一个足够大的静态数组来存储结果static char result1[] {N,U,L,L,\0};int i, j;// 检查startloc是否在字符串的范围内if (startloc < 1…

「Mac畅玩鸿蒙与硬件45」UI互动应用篇22 - 评分统计工具

本篇将带你实现一个评分统计工具&#xff0c;用户可以对多个选项进行评分。应用会实时更新每个选项的评分结果&#xff0c;并统计平均分。这一功能适合用于问卷调查或评分统计的场景。 关键词 UI互动应用评分统计状态管理数据处理多目标评分 一、功能说明 评分统计工具允许用…

递归实现指数型枚举(递归)

92. 递归实现指数型枚举 - AcWing题库 每个数有选和不选两种情况 我们把每个数看成每层&#xff0c;可以画出一个递归搜索树 叶子节点就是我们的答案 很容易写出每dfs函数 dfs传入一个u表示层数 当层数大于我们n时&#xff0c;去判断每个数字的选择情况&#xff0c;输出被选…

Linux相关概念和易错知识点(25)(信号原理、操作系统的原理、volatile)

目录 1.信号的产生 &#xff08;1&#xff09;kill &#xff08;2&#xff09;raise、abort 2.对block、pending、handler表的管理 &#xff08;1&#xff09;信号集&#xff08;sigset_t&#xff09; &#xff08;2&#xff09;block表的管理 ①操作相关的函数 ②sigpr…

opencv中的色彩空间及其转换

在 OpenCV 中&#xff0c;色彩空间&#xff08;Color Space&#xff09;指的是表示颜色的一种方式&#xff0c;或是用数学模型对颜色的表达。不同的色彩空间采用不同的方式来描述颜色的三要素&#xff08;如亮度、饱和度、色调&#xff09;&#xff0c;因此可以在不同的应用场景…

大模型微调---Prompt-tuning微调

目录 一、前言二、Prompt-tuning实战2.1、下载模型到本地2.2、加载模型与数据集2.3、处理数据2.4、Prompt-tuning微调2.5、训练参数配置2.6、开始训练 三、模型评估四、完整训练代码 一、前言 Prompt-tuning通过修改输入文本的提示&#xff08;Prompt&#xff09;来引导模型生…

Edge Scdn用起来怎么样?

Edge Scdn&#xff1a;提升网站安全与性能的最佳选择 在当今互联网高速发展的时代&#xff0c;各种网络攻击层出不穷&#xff0c;特别是针对网站的DDoS攻击威胁&#xff0c;几乎每个行业都可能成为目标。为了确保网站的安全性与稳定性&#xff0c;越来越多的企业开始关注Edge …

通信技术以及5G和AI保障电网安全与网络安全

摘 要&#xff1a;电网安全是电力的基础&#xff0c;随着智能电网的快速发展&#xff0c;越来越多的ICT信息通信技术被应用到电力网络。本文分析了历史上一些重大电网安全与网络安全事故&#xff0c;介绍了电网安全与网络安全、通信技术与电网安全的关系以及相应的电网安全标准…

批量提取zotero的论文构建知识库做问答的大模型(可选)——含转存PDF-分割统计PDF等

文章目录 提取zotero的PDF上传到AI平台保留文件名代码分成20个PDF视频讲解 提取zotero的PDF 右键查看目录 发现目录为 C:\Users\89735\Zotero\storage 写代码: 扫描路径‘C:\Users\89735\Zotero\storage’下面的所有PDF文件,全部复制一份汇总到"C:\Users\89735\Downl…

精准采集整车信号:风丘混合动力汽车工况测试

一 背景 混合动力汽车是介于纯电动汽车与燃油汽车两者之间的一种新能源汽车。它既包含纯电动汽车无污染、启动快的优势&#xff0c;又拥有燃油车续航便捷、不受电池容量限制的特点。在当前环境下&#xff0c;混合动力汽车比纯电动汽车更符合目前的市场需求。 然而&#xff0c…

带标题和不带标题的内部表

什么是工作区&#xff1f; 什么是工作区&#xff1f;简单来说&#xff0c;工作区是单行数据。它们应具有与任何内部表相同的格式。它用于一次处理一行内部表中的数据。 内表和工作区的区别 &#xff1f; 一图胜千言 内表的类型 有两种类型的内表&#xff1a; 带 Header 行…

【图像分类实用脚本】数据可视化以及高数量类别截断

图像分类时&#xff0c;如果某个类别或者某些类别的数量远大于其他类别的话&#xff0c;模型在计算的时候&#xff0c;更倾向于拟合数量更多的类别&#xff1b;因此&#xff0c;观察类别数量以及对数据量多的类别进行截断是很有必要的。 1.准备数据 数据的格式为图像分类数据集…

React系列(八)——React进阶知识点拓展

前言 在之前的学习中&#xff0c;我们已经知道了React组件的定义和使用&#xff0c;路由配置&#xff0c;组件通信等其他方法的React知识点&#xff0c;那么本篇文章将针对React的一些进阶知识点以及React16.8之后的一些新特性进行讲解。希望对各位有所帮助。 一、setState &am…

PCIe_Host驱动分析_地址映射

往期内容 本文章相关专栏往期内容&#xff0c;PCI/PCIe子系统专栏&#xff1a; 嵌入式系统的内存访问和总线通信机制解析、PCI/PCIe引入 深入解析非桥PCI设备的访问和配置方法 PCI桥设备的访问方法、软件角度讲解PCIe设备的硬件结构 深入解析PCIe设备事务层与配置过程 PCIe的三…

【阅读记录-章节6】Build a Large Language Model (From Scratch)

文章目录 6. Fine-tuning for classification6.1 Different categories of fine-tuning6.2 Preparing the dataset第一步&#xff1a;下载并解压数据集第二步&#xff1a;检查类别标签分布第三步&#xff1a;创建平衡数据集第四步&#xff1a;数据集拆分 6.3 Creating data loa…

梳理你的思路(从OOP到架构设计)_简介设计模式

目录 1、 模式(Pattern) 是较大的结构​编辑 2、 结构形式愈大 通用性愈小​编辑 3、 从EIT造形 组合出设计模式 1、 模式(Pattern) 是较大的结构 组合与创新 達芬奇說&#xff1a;簡單是複雜的終極形式 (Simplicity is the ultimate form of sophistication) —Leonardo d…