6.13. 流顺序内存分配器

概述

异步分配器允许用户按流顺序分配和释放内存。对分配的所有异步访问都必须发生在分配和释放的流执行之间。如果在承诺的流顺序之外访问内存,则在分配前使用/在释放后使用错误将导致未定义的行为。

分配器可以自由地重新分配内存,只要它可以保证符合标准的内存访问在时间上不会重叠。分配器在建立时间保证时,可以参考内部流顺序以及流间依赖关系(例如 CUDA 事件和空流依赖关系)。分配器还可以插入流间依赖关系以建立时间保证。

支持的平台

设备是否支持集成的流顺序内存分配器可以通过调用 cudaDeviceGetAttribute() 并使用设备属性 cudaDevAttrMemoryPoolsSupported 进行查询。

函数

__host__cudaError_t cudaFreeAsync ( void* devPtr, cudaStream_t hStream )
使用流顺序语义释放内存。
__host__cudaError_t cudaMallocAsync ( void** devPtr, size_t size, cudaStream_t hStream )
使用流顺序语义分配内存。
__host__cudaError_t cudaMallocFromPoolAsync ( void** ptr, size_t size, cudaMemPool_t memPool, cudaStream_t stream )
从指定的池中分配具有流顺序语义的内存。
__host__cudaError_t cudaMemPoolCreate ( cudaMemPool_t* memPool, const cudaMemPoolProps* poolProps )
创建内存池。
__host__cudaError_t cudaMemPoolDestroy ( cudaMemPool_t memPool )
销毁指定的内存池。
__host__cudaError_t cudaMemPoolExportPointer ( cudaMemPoolPtrExportData* exportData, void* ptr )
导出数据以在进程之间共享内存池分配。
__host__cudaError_t cudaMemPoolExportToShareableHandle ( void* shareableHandle, cudaMemPool_t memPool, cudaMemAllocationHandleType handleType, unsigned int  flags )
将内存池导出到请求的句柄类型。
__host__cudaError_t cudaMemPoolGetAccess ( cudaMemAccessFlags ** flags, cudaMemPool_t memPool, cudaMemLocation* location )
返回设备访问池的可访问性。
__host__cudaError_t cudaMemPoolGetAttribute ( cudaMemPool_t memPool, cudaMemPoolAttr attr, void* value )
获取内存池的属性。
__host__cudaError_t cudaMemPoolImportFromShareableHandle ( cudaMemPool_t* memPool, void* shareableHandle, cudaMemAllocationHandleType handleType, unsigned int  flags )
从共享句柄导入内存池。
__host__cudaError_t cudaMemPoolImportPointer ( void** ptr, cudaMemPool_t memPool, cudaMemPoolPtrExportData* exportData )
从另一个进程导入内存池分配。
__host__cudaError_t cudaMemPoolSetAccess ( cudaMemPool_t memPool, const cudaMemAccessDesc* descList, size_t count )
控制设备之间池的可见性。
__host__cudaError_t cudaMemPoolSetAttribute ( cudaMemPool_t memPool, cudaMemPoolAttr attr, void* value )
设置内存池的属性。
__host__cudaError_t cudaMemPoolTrimTo ( cudaMemPool_t memPool, size_t minBytesToKeep )
尝试将内存释放回操作系统。

函数

__host__cudaError_t cudaFreeAsync ( void* devPtr, cudaStream_t hStream )
使用流顺序语义释放内存。
参数
devPtr
hStream
- 建立流顺序承诺的流
描述

插入一个释放操作到hStream。在流执行到达释放操作之后,不得访问该分配。在此 API 返回后,从 GPU 上启动的任何后续工作访问内存或查询其指针属性都会导致未定义的行为。

注意

在流捕获期间,此函数会导致创建释放节点,因此必须传递图分配的地址。

注意

另请参阅

cuMemFreeAsync, cudaMallocAsync

__host__cudaError_t cudaMallocAsync ( void** devPtr, size_t size, cudaStream_t hStream )
使用流顺序语义分配内存。
参数
devPtr
- 返回的设备指针
size
- 要分配的字节数
hStream
- 建立流顺序合同和要从中分配内存的内存池的流
返回值

cudaSuccess, cudaErrorInvalidValue, cudaErrorNotSupported, cudaErrorOutOfMemory,

描述

插入一个分配操作到hStream。分配内存的指针会立即在 *dptr 中返回。在分配操作完成之前,不得访问该分配。分配来自与流的设备关联的内存池。

