主要内容

GPU内存分配和最小化

离散和管理模式

GPU编码器™提供您访问两个不同的内存分配(malloc在CUDA)模式®编程模型,cudaMalloccudaMallocManagedcudaMallocAPI是传统上适用于独立的CPU和GPU全球记忆。cudaMallocManaged适用于统一内存

从程序员的角度来看,传统的计算机体系结构要求数据分配和共享CPU和GPU之间的内存空间。需要应用程序来管理数据传输这两个内存空间之间增加了增加了复杂性。统一内存池创建一个托管内存、CPU和GPU之间的共享。托管内存访问CPU和GPU通过一个指针。统一内存试图优化内存性能的数据迁移到需要它的设备,同时隐藏迁移计划的细节。虽然统一内存简化了编程模型,它需要device-sync调用当数据写在GPU上被访问CPU。GPU编码器插入这些同步调用。根据英伟达®统一内存可以提供显著的性能好处当使用CUDA 8.0,或者当针对嵌入式硬件等NVIDIA Tegra®

改变内存分配模式的GPU编码器应用,使用Malloc模式下的下拉框设置- > GPU编码器。使用命令行界面时,使用MallocMode构建配置属性和设置它“离散”“统一”

请注意

在未来的版本中,统一内存分配(cudaMallocManaged)模式时,将删除目标NVIDIA GPU设备在开发计算机主机。可以继续使用统一内存分配模式针对NVIDIA嵌入式平台。

GPU内存管理器

您可以使用GPU内存管理器的高效的内存分配,管理和提高运行时性能。GPU内存管理器创建了一个集合并管理大型GPU内存池分配和回收的大块的内存块在这些池。通过创建大的内存池,内存管理器减少CUDA内存api调用的数量,提高运行时性能。您可以使用墨西哥人和独立CUDA GPU内存管理器代码生成。

要启用GPU内存管理器,使用这些方法之一:

  • 在GPU代码配置对象(coder.gpuConfig),使MemoryManager财产。

  • 在GPU编码器应用,GPU代码选项卡上,选择GPU内存管理器

  • 在仿真软件金宝app®配置参数对话框中,代码生成> GPU的代码窗格中,选择内存管理器参数。

使用NVIDIA CUDA CUDA代码库,如cuFFT cuBLAS, cuSOLVER,您可以启用GPU内存管理器的使用有效的内存分配和管理。

使用内存池CUDA库,使内存管理器使用一个和上面的方法:

  • 在GPU代码配置对象(coder.gpuConfig),使EnableCUFFT,EnableCUBLAS,或EnableCUSOLVER属性。

  • 在GPU编码器应用,GPU代码选项卡上,选择使cuFFT,使cuBLAS,或使cuSOLVER

  • 在仿真软件配置金宝app参数对话框中,代码生成> GPU的代码窗格中,选择cuFFT,cuBLAS,或cuSOLVER参数。

GPU内存池的定制选项

GPU内存管理器提供了额外的代码配置参数表中列出的管理分配和重分配在GPU内存池的内存块。

代码配置参数 描述 价值

在GPU代码配置对象(coder.gpuConfig):BlockAlignment

在GPU编码器应用:GPU代码选项卡,块对齐

控制块的对齐。块大小(字节)池中的指定值的倍数。

正整数是2的幂。默认值是256。

在GPU代码配置对象:FreeMode

在GPU编码器应用:GPU代码选项卡,免费模式

控制时,内存管理器释放GPU设备内存。

当设置为“永远”内存已经被释放了,只有当内存管理器被摧毁。

使用“AtTerminate”当自由空GPU池终止函数被调用生成的代码。墨西哥人的目标,内存被释放后每次调用函数生成的墨西哥人。对于其他目标,当调用终止函数内存已经被释放了。

当设置为“AfterAllocate”每次调用后,空池释放CUDA内存分配。

“永远”(默认)|“AtTerminate”|“AfterAllocate”

在GPU代码配置对象:MinPoolSize

在GPU编码器应用:GPU代码选项卡,最小池大小

以兆字节为单位指定的最小池大小(MB)。

正整数是2的幂。默认值是8。

在GPU代码配置对象:MaxPoolSize

在GPU编码器应用:GPU代码选项卡,最大池大小

指定兆字节(MB)的最大池大小。

使用的内存管理器计算规模水平MinPoolSizeMaxPoolSize参数通过插值的两个值之间增加2。例如,如果MinPoolSize4,MaxPoolSize是1024,规模水平{4、8、16、32、64、128、256、512、1024}。

正整数是2的幂。默认值是2048。

内存极小化

GPU编码器之间的数据依赖分析CPU和GPU分区和执行优化的数量降到最低cudaMemcpy函数调用生成的代码。分析还决定了最低的位置数据必须复制CPU和GPU之间使用cudaMemcpy

例如,函数喷火部分的代码,按顺序处理数据在CPU和GPU并行。

函数[出]= foo (input1 input2)…% CPU工作input1 =…input2 =…tmp1 =…tmp2 =……% GPU工作kernel1 (gpuInput1 gpuTmp1);kernel2 (gpuInput2 gpuTmp1 gpuTmp2);kernel3 (gpuTmp1 gpuTmp2 gpuOut);CPU工作……% =结束

一个非CUDA实现可能有多个cudaMemcpy函数调用将所有输入gpuInput1, gpuInput2,暂时的结果gpuTmp1, gpuTmp2内核调用之间。因为中间结果gpuTmp1, gpuTmp2不习惯在GPU之外,它们可以存储在GPU内存从而减少cudaMemcpy函数调用。这些优化提高整体生成的代码的性能。优化的实现是:

gpuInput1 = input1;gpuInput2 = input2;kernel1 < < < > > > (gpuInput1 gpuTmp1);kernel2 < < < > > > (gpuInput2, gpuTmp1 gpuTmp2);kernel3 < < < > > > (gpuTmp1, gpuTmp2 gpuOut);= gpuOut;

为了消除冗余cudaMemcpy电话,GPU编码器分析所有使用给定的变量的定义和使用执行最小化状态标志。一个例子的原始代码,生成的代码是什么样子这个表所示。

原始代码 优化生成的代码
(:)=……i = 1: N g = kernel1 (gA);gA = kernel2 (gB);如果(somecondition) gC = kernel3 (gA、gB);结束结束………= C;
(:)=…A_isDirtyOnCpu = true;…因为我= 1:N如果(A_isDirtyOnCpu) gA =;A_isDirtyOnCpu = false;结束gB = kernel1 (gA);gA = kernel2 (gB);如果(somecondition) gC = kernel3 (gA、gB);C_isDirtyOnGpu = true;结束结束……如果(C_isDirtyOnGpu) C = gC;C_isDirtyOnGpu = false;结束…= C;

_isDirtyOnCpu国旗告诉GPU编码器内存优化程序在给定的变量声明和使用的CPU或GPU。

另请参阅

应用程序

功能

对象

相关的话题