并行编程实战——CUDA编程的内存建

📅 发布时间:2026/7/16 3:35:02 👁️ 浏览次数:
并行编程实战——CUDA编程的内存建
一、内存优化中的内存建议统一内存的优势是让开发者在面对内存只是看到一个内存而不是要区别主机和设备内存这样更有利于应用和底层管理的操作。毕竟复杂度的降低往往都是一种技术的进步。而统一内存出现后就对内存的优化提供了统一的路径除了前面提到的内存的预取另外一个就是本文将要分析的内存建议memory advise。内存建议是与统一内存配合使用的一种高级的内存优化技术。其关键的技术点在于向CUDA运行时提供了内存访问模式的提示hints。它可以让CUDA整体上在一个较长的周期内做出更优的数据迁移策略减少内存的抖动笔缺页中断等提高运行的性能。内存建议其实就是在保证统一内存管理的前提下通过显式的说明让CUDA框架确定统一内存的适配对象、应用范围等等。即在一个整体的宏观的方向上为CUDA运行时提供一个对内存操作的可能性。这样CUDA运行时就可以为其提供稳定的内存布局决策防止短期的优化操作。其定义为cudaError_tcudaMemAdvise(constvoid*devPtr,size_tcount,cudaMemoryAdvise advice,intdevice);这个函数的关键在于第三个参数即cudaMemoryAdvise advice它是一个枚举用于确定建议的种类。二、CUDA的内存建议种类在CUDA接口cudaMemAdvise中内存建议cudaMemoryAdvise枚举主要有三种情况只读建议cudaMemAdviseSetReadMostly用于在每个访问该数据的处理器上创建只读副本避免数据的迁移。它只适合于共享读即读多写少的场景否则反而会适得其反首选建议cudaMemAdviseSetPreferredLocation将数据的物理存储位置固定在设备上CPU或GPU其它设备访问只建议映射而不进行迁移。它适合对设备应用明确其它设备操作偶发的情况下应用。但需要注意的是如果硬件不支持远程映射则仍然会引发数据迁移。访问设备建议cudaMemAdviseSetAccessedBy设定目标设备GPU预先建立直接的内存映射从而确保映射的数据对物理存储的透明和完备性保证不会因为缺页而触发中断。它一般在多GPU协同工作的场景下两个GPU间可能会频繁的进行数据的交互。不过映射会导致些许的性能损失这一点要考虑到再次强调内存建议是非强制笥的可能被忽略所以要根据情况来实际确定。具体的可以通过Nsight Systems工具进行可视化的内存迁移监控确定内存建议是否生效。三、分析说明如果说内存预取一般可立马看到效果但内存建议未必。毕竟“建议”这两个字本身就代表着非强制性意思。在一些文档中针对主流的平台测试intel x86 pascal gpu可以看到在显存满足应用的场景下内存建议导致的性能的提升几乎可以忽略。而在显存超50%的负荷后使用内存建议可以获得较高的提升大约25%而在另外一个平台上IBM Power9Volta GPU则恰恰相反。这意味着这项内存增强技术与硬件平台耦合紧密在实际应用时需要认真的对硬件平台和软件应用场景进行评估。另外内存建议只适合于统一内存cudaMallocManaged的优化和增强并对相关的硬件设备和CUDA版本有一定的要求不要想当然的进行应用和操作。四、应用场景在掌握了内存建议的内容后就可以发现与之相应的开发场景主要有需要显式的参数预加载和预指定在与内存预取协同的情况下通过内存建议应用在大模型的推理和训练中。根据实际的不同可以将数据预加载到指定的CPU和GPU上。可以有效的防止首次加载的数据迁移。分布式GPU应用AI中的大模型中多GPU的分布式处理已经成为一种主流这对于某些场景下GPU的交互使用内存建议中的“访问设备建议”就非常重要。特别是当多个GPU共享参数时就有明显的效果。CPU-GPU协同处理在实地的应用场景中可能需要CPU和GPU协同操作比如CPU也可能访问运算的中间态结果数据在哪个设备上更有优势这都是内存建议可以发挥其作用的地方。CUDA虽然应用场景很多但现在AI风头正盛其它的一切都在它的应用前变得黯淡无光所以基本上谈CUDA不能离开AI的应用。五、例程看一个内存建议的简单例子#includecuda_runtime.h#includedevice_launch_parameters.h#includestdio.h__global__voidwrite(int*ret,inta,intb){ret[threadIdx.x]abthreadIdx.x;}__global__voidappend(int*ret,inta,intb){ret[threadIdx.x]abthreadIdx.x;}intmain(){int*ret;cudaMallocManaged(ret,1000*sizeof(int));cudaMemLocation location{cudaMemLocationTypeHost};cudaMemAdvise(ret,1000*sizeof(int),cudaMemAdviseSetAccessedBy,location);// set direct access hintwrite1,1000(ret,10,100);// pages populated in GPU memorycudaDeviceSynchronize();for(inti0;i1000;i)printf(%d: AB %d\n,i,ret[i]);// directManagedMemAccessFromHost1: CPU accesses GPU memory directly without migrations// directManagedMemAccessFromHost0: CPU faults and triggers device-to-host migrationsappend1,1000(ret,10,100);// directManagedMemAccessFromHost1: GPU accesses GPU memory without migrationscudaDeviceSynchronize();// directManagedMemAccessFromHost0: GPU faults and triggers host-to-device migrationscudaFree(ret);return0;}代码来自官网。上面的注释很清楚就不重复说明了。六、总结技术应用的默认设置往往是超于保守的目的是为了兼容性和安全性的控制。但在某些明确目标的情况下开发者是可以显式的屏蔽短板的情况的这样就可以使用内存建议这种技术对内存进行优化。优化技术是一个体系所以内存建议经常和内存预取等优化技术一起协同工作从整体上完成对内存的优化。达到设计的目的和并满足实际的需求。