注意
  • 设备的默认内存池包含来自该设备的设备内存。

  • 基本流排序允许提交到同一流的未来工作使用该分配。流查询、流同步和 CUDA 事件可用于保证分配操作在单独流中提交的工作运行之前完成。

  • 在流捕获期间,此函数会导致创建分配节点。在这种情况下,分配由图而不是内存池拥有。内存池的属性用于设置节点的创建参数。

注意

另请参阅

cuMemAllocAsync, cudaMallocAsync ( C++ API), cudaMallocAsync, cudaFreeAsync, cudaDeviceSetMemPool, cudaDeviceGetDefaultMemPool, cudaDeviceGetMemPool, cudaMemPoolSetAccess, cudaMemPoolSetAttribute, cudaMemPoolGetAttribute

__host__cudaError_t cudaMallocFromPoolAsync ( void** ptr, size_t size, cudaMemPool_t memPool, cudaStream_t stream )
从指定的池中分配具有流顺序语义的内存。
参数
ptr
- 返回的设备指针
size
memPool
- 要从中分配的池
stream
- 建立流顺序语义的流
返回值

cudaSuccess, cudaErrorInvalidValue, cudaErrorNotSupported, cudaErrorOutOfMemory

描述

插入一个分配操作到hStream。分配内存的指针会立即在 *dptr 中返回。在分配操作完成之前,不得访问该分配。分配来自指定的内存池。

注意
  • 指定的内存池可能来自与指定的hStream.

  • 基本流排序允许提交到同一流的未来工作使用该分配。流查询、流同步和 CUDA 事件可用于保证分配操作在单独流中提交的工作运行之前完成。

注意

在流捕获期间,此函数会导致创建分配节点。在这种情况下,分配由图而不是内存池拥有。内存池的属性用于设置节点的创建参数。

另请参阅

cuMemAllocFromPoolAsync, cudaMallocAsync ( C++ API), cudaMallocAsync, cudaFreeAsync, cudaDeviceGetDefaultMemPool, cudaMemPoolCreate, cudaMemPoolSetAccess, cudaMemPoolSetAttribute

__host__cudaError_t cudaMemPoolCreate ( cudaMemPool_t* memPool, const cudaMemPoolProps* poolProps )
创建内存池。
描述

创建 CUDA 内存池并在pool中返回句柄。poolProps确定池的属性,例如后备设备和 IPC 功能。

要创建以特定主机 NUMA 节点为目标的内存池,应用程序必须将 cudaMemPoolProps::cudaMemLocation::type 设置为 cudaMemLocationTypeHostNuma,并且 cudaMemPoolProps::cudaMemLocation::id 必须指定主机内存节点的 NUMA ID。将 cudaMemLocationTypeHostNumaCurrentcudaMemLocationTypeHost 指定为 cudaMemPoolProps::cudaMemLocation::type 将导致 cudaErrorInvalidValue。默认情况下,池的内存将可从其分配的设备访问。对于使用 cudaMemLocationTypeHostNuma 创建的池,它们的默认可访问性将来自主机 CPU。应用程序可以通过为 cudaMemPoolProps::maxSize 指定非零值来控制池的最大大小。如果设置为 0,则池的最大大小将默认为系统相关的值。

打算使用基于 CU_MEM_HANDLE_TYPE_FABRIC 的内存共享的应用程序必须确保:(1)驱动程序创建了 `nvidia-caps-imex-channels` 字符设备,并且该设备列在 /proc/devices 下(2)至少有一个 IMEX 通道文件可供启动应用程序的用户访问。

当导出器和导入器 CUDA 进程被授予对同一 IMEX 通道的访问权限时,它们可以安全地共享内存。

IMEX 通道安全模型基于每个用户。这意味着如果用户有权访问有效的 IMEX 通道,则该用户下的所有进程都可以共享内存。当需要多用户隔离时,每个用户都需要单独的 IMEX 通道。

这些通道文件存在于 /dev/nvidia-caps-imex-channels/channel* 中,可以使用标准的操作系统本机调用(如 Linux 上的 mknod)来创建。例如:要使用 /proc/devices 中的主设备号创建 channel0,用户可以执行以下命令:`mknod /dev/nvidia-caps-imex-channels/channel0 c <主设备号>=""> 0`

注意

指定 cudaMemHandleTypeNone 会创建一个不支持 IPC 的内存池。

另请参阅

cuMemPoolCreate, cudaDeviceSetMemPool, cudaMallocFromPoolAsync, cudaMemPoolExportToShareableHandle, cudaDeviceGetDefaultMemPool, cudaDeviceGetMemPool

