6.15. 流序内存分配器
本节介绍由底层 CUDA 驱动程序应用程序编程接口公开的流序内存分配器。
概述
异步分配器允许用户以流序分配和释放内存。所有分配的异步访问必须发生在分配和释放的流执行之间。如果内存访问超出承诺的流序范围,则先使用后分配/使用后释放错误将导致未定义行为。
分配器可以自由地重新分配内存,只要它可以保证合规的内存访问不会在时间上重叠。在建立时间保证时,分配器可以参考内部流序以及流间依赖关系(例如 CUDA 事件和空流依赖关系)。分配器也可能插入流间依赖关系以建立时间保证。
支持的平台
设备是否支持集成流序内存分配器可以通过调用 cuDeviceGetAttribute() 并使用设备属性 CU_DEVICE_ATTRIBUTE_MEMORY_POOLS_SUPPORTED 来查询
函数
- CUresult cuMemAllocAsync ( CUdeviceptr* dptr, size_t bytesize, CUstream hStream )
- 使用流序语义分配内存。
- CUresult cuMemAllocFromPoolAsync ( CUdeviceptr* dptr, size_t bytesize, CUmemoryPool pool, CUstream hStream )
- 从指定的池中分配具有流序语义的内存。
- CUresult cuMemFreeAsync ( CUdeviceptr* dptr, CUstream hStream )
- 使用流序语义释放内存。
- CUresult cuMemPoolCreate ( CUmemoryPool* pool, const CUmemPoolProps* poolProps )
- 创建内存池。
- CUresult cuMemPoolDestroy ( CUmemoryPool pool )
- 销毁指定的内存池。
- CUresult cuMemPoolExportPointer ( CUmemPoolPtrExportData* shareData_out, CUdeviceptr ptr )
- 导出数据以在进程之间共享内存池分配。
- CUresult cuMemPoolExportToShareableHandle ( void* handle_out, CUmemoryPool pool, CUmemAllocationHandleType handleType, unsigned long long flags )
- 将内存池导出到请求的句柄类型。
- CUresult cuMemPoolGetAccess ( CUmemAccess_flags* flags, CUmemoryPool memPool, CUmemLocation* location )
- 返回从设备访问池的可访问性。
- CUresult cuMemPoolGetAttribute ( CUmemoryPool pool, CUmemPool_attribute attr, void* value )
- 获取内存池的属性。
- CUresult cuMemPoolImportFromShareableHandle ( CUmemoryPool* pool_out, void* handle, CUmemAllocationHandleType handleType, unsigned long long flags )
- 从共享句柄导入内存池。
- CUresult cuMemPoolImportPointer ( CUdeviceptr* ptr_out, CUmemoryPool pool, CUmemPoolPtrExportData* shareData )
- 从另一个进程导入内存池分配。
- CUresult cuMemPoolSetAccess ( CUmemoryPool pool, const CUmemAccessDesc* map, size_t count )
- 控制设备之间池的可见性。
- CUresult cuMemPoolSetAttribute ( CUmemoryPool pool, CUmemPool_attribute attr, void* value )
- 设置内存池的属性。
- CUresult cuMemPoolTrimTo ( CUmemoryPool pool, size_t minBytesToKeep )
- 尝试将内存释放回操作系统。
函数
- CUresult cuMemAllocAsync ( CUdeviceptr* dptr, size_t bytesize, CUstream hStream )
-
使用流序语义分配内存。
参数
- dptr
- - 返回的设备指针
- bytesize
- - 要分配的字节数
- hStream
- - 建立流序合约的流以及要从中分配的内存池
返回值
CUDA_SUCCESS, CUDA_ERROR_INVALID_VALUE, CUDA_ERROR_NOT_INITIALIZED, CUDA_ERROR_INVALID_CONTEXT (没有当前上下文时指定了默认流), CUDA_ERROR_NOT_SUPPORTED, CUDA_ERROR_OUT_OF_MEMORY
描述
将分配操作插入到hStream。指向已分配内存的指针立即在 *dptr 中返回。在分配操作完成之前,不得访问分配。分配来自当前流设备相关的内存池。
注意-
设备的默认内存池包含来自该设备的设备内存。
-
基本流序允许提交到同一流的未来工作使用分配。流查询、流同步和 CUDA 事件可用于保证分配操作在单独的流中提交的工作运行之前完成。
-
在流捕获期间,此函数会导致创建分配节点。在这种情况下,分配由图而不是内存池拥有。内存池的属性用于设置节点的创建参数。
另请参阅
cuMemAllocFromPoolAsync, cuMemFreeAsync, cuDeviceSetMemPool, cuDeviceGetDefaultMemPool, cuDeviceGetMemPool, cuMemPoolCreate, cuMemPoolSetAccess, cuMemPoolSetAttribute
- CUresult cuMemAllocFromPoolAsync ( CUdeviceptr* dptr, size_t bytesize, CUmemoryPool pool, CUstream hStream )
-
从指定的池中分配具有流序语义的内存。
参数
- dptr
- - 返回的设备指针
- bytesize
- - 要分配的字节数
- pool
- - 要从中分配的池
- hStream
- - 建立流序语义的流
返回值
CUDA_SUCCESS, CUDA_ERROR_INVALID_VALUE, CUDA_ERROR_NOT_INITIALIZED, CUDA_ERROR_INVALID_CONTEXT (没有当前上下文时指定了默认流), CUDA_ERROR_NOT_SUPPORTED, CUDA_ERROR_OUT_OF_MEMORY
描述
将分配操作插入到hStream。指向已分配内存的指针立即在 *dptr 中返回。在分配操作完成之前,不得访问分配。分配来自指定的内存池。
注意-
指定的内存池可能来自与指定流设备不同的设备hStream.
-
基本流序允许提交到同一流的未来工作使用分配。流查询、流同步和 CUDA 事件可用于保证分配操作在单独的流中提交的工作运行之前完成。
注意在流捕获期间,此函数会导致创建分配节点。在这种情况下,分配由图而不是内存池拥有。内存池的属性用于设置节点的创建参数。
另请参阅
cuMemAllocAsync, cuMemFreeAsync, cuDeviceGetDefaultMemPool, cuDeviceGetMemPool, cuMemPoolCreate, cuMemPoolSetAccess, cuMemPoolSetAttribute
- CUresult cuMemFreeAsync ( CUdeviceptr* dptr, CUstream hStream )
-
使用流序语义释放内存。
参数
- dptr
- - 要释放的内存
- hStream
- - 建立流序合约的流。
返回值
CUDA_SUCCESS, CUDA_ERROR_INVALID_VALUE, CUDA_ERROR_NOT_INITIALIZED, CUDA_ERROR_INVALID_CONTEXT (没有当前上下文时指定了默认流), CUDA_ERROR_NOT_SUPPORTED
描述
将释放操作插入到hStream。在流执行到达释放点后,不得访问分配。在此 API 返回后,从 GPU 上启动的任何后续工作中访问内存或查询其指针属性都会导致未定义行为。
注意在流捕获期间,此函数会导致创建一个释放节点,因此必须传递图分配的地址。
- CUresult cuMemPoolCreate ( CUmemoryPool* pool, const CUmemPoolProps* poolProps )
-
创建内存池。
返回值
CUDA_SUCCESS, CUDA_ERROR_NOT_INITIALIZED, CUDA_ERROR_INVALID_VALUE, CUDA_ERROR_OUT_OF_MEMORY, CUDA_ERROR_NOT_PERMITTEDCUDA_ERROR_NOT_SUPPORTED
描述
创建 CUDA 内存池并在pool中返回句柄。poolProps确定池的属性,例如后备设备和 IPC 功能。
要创建针对特定主机 NUMA 节点的内存池,应用程序必须将 CUmemPoolProps::CUmemLocation::type 设置为 CU_MEM_LOCATION_TYPE_HOST_NUMA,并且 CUmemPoolProps::CUmemLocation::id 必须指定主机内存节点的 NUMA ID。将 CU_MEM_LOCATION_TYPE_HOST_NUMA_CURRENT 或 CU_MEM_LOCATION_TYPE_HOST 指定为 CUmemPoolProps::CUmemLocation::type 将导致 CUDA_ERROR_INVALID_VALUE。默认情况下,池的内存将可从其分配到的设备访问。对于使用 CU_MEM_LOCATION_TYPE_HOST_NUMA 创建的池,它们的默认可访问性将来自主机 CPU。应用程序可以通过为 CUmemPoolProps::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 <major number>=""> 0`
注意指定 CU_MEM_HANDLE_TYPE_NONE 会创建一个不支持 IPC 的内存池。
另请参阅
cuDeviceSetMemPool, cuDeviceGetMemPool, cuDeviceGetDefaultMemPool, cuMemAllocFromPoolAsync, cuMemPoolExportToShareableHandle
- CUresult cuMemPoolDestroy ( CUmemoryPool pool )
-
销毁指定的内存池。
描述
如果从此池中获得的任何指针尚未释放,或者池中有尚未完成的释放操作,则在调用 cuMemPoolDestroy 时,该函数将立即返回,并且一旦没有更多未完成的分配,则与池关联的资源将自动释放。
销毁设备的当前内存池会设置该设备的默认内存池作为当前内存池。
注意设备的默认内存池无法销毁。
另请参阅
cuMemFreeAsync, cuDeviceSetMemPool, cuDeviceGetMemPool, cuDeviceGetDefaultMemPool, cuMemPoolCreate
- CUresult cuMemPoolExportPointer ( CUmemPoolPtrExportData* shareData_out, CUdeviceptr ptr )
-
导出数据以在进程之间共享内存池分配。
参数
- shareData_out
- - 返回的导出数据
- ptr
- - 指向正在导出的内存的指针
描述
构造函数shareData_out用于从已共享的内存池中共享特定的分配。接收进程可以使用 cuMemPoolImportPointer API 导入分配。数据不是句柄,可以通过任何 IPC 机制共享。
另请参阅
cuMemPoolExportToShareableHandle, cuMemPoolImportFromShareableHandle, cuMemPoolImportPointer
- CUresult cuMemPoolExportToShareableHandle ( void* handle_out, CUmemoryPool pool, CUmemAllocationHandleType handleType, unsigned long long flags )
-
将内存池导出到请求的句柄类型。
参数
- handle_out
- - 返回的操作系统句柄
- pool
- - 要导出的内存池
- handleType
- - 要创建的句柄类型
- flags
- - 必须为 0
描述
给定一个支持 IPC 的内存池,创建一个操作系统句柄以与另一个进程共享该内存池。接收进程可以使用 cuMemPoolImportFromShareableHandle 将可共享句柄转换为内存池。然后可以使用 cuMemPoolExportPointer 和 cuMemPoolImportPointer API 共享各个指针。可共享句柄是什么以及如何传输它的实现由请求的句柄类型定义。
注意: 要创建支持 IPC 的内存池,请使用 CUmemAllocationHandleType 创建内存池,而不是 CU_MEM_HANDLE_TYPE_NONE。
另请参阅
cuMemPoolImportFromShareableHandle, cuMemPoolExportPointer, cuMemPoolImportPointer, cuMemAllocAsync, cuMemFreeAsync, cuDeviceGetDefaultMemPool, cuDeviceGetMemPool, cuMemPoolCreate, cuMemPoolSetAccess, cuMemPoolSetAttribute
- CUresult cuMemPoolGetAccess ( CUmemAccess_flags* flags, CUmemoryPool memPool, CUmemLocation* location )
-
返回设备访问内存池的可访问性。
参数
- flags
- - 从指定位置访问内存池的可访问性
- memPool
- - 要查询的内存池
- location
- - 访问内存池的位置
描述
返回从指定位置访问内存池内存的可访问性。
另请参阅
cuMemAllocAsync, cuMemFreeAsync, cuDeviceGetDefaultMemPool, cuDeviceGetMemPool, cuMemPoolCreate
- CUresult cuMemPoolGetAttribute ( CUmemoryPool pool, CUmemPool_attribute attr, void* value )
-
获取内存池的属性。
参数
- pool
- - 要获取属性的内存池
- attr
- - 要获取的属性
- value
- - 检索到的值
描述
支持的属性有
-
CU_MEMPOOL_ATTR_RELEASE_THRESHOLD: (value type = cuuint64_t) 在尝试将内存释放回操作系统之前,要保留的字节为单位的预留内存量。当内存池持有的内存超过释放阈值字节时,分配器将在下次调用流、事件或上下文同步时尝试将内存释放回操作系统。(默认值 0)
-
CU_MEMPOOL_ATTR_REUSE_FOLLOW_EVENT_DEPENDENCIES: (value type = int) 允许 cuMemAllocAsync 使用在另一个流中异步释放的内存,只要分配流对释放操作存在流排序依赖性。Cuda 事件和空流交互可以创建所需的流排序依赖性。(默认启用)
-
CU_MEMPOOL_ATTR_REUSE_ALLOW_OPPORTUNISTIC: (value type = int) 当释放和分配之间没有依赖关系时,允许重用已完成的释放。(默认启用)
-
CU_MEMPOOL_ATTR_REUSE_ALLOW_INTERNAL_DEPENDENCIES: (value type = int) 允许 cuMemAllocAsync 插入新的流依赖关系,以便建立重用由 cuMemFreeAsync 释放的内存块所需的流排序(默认启用)。
-
CU_MEMPOOL_ATTR_RESERVED_MEM_CURRENT: (value type = cuuint64_t) 当前为内存池分配的后备内存量
-
CU_MEMPOOL_ATTR_RESERVED_MEM_HIGH: (value type = cuuint64_t) 自上次重置以来为内存池分配的后备内存的最高水位线。
-
CU_MEMPOOL_ATTR_USED_MEM_CURRENT: (value type = cuuint64_t) 应用程序当前正在使用的池中的内存量。
-
CU_MEMPOOL_ATTR_USED_MEM_HIGH: (value type = cuuint64_t) 应用程序已使用的池中内存量的最高水位线。
另请参阅
cuMemAllocAsync, cuMemFreeAsync, cuDeviceGetDefaultMemPool, cuDeviceGetMemPool, cuMemPoolCreate
- CUresult cuMemPoolImportFromShareableHandle ( CUmemoryPool* pool_out, void* handle, CUmemAllocationHandleType handleType, unsigned long long flags )
-
从共享句柄导入内存池。
参数
- pool_out
- - 返回的内存池
- handle
- - 要打开的内存池的操作系统句柄
- handleType
- - 要导入的句柄类型
- flags
- - 必须为 0
描述
可以使用 cuMemPoolImportPointer 从导入的池中导入特定的分配。
如果handleType为 CU_MEM_HANDLE_TYPE_FABRIC 且导入器进程未被授予与导出器进程相同的 IMEX 通道的访问权限,则此 API 将报错 CUDA_ERROR_NOT_PERMITTED。
注意导入的内存池不支持创建新的分配。因此,导入的内存池可能不用于 cuDeviceSetMemPool 或 cuMemAllocFromPoolAsync 调用。
另请参阅
cuMemPoolExportToShareableHandle, cuMemPoolExportPointer, cuMemPoolImportPointer
- CUresult cuMemPoolImportPointer ( CUdeviceptr* ptr_out, CUmemoryPool pool, CUmemPoolPtrExportData* shareData )
-
从另一个进程导入内存池分配。
参数
- ptr_out
- - 指向导入内存的指针
- pool
- - 要从中导入的内存池
- shareData
- - 指定要导入的内存的数据
描述
在ptr_out中返回指向导入内存的指针。在导出进程中的分配操作完成之前,不得访问导入的内存。导入的内存必须在导出进程中释放之前从所有导入进程中释放。指针可以使用 cuMemFree 或 cuMemFreeAsync 释放。如果使用 cuMemFreeAsync,则释放必须在导入进程中完成,然后才能在导出进程中进行释放操作。
注意只要导出进程中的 cuMemFreeAsync 指定的流与导入进程的 cuMemFreeAsync 具有流依赖性,就可以在导出进程中使用 cuMemFreeAsync API,而无需等待其流中的 cuMemFreeAsync 操作完成。
另请参阅
cuMemPoolExportToShareableHandle, cuMemPoolImportFromShareableHandle, cuMemPoolExportPointer
- CUresult cuMemPoolSetAccess ( CUmemoryPool pool, const CUmemAccessDesc* map, size_t count )
-
控制设备之间内存池的可见性。
参数
- pool
- - 要修改的内存池
- map
- - 访问描述符数组。每个描述符指示为单个 gpu 启用的访问权限。
- count
- - map 数组中描述符的数量。
- CUresult cuMemPoolSetAttribute ( CUmemoryPool pool, CUmemPool_attribute attr, void* value )
-
设置内存池的属性。
参数
- pool
- - 要修改的内存池
- attr
- - 要修改的属性
- value
- - 指向要分配的值的指针
描述
支持的属性有
-
CU_MEMPOOL_ATTR_RELEASE_THRESHOLD: (value type = cuuint64_t) 在尝试将内存释放回操作系统之前,要保留的字节为单位的预留内存量。当内存池持有的内存超过释放阈值字节时,分配器将在下次调用流、事件或上下文同步时尝试将内存释放回操作系统。(默认值 0)
-
CU_MEMPOOL_ATTR_REUSE_FOLLOW_EVENT_DEPENDENCIES: (value type = int) 允许 cuMemAllocAsync 使用在另一个流中异步释放的内存,只要分配流对释放操作存在流排序依赖性。Cuda 事件和空流交互可以创建所需的流排序依赖性。(默认启用)
-
CU_MEMPOOL_ATTR_REUSE_ALLOW_OPPORTUNISTIC: (value type = int) 当释放和分配之间没有依赖关系时,允许重用已完成的释放。(默认启用)
-
CU_MEMPOOL_ATTR_REUSE_ALLOW_INTERNAL_DEPENDENCIES: (value type = int) 允许 cuMemAllocAsync 插入新的流依赖关系,以便建立重用由 cuMemFreeAsync 释放的内存块所需的流排序(默认启用)。
-
CU_MEMPOOL_ATTR_RESERVED_MEM_HIGH: (value type = cuuint64_t) 重置跟踪为内存池分配的后备内存量的最高水位线。将此属性设置为非零值是非法的。
-
CU_MEMPOOL_ATTR_USED_MEM_HIGH: (value type = cuuint64_t) 重置跟踪为内存池分配的已用内存量的最高水位线。
另请参阅
cuMemAllocAsync, cuMemFreeAsync, cuDeviceGetDefaultMemPool, cuDeviceGetMemPool, cuMemPoolCreate
- CUresult cuMemPoolTrimTo ( CUmemoryPool pool, size_t minBytesToKeep )
-
尝试将内存释放回操作系统。
参数
- pool
- - 要修剪的内存池
- minBytesToKeep
- - 如果池的预留字节数少于 minBytesToKeep,则 TrimTo 操作无效。否则,操作后将保证池至少保留 minBytesToKeep 字节。
描述
将内存释放回操作系统,直到池包含少于 minBytesToKeep 预留字节,或者分配器无法安全释放更多内存为止。分配器无法释放支持未完成的异步分配的操作系统分配。操作系统分配可能以与用户分配不同的粒度发生。
注意-
: 尚未释放的分配计为未完成。
-
: 已异步释放但其完成尚未在主机上观察到的分配(例如,通过同步)可以计为未完成。
另请参阅
cuMemAllocAsync, cuMemFreeAsync, cuDeviceGetDefaultMemPool, cuDeviceGetMemPool, cuMemPoolCreate