news 2026/5/8 18:57:36

并行编程实战——CUDA编程的统一内存

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
并行编程实战——CUDA编程的统一内存

一、统一内存

在前面的分析中,对CUDA中的内存进行了整体的说明和分项的说明。但随着硬件和软件技术的不断进步,新的CUDA会跟随着GPU不同的架构会不断的演进。新功能的不断添加,在为开发者提供了更方便快捷且更强大的功能外,也提供了复杂的编程差异度。为了方便开发者进行程序和算法的移植,保证不同版本下的CUDA开发尽量保持一致,CUDA6.0提供了一个重要功能——统一内存,Unified Memory(UM)。它支持GPU硬件Kepler GPU架构及以后的迭代版本。
统一内存的的功能和编程范式都在不断的推进,在不同的版本中可能不尽相同,目前最新的为官网上的CUDA13.1版本。

二、统一内存的特点和分析

统一内存看名字就比较容易理解,统一的,不再区分什么主机和设备(CPU和GPU)的单独内存管理。也就是说,在它们眼中,这片内存是都可以直接操作并管理的。这就大大的减轻了不同内存空间复制操作的复杂度,并因此产生了一些新的技术应用如数据预取等。它包含以下几个重点特点:

  1. 所有CPU、GPU使用同一内存空间,降低开发复杂度并消除它们之间的数据复制
  2. 高性能,减少CPU和GPU间的数据复制,将数据预取或移动到操作频率高的处理器,减少内存整体的使用数量,提高数据访问速度,从而在整体提高性能
  3. 容量扩展,有点类似于虚拟内存的意思,使得GPU可以突破自身的内存大小来操作数据

在CUDA编程中,获取统一内存的方法有两种:

  1. 系统分配内存,使用系统API在主机上分配的内存:堆栈变量、全局/文件作用域变量、malloc()/mmap()、线程本地变量等。
  2. 显式分配统一内存的CUDA API,如cudaAllocManaged函数,其分配的内存在更多系统上可用,其可能优于系统分配内存

需要注意的是,数据的移动并不会因为统一内存的存在而完全消除,只是会减少。
另外,此处需要说明一下托管内存:
上面提到的cudaAllocManaged函数可以提供托管内存的分配。统一内存提供托管内存用来桥接主机和设备内存空间。托管内存可以从系统中的所有CPU和GPU访问,作为具有公共地址空间的单个连续内存映像。托管内存实现了设备内存的扩展,并通过消除主机和设备间显式镜像数据的过程,极大简化了应用程序移植的复杂度。托管内存仅用于堆数据,而不是栈/静态数据。
如果想了解当前境对统一内存的支持程度,可以通过下面的方法进行查询(使用cudaDeviceGetAttribute函数):

  1. 完全支持统一内存
    pageableMemoryAccess设置为1,如果支持硬件加速还会把hostNativeAtomicSupported, pageableMemoryAccessUsesHostPageTables, directManagedMemAccessFromHost也设置为1
  2. CUDA托管内存完全支持
    concurrentManagedAccess设置为1而pageableMemoryAccess设置为0
  3. CUDA托管内存不完全支持
    managedMemory设置为1而concurrentManagedAccess设置为0
  4. 不支持
    managedMemory设置为0

在硬件和系统支持上,统一内存的要求都比较严格,比如在Linux平台上,对内核的版本、显卡的计算力等等,都需要开发者去进行确定,不能盲目的使用相关的特点,导致引入一些莫名的问题。
在最新的CUDA文档说明中,对其进行了更抽象的说明,有兴趣的可以自行查阅,并进行相关的比较学习。

三、CUDA中的应用

CUDA中提供了以下几种统一内存开发的接口:

  1. 系统API
    在完全支持统一内存的系统上,通过过主机进程系统分配的相关API都可以支持统一内存的操作。如malloc,new,mmap等
  2. CUDA托管内存API
    比如通过cudaMallocManaged函数即获取相关的统一内存地址
  3. CUDA中的托管变量
    即在CUDA中使用/__managed__声明的变量等

通过上面的方式方法,就可以在CUDA编程中创建和使用统一内存并进行相关的功能应用(比如后面分析的数据预取)。
CUDA的托管内存在GPU Pascal架构开始,就不再直接分配物理内存了,而是在首次应用的基础上分配内存(和COW有点意思啊)。GPU和CPU在分配内存时略有不同,如果CPU先进行分配则分配映射到CPU,GPU先进行分配则分配到GPU的页表。那么就会出现一个问题,如果CPU分配了内存但GPU使用,则会出现页面错误,内存会进行重新的复制即从CPU内存中复制到GPU内存。由此产生的成本是相当高的。
那既然存在这种问题,就会有解决问题的方法。在CUDA中有两种方法,第一种是使用warp优化统一内存;另外一个是使用数据预取。

  1. warp优化统一内存
    Per-page warp,即尽量让同一个warp的线程访问同一个内存页的数据。目的就是将代价巨大的页面迁移次数尽量降低
  2. 数据预取
    Data Prefetching,就是提前把数据加载到指定的处理器处理器相关位置。在后面的文章中会进行详细的分析说明。

通过上面的说明,大家就对统一内存的应用有一个初步的印象,然后在此基础上就可以不断的进行实践编程,进一步掌握相关的技术知识。

四、例程

根据上面的说明,看一下例程