__host__cudaError_t cudaMemPoolDestroy ( cudaMemPool_t memPool )
销毁指定的内存池。
描述

如果在调用 cudaMemPoolDestroy 时,从此池中获得的任何指针尚未释放,或者池中有尚未完成的释放操作,则该函数将立即返回,并且与池关联的资源将在没有更多未完成的分配时自动释放。

销毁设备的当前内存池会将该设备的默认内存池设置为该设备的当前内存池。

注意

设备的默认内存池无法销毁。

另请参阅

cuMemPoolDestroy, cudaFreeAsync, cudaDeviceSetMemPool, cudaDeviceGetDefaultMemPool, cudaDeviceGetMemPool, cudaMemPoolCreate

__host__cudaError_t cudaMemPoolExportPointer ( cudaMemPoolPtrExportData* exportData, void* ptr )
导出数据以在进程之间共享内存池分配。
参数
exportData
ptr
- 要导出的内存指针
返回值

cudaSuccess, cudaErrorInvalidValue, cudaErrorOutOfMemory

描述

构造shareData_out用于从已共享的内存池中共享特定分配。接收进程可以使用 cudaMemPoolImportPointer API 导入分配。数据不是句柄,可以通过任何 IPC 机制共享。

另请参阅

cuMemPoolExportPointer, cudaMemPoolExportToShareableHandle, cudaMemPoolImportFromShareableHandle, cudaMemPoolImportPointer

__host__cudaError_t cudaMemPoolExportToShareableHandle ( void* shareableHandle, cudaMemPool_t memPool, cudaMemAllocationHandleType handleType, unsigned int  flags )
将内存池导出到请求的句柄类型。
参数
shareableHandle
memPool
handleType
- 要创建的句柄类型
flags
- 必须为 0
返回值

cudaSuccess, cudaErrorInvalidValue, cudaErrorOutOfMemory

描述

给定一个支持 IPC 的内存池,创建一个操作系统句柄以与其他进程共享该内存池。接收进程可以使用 cudaMemPoolImportFromShareableHandle 将可共享句柄转换为内存池。然后可以使用 cudaMemPoolExportPointercudaMemPoolImportPointer API 共享单个指针。可共享句柄是什么以及如何传输它由请求的句柄类型定义。

注意

: 要创建支持 IPC 的内存池,请使用除 cudaMemHandleTypeNone 之外的 CUmemAllocationHandleType 创建内存池。

另请参阅

cuMemPoolExportToShareableHandle, cudaMemPoolImportFromShareableHandle, cudaMemPoolExportPointer, cudaMemPoolImportPointer

__host__cudaError_t cudaMemPoolGetAccess ( cudaMemAccessFlags ** flags, cudaMemPool_t memPool, cudaMemLocation* location )
返回从设备访问池的可访问性。
参数
flags
- 从指定位置访问池的可访问性
memPool
- 正在查询的池
location
- 访问池的位置
描述

返回从指定位置访问池内存的可访问性。

另请参阅

cuMemPoolGetAccess, cudaMemPoolSetAccess

__host__cudaError_t cudaMemPoolGetAttribute ( cudaMemPool_t memPool, cudaMemPoolAttr attr, void* value )
获取内存池的属性。
参数
memPool
attr
- 要获取的属性
value
- 检索到的值
描述

支持的属性有

注意

请注意,根据 cudaStreamAddCallback 的规定,不得从回调中调用任何 CUDA 函数。cudaErrorNotPermitted 可能会返回,但不保证作为这种情况下的诊断信息。

另请参阅

cuMemPoolGetAttribute, cudaMallocAsync, cudaFreeAsync, cudaDeviceGetDefaultMemPool, cudaDeviceGetMemPool, cudaMemPoolCreate

__host__cudaError_t cudaMemPoolImportFromShareableHandle ( cudaMemPool_t* memPool, void* shareableHandle, cudaMemAllocationHandleType handleType, unsigned int  flags )
从共享句柄导入内存池。
参数
memPool
shareableHandle
handleType
- 要导入的句柄类型
flags
- 必须为 0
返回值

cudaSuccess, cudaErrorInvalidValue, cudaErrorOutOfMemory

描述

可以使用 cudaMemPoolImportPointer 从导入的池中导入特定分配。

注意

导入的内存池不支持创建新分配。因此,导入的内存池可能不用于 cudaDeviceSetMemPoolcudaMallocFromPoolAsync 调用。

另请参阅

cuMemPoolImportFromShareableHandle, cudaMemPoolExportToShareableHandle, cudaMemPoolExportPointer, cudaMemPoolImportPointer

__host__cudaError_t cudaMemPoolImportPointer ( void** ptr, cudaMemPool_t memPool, cudaMemPoolPtrExportData* exportData )
从另一个进程导入内存池分配。
描述

在以下项中返回ptr_out指向导入内存的指针。在导出进程中的分配操作完成之前,不得访问导入的内存。在导出进程中释放导入的内存之前,必须从所有导入进程中释放导入的内存。可以使用 cudaFree 或 cudaFreeAsync 释放指针。如果使用 cudaFreeAsync,则必须在导出进程中的释放操作之前在导入进程中完成释放。

注意

只要导出进程中的 cudaFreeAsync 指定的流与导入进程的 cudaFreeAsync 具有流依赖性,就可以在导出进程中使用 cudaFreeAsync API,而无需等待其流中的 cudaFreeAsync 操作完成。

另请参阅

cuMemPoolImportPointer, cudaMemPoolExportToShareableHandle, cudaMemPoolImportFromShareableHandle, cudaMemPoolExportPointer

__host__cudaError_t cudaMemPoolSetAccess ( cudaMemPool_t memPool, const cudaMemAccessDesc* descList, size_t count )
控制设备之间池的可见性。
参数
memPool
descList
count
- 映射数组中描述符的数量。
__host__cudaError_t cudaMemPoolSetAttribute ( cudaMemPool_t memPool, cudaMemPoolAttr attr, void* value )
设置内存池的属性。
参数
memPool
attr
attr
value
- 要修改的属性
描述

支持的属性有

  • cudaMemPoolAttrReleaseThreshold: (value type = cuuint64_t) 在尝试将内存释放回操作系统之前,要保留的已保留内存量(以字节为单位)。当内存池持有的内存超过释放阈值字节时,分配器将在下次调用流、事件或上下文同步时尝试将内存释放回操作系统。(默认值为 0)

  • cudaMemPoolReuseFollowEventDependencies: (value type = int) 只要分配流依赖于释放操作的流排序依赖关系存在,就允许 cudaMallocAsync 使用在另一个流中异步释放的内存。Cuda 事件和空流交互可以创建所需的流有序依赖关系。(默认启用)

  • cudaMemPoolReuseAllowOpportunistic: (value type = int) 当释放和分配之间没有依赖关系时,允许重用已完成的释放。(默认启用)

  • cudaMemPoolReuseAllowInternalDependencies: (value type = int) 允许 cudaMallocAsync 插入新的流依赖关系,以便建立重用由 cudaFreeAsync 释放的一块内存所需的流排序。(默认启用)。

  • - 指向要分配的值的指针

  • cudaMemPoolAttrReservedMemHigh: (value type = cuuint64_t) 重置跟踪为内存池分配的后备内存量的最高水位线。将此属性设置为非零值是非法的。

注意

请注意,根据 cudaStreamAddCallback 的规定,不得从回调中调用任何 CUDA 函数。cudaErrorNotPermitted 可能会返回,但不保证作为这种情况下的诊断信息。

另请参阅

cudaMemPoolAttrUsedMemHigh: (value type = cuuint64_t) 重置跟踪为内存池分配的已用内存量的最高水位线。将此属性设置为非零值是非法的。

__host__cudaError_t cudaMemPoolTrimTo ( cudaMemPool_t memPool, size_t minBytesToKeep )
尝试将内存释放回操作系统。
参数
memPool
minBytesToKeep
- 如果池的保留内存少于 minBytesToKeep,则 TrimTo 操作不执行任何操作。否则,保证池在操作后至少保留 minBytesToKeep 字节。
描述

将内存释放回操作系统,直到池包含少于 minBytesToKeep 保留字节,或者没有更多分配器可以安全释放的内存。分配器无法释放支持未完成的异步分配的操作系统分配。操作系统分配可能以不同于用户分配的粒度发生。

注意
  • : 尚未释放的分配计为未完成。

  • : 已异步释放但其完成尚未在主机上观察到的分配(例如,通过同步)可以计为未完成。

注意

请注意,根据 cudaStreamAddCallback 的规定,不得从回调中调用任何 CUDA 函数。cudaErrorNotPermitted 可能会返回,但不保证作为这种情况下的诊断信息。

另请参阅

cuMemPoolTrimTo, cudaMallocAsync, cudaFreeAsync, cudaDeviceGetDefaultMemPool, cudaDeviceGetMemPool, cudaMemPoolCreate