//system malloc//no support__global__voidwrite_value(int*ptr,intv){*ptr=v;}intmain(){int*d_ptr=nullptr;// Does not require any unified memory supportcudaMalloc(&d_ptr,sizeof(int));write_value<<<1,1>>>(d_ptr,1);inth_value;// Copy memory back to the host and synchronizecudaMemcpy(&h_value,d_ptr,sizeof(int),cudaMemcpyDefault);printf("value = %d\n",h_value);cudaFree(d_ptr);return0;}//malloc__global__voidwrite_value(int*ptr,intv){*ptr=v;}intmain(){// Requires System-Allocated Memory supportint*ptr=(int*)malloc(sizeof(int));write_value<<<1,1>>>(ptr,1);// Synchronize required// (before, cudaMemcpy was synchronizing)cudaDeviceSynchronize();printf("value = %d\n",*ptr);free(ptr);return0;}//Requires System-Allocated Memory support__global__voidwrite_value(int*ptr,intv){*ptr=v;}intmain(){// Requires System-Allocated Memory supportintvalue;write_value<<<1,1>>>(&value,1);// Synchronize required// (before, cudaMemcpy was synchronizing)cudaDeviceSynchronize();printf("value = %d\n",value);return0;}//managed Memory__global__voidwrite_value(int*ptr,intv){*ptr=v;}intmain(){int*ptr=nullptr;// Requires CUDA Managed Memory supportcudaMallocManaged(&ptr,sizeof(int));write_value<<<1,1>>>(ptr,1);// Synchronize required// (before, cudaMemcpy was synchronizing)cudaDeviceSynchronize();printf("value = %d\n",*ptr);cudaFree(ptr);return0;}//managed var__global__voidwrite_value(int*ptr,intv){*ptr=v;}// Requires CUDA Managed Memory support__managed__intvalue;intmain(){write_value<<<1,1>>>(&value,1);// Synchronize required// (before, cudaMemcpy was synchronizing)cudaDeviceSynchronize();printf("value = %d\n",value);return0;}

代码来自官方文档,大家可以根据文档的相关内容展开更多的代码实例测试。
上面的代码首先是一个不需要统一内存支持的标准的代码,然后是两个在完全支持统一内存环境下的malloc和栈变量的代码,最后是托管接口和托管变量的代码。

五、总结

统一内存作为一种正在不断演进的技术或功能,需要开发者注意其应用的软硬件环境,特别是在不同的平台上不同的细节功能把握,不要在这些细节上犯一些低级的错误。也可以这样理解,统一内存的应用与环境紧密相关,不能脱离开进行专门的讨论。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/29 11:52:12

颠覆性语音合成技术:Chatterbox如何重塑企业级TTS市场格局

颠覆性语音合成技术&#xff1a;Chatterbox如何重塑企业级TTS市场格局 【免费下载链接】chatterbox 项目地址: https://ai.gitcode.com/hf_mirrors/ResembleAI/chatterbox 在数字化转型浪潮中&#xff0c;语音交互已成为企业服务升级的关键环节。然而&#xff0c;传统语…

作者头像 李华
网站建设 2026/4/29 15:30:51

STLink在工业控制中的应用:实战案例解析

STLink在工业控制中的实战落地&#xff1a;从开发到产线的全链路解析你有没有遇到过这样的场景&#xff1f;产线上&#xff0c;几十块电机驱动板排队等待烧录固件&#xff0c;每块耗时15秒——一天下来&#xff0c;光编程就浪费了近两个小时。现场调试时&#xff0c;STLink突然…

作者头像 李华
网站建设 2026/4/28 2:54:20

终极指南:HandBrake两大降噪算法深度对比与实战优化

终极指南&#xff1a;HandBrake两大降噪算法深度对比与实战优化 【免费下载链接】HandBrake HandBrakes main development repository 项目地址: https://gitcode.com/gh_mirrors/ha/HandBrake 在视频转码过程中&#xff0c;噪点问题一直是困扰进阶用户的技术难题。作为…

作者头像 李华
网站建设 2026/5/2 5:44:20

xtb量子化学计算软件:突破传统计算瓶颈的科研利器

在量子化学计算领域&#xff0c;你是否曾因计算速度太慢而错过重要发现&#xff1f;是否因计算资源不足而无法研究大分子体系&#xff1f;xtb半经验扩展紧束缚程序包正是为你解决这些挑战的强大工具。作为一个高效准确的量子化学计算软件&#xff0c;xtb在保持专业精度的同时大…

作者头像 李华
网站建设 2026/5/2 11:06:21

终极指南:如何用文本快速创建专业图表

终极指南&#xff1a;如何用文本快速创建专业图表 【免费下载链接】nodeppt This is probably the best web presentation tool so far! 项目地址: https://gitcode.com/gh_mirrors/no/nodeppt 还在为制作演示文稿中的图表而烦恼吗&#xff1f;nodeppt图表制作工具让你用…

作者头像 李华
网站建设 2026/5/5 8:20:12

如何快速部署AI大模型:CPU环境下的完整实践指南

如何快速部署AI大模型&#xff1a;CPU环境下的完整实践指南 【免费下载链接】T-pro-it-2.0-GGUF 项目地址: https://ai.gitcode.com/hf_mirrors/t-tech/T-pro-it-2.0-GGUF 在人工智能技术飞速发展的今天&#xff0c;本地部署大语言模型已成为技术爱好者和开发者的重要需…

作者头像 李华