6.17. 统一寻址
本节介绍底层 CUDA 驱动程序应用程序编程接口的统一寻址功能。
概述
CUDA 设备可以与主机共享统一的地址空间。对于这些设备,设备指针和主机指针之间没有区别 -- 相同的指针值可以用于从主机程序和设备上运行的内核访问内存(以下列出的例外情况除外)。
支持的平台
设备是否支持统一寻址可以通过调用 cuDeviceGetAttribute() 并使用设备属性 CU_DEVICE_ATTRIBUTE_UNIFIED_ADDRESSING 来查询。
统一寻址在 64 位进程中自动启用
从指针值查找信息
可以查找支持指针值的内存信息。例如,可能想知道指针是否指向主机内存或设备内存。再例如,在设备内存的情况下,可能想知道内存驻留在哪个 CUDA 设备上。这些属性可以使用函数 cuPointerGetAttribute() 查询。
由于指针是唯一的,因此无需指定 CUDA API 中各种复制函数指定的指针信息。函数 cuMemcpy() 可用于在两个指针之间执行复制,忽略它们是指向主机内存还是设备内存(对于支持统一寻址的设备,cuMemcpyHtoD()、cuMemcpyDtoD() 和 cuMemcpyDtoH() 变得不必要)。对于多维复制,内存类型 CU_MEMORYTYPE_UNIFIED 可用于指定 CUDA 驱动程序应从指针值推断指针的位置。
自动映射主机分配的主机内存
使用 cuMemAllocHost() 和 cuMemHostAlloc() 在所有上下文中分配的所有主机内存始终可以直接从支持统一寻址的所有设备上的所有上下文访问。无论是否指定标志 CU_MEMHOSTALLOC_PORTABLE 和 CU_MEMHOSTALLOC_DEVICEMAP,情况都是如此。
在支持统一寻址的所有设备上,内核可以通过其访问已分配主机内存的指针值与主机访问该内存的指针值相同,因此无需调用 cuMemHostGetDevicePointer() 来获取这些分配的设备指针。
请注意,对于使用标志 CU_MEMHOSTALLOC_WRITECOMBINED 分配的内存,情况并非如此,如下所述。
自动注册对等内存
在使用 cuCtxEnablePeerAccess() 从支持统一寻址的上下文启用对另一个支持统一寻址的对等上下文的直接访问后,使用 cuMemAlloc() 和 cuMemAllocPitch() 在对等上下文中分配的所有内存将立即被当前上下文访问。当前上下文中可以访问任何对等内存的设备指针值与对等上下文中可以访问该内存的指针值相同。
例外情况,不相交寻址
并非所有内存都可以通过与主机访问时相同的指针值在设备上访问。这些例外情况是使用 cuMemHostRegister() 注册的主机内存和使用标志 CU_MEMHOSTALLOC_WRITECOMBINED 分配的主机内存。对于这些例外情况,内存存在不同的主机地址和设备地址。设备地址保证不与任何有效的主机指针范围重叠,并保证在所有支持统一寻址的上下文中具有相同的值。
当使用统一寻址的上下文为当前上下文时,可以使用 cuMemHostGetDevicePointer() 查询此设备地址。主机或统一设备指针值都可以用于通过 cuMemcpy() 和使用 CU_MEMORYTYPE_UNIFIED 内存类型的类似函数来引用此内存。
函数
- CUresult cuMemAdvise ( CUdeviceptr devPtr, size_t count, CUmem_advise advice, CUdevice device )
- 建议给定内存范围的用法。
- CUresult cuMemAdvise_v2 ( CUdeviceptr devPtr, size_t count, CUmem_advise advice, CUmemLocation location )
- 建议给定内存范围的用法。
- CUresult cuMemPrefetchAsync ( CUdeviceptr devPtr, size_t count, CUdevice dstDevice, CUstream hStream )
- 将内存预取到指定的目的地设备。
- CUresult cuMemPrefetchAsync_v2 ( CUdeviceptr devPtr, size_t count, CUmemLocation location, unsigned int flags, CUstream hStream )
- 将内存预取到指定的目的地位置。
- CUresult cuMemRangeGetAttribute ( void* data, size_t dataSize, CUmem_range_attribute attribute, CUdeviceptr devPtr, size_t count )
- 查询给定内存范围的属性。
- CUresult cuMemRangeGetAttributes ( void** data, size_t* dataSizes, CUmem_range_attribute* attributes, size_t numAttributes, CUdeviceptr devPtr, size_t count )
- 查询给定内存范围的属性。
- CUresult cuPointerGetAttribute ( void* data, CUpointer_attribute attribute, CUdeviceptr ptr )
- 返回有关指针的信息。
- CUresult cuPointerGetAttributes ( unsigned int numAttributes, CUpointer_attribute* attributes, void** data, CUdeviceptr ptr )
- 返回有关指针的信息。
- CUresult cuPointerSetAttribute ( const void* value, CUpointer_attribute attribute, CUdeviceptr ptr )
- 在先前分配的内存区域上设置属性。
函数
- CUresult cuMemAdvise ( CUdeviceptr devPtr, size_t count, CUmem_advise advice, CUdevice device )
-
建议给定内存范围的用法。
参数
- devPtr
- - 指向要设置建议的内存的指针
- count
- - 内存范围的大小(字节)
- advice
- - 要应用于指定内存范围的建议
- device
- - 要应用建议的设备
描述
注意:此 API 有一个更新的版本,cuMemAdvise_v2。它将在 13.0 版本中取代此版本,此版本为了次要版本兼容性而保留。
向统一内存子系统建议从以下位置开始的内存范围的用法模式devPtr大小为count字节。在应用建议之前,内存范围的起始地址和结束地址将分别向下和向上舍入以与 CPU 页面大小对齐。内存范围必须引用通过 cuMemAllocManaged 分配或通过 __managed__ 变量声明的托管内存。内存范围也可以引用系统分配的可分页内存,前提是它代表有效的、主机可访问的内存区域以及以下施加的所有其他约束advice如下所述也得到满足。指定无效的系统分配的可分页内存范围会导致返回错误。
Theadvice参数可以采用以下值
-
CU_MEM_ADVISE_SET_READ_MOSTLY:这表示数据主要将被读取,仅偶尔写入。任何处理器对该区域的任何读取访问都将在该处理器的内存中创建至少访问页面的只读副本。此外,如果在此区域调用 cuMemPrefetchAsync,它将在目标处理器上创建数据的只读副本。如果任何处理器写入此区域,则除了发生写入的页面之外,相应页面的所有副本都将失效。Thedevice参数在此建议中被忽略。请注意,为了使页面被读取重复,访问处理器必须是 CPU 或 GPU,其设备属性 CU_DEVICE_ATTRIBUTE_CONCURRENT_MANAGED_ACCESS 的值必须为非零。此外,如果在不具有设备属性 CU_DEVICE_ATTRIBUTE_CONCURRENT_MANAGED_ACCESS 集的设备上创建上下文,则在销毁所有此类上下文之前,不会发生读取重复。如果内存区域引用有效的系统分配的可分页内存,则访问设备必须具有设备属性 CU_DEVICE_ATTRIBUTE_PAGEABLE_MEMORY_ACCESS 的非零值,以便在该设备上创建只读副本。但是请注意,如果访问设备也具有设备属性 CU_DEVICE_ATTRIBUTE_PAGEABLE_MEMORY_ACCESS_USES_HOST_PAGE_TABLES 的非零值,则设置此建议不会在该设备访问此内存区域时创建只读副本。
-
CU_MEM_ADVISE_UNSET_READ_MOSTLY:撤消 CU_MEM_ADVISE_SET_READ_MOSTLY 的效果,并阻止统一内存驱动程序尝试对内存范围进行启发式读取重复。数据的任何读取重复副本都将折叠为单个副本。如果页面具有首选位置,并且其中一个读取重复副本驻留在该位置,则折叠副本的位置将是首选位置。否则,选择的位置是任意的。
-
CU_MEM_ADVISE_SET_PREFERRED_LOCATION:此建议将数据的首选位置设置为属于以下设备的内存device。传入 CU_DEVICE_CPU 作为device将首选位置设置为主机内存。如果device是 GPU,则其设备属性 CU_DEVICE_ATTRIBUTE_CONCURRENT_MANAGED_ACCESS 的值必须为非零。设置首选位置不会导致数据立即迁移到该位置。相反,它会在该内存区域发生故障时指导迁移策略。如果数据已在其首选位置,并且故障处理器可以建立映射而无需迁移数据,则将避免数据迁移。另一方面,如果数据不在其首选位置,或者无法建立直接映射,则数据将被迁移到访问它的处理器。重要的是要注意,设置首选位置不会阻止使用 cuMemPrefetchAsync 完成的数据预取。具有首选位置可以覆盖统一内存驱动程序中的页面抖动检测和解决逻辑。通常,如果检测到页面在例如主机内存和设备内存之间不断抖动,则页面最终可能会被统一内存驱动程序固定到主机内存。但是,如果首选位置设置为设备内存,则页面将继续无限期地抖动。如果 CU_MEM_ADVISE_SET_READ_MOSTLY 也在此内存区域或其任何子集上设置,则与该建议关联的策略将覆盖此建议的策略,除非来自以下的读取访问device如建议 CU_MEM_ADVISE_SET_READ_MOSTLY 的描述中所述,不会导致在该设备上创建只读副本。如果内存区域引用有效的系统分配的可分页内存,则device的设备属性 CU_DEVICE_ATTRIBUTE_PAGEABLE_MEMORY_ACCESS 的值必须为非零。
-
CU_MEM_ADVISE_UNSET_PREFERRED_LOCATION:撤消 CU_MEM_ADVISE_SET_PREFERRED_LOCATION 的效果,并将首选位置更改为无。
-
CU_MEM_ADVISE_SET_ACCESSED_BY:此建议表示数据将由以下设备访问device。传入 CU_DEVICE_CPU 作为device将为 CPU 设置建议。如果device是 GPU,则设备属性 CU_DEVICE_ATTRIBUTE_CONCURRENT_MANAGED_ACCESS 的值必须为非零。此建议不会导致数据迁移,并且本身对数据的位置没有影响。相反,它会导致数据始终映射到指定处理器的页表中,只要数据的位置允许建立映射即可。如果数据由于任何原因被迁移,则映射会相应更新。在数据局部性不重要但避免故障很重要的场景中,建议使用此建议。例如,考虑一个包含多个启用对等访问的 GPU 的系统,其中位于一个 GPU 上的数据偶尔会被对等 GPU 访问。在这种情况下,将数据迁移到其他 GPU 并不那么重要,因为访问不频繁,并且迁移的开销可能太高。但是,防止故障仍然可以帮助提高性能,因此预先设置映射是有用的。请注意,在 CPU 访问此数据时,数据可能会迁移到主机内存,因为 CPU 通常无法直接访问设备内存。任何为该数据设置了 CU_MEM_ADVISE_SET_ACCESSED_BY 标志的 GPU 现在将更新其映射以指向主机内存中的页面。如果 CU_MEM_ADVISE_SET_READ_MOSTLY 也在此内存区域或其任何子集上设置,则与该建议关联的策略将覆盖此建议的策略。此外,如果此内存区域或其任何子集的首选位置也是device,则与 CU_MEM_ADVISE_SET_PREFERRED_LOCATION 关联的策略将覆盖此建议的策略。如果内存区域引用有效的系统分配的可分页内存,则device的设备属性 CU_DEVICE_ATTRIBUTE_PAGEABLE_MEMORY_ACCESS 的值必须为非零。此外,如果device的设备属性 CU_DEVICE_ATTRIBUTE_PAGEABLE_MEMORY_ACCESS_USES_HOST_PAGE_TABLES 的值为非零,则此调用无效。
-
CU_MEM_ADVISE_UNSET_ACCESSED_BY:撤消 CU_MEM_ADVISE_SET_ACCESSED_BY 的效果。来自以下的任何数据映射device可能随时删除,导致访问导致非致命页面错误。如果内存区域引用有效的系统分配的可分页内存,则device的设备属性 CU_DEVICE_ATTRIBUTE_PAGEABLE_MEMORY_ACCESS 的值必须为非零。此外,如果device的设备属性 CU_DEVICE_ATTRIBUTE_PAGEABLE_MEMORY_ACCESS_USES_HOST_PAGE_TABLES 的值为非零,则此调用无效。
另请参阅
cuMemcpy, cuMemcpyPeer, cuMemcpyAsync, cuMemcpy3DPeerAsync, cuMemPrefetchAsync, cuMemAdvise_v2cudaMemAdvise
- CUresult cuMemAdvise_v2 ( CUdeviceptr devPtr, size_t count, CUmem_advise advice, CUmemLocation location )
-
建议给定内存范围的用法。
参数
- devPtr
- - 指向要设置建议的内存的指针
- count
- - 内存范围的大小(字节)
- advice
- - 要应用于指定内存范围的建议
- location
- - 要应用建议的位置
描述
向统一内存子系统建议从以下位置开始的内存范围的用法模式devPtr大小为count字节。在应用建议之前,内存范围的起始地址和结束地址将分别向下和向上舍入以与 CPU 页面大小对齐。内存范围必须引用通过 cuMemAllocManaged 分配或通过 __managed__ 变量声明的托管内存。内存范围也可以引用系统分配的可分页内存,前提是它代表有效的、主机可访问的内存区域以及以下施加的所有其他约束advice如下所述也得到满足。指定无效的系统分配的可分页内存范围会导致返回错误。
Theadvice参数可以采用以下值
-
CU_MEM_ADVISE_SET_READ_MOSTLY:这表示数据主要用于读取,仅偶尔写入。任何处理器对该区域的读取访问都将至少在该处理器内存中创建被访问页面的只读副本。此外,如果在该区域上调用 cuMemPrefetchAsync 或 cuMemPrefetchAsync_v2,它将在目标处理器上创建数据的只读副本。如果 cuMemPrefetchAsync_v2 的目标位置是主机 NUMA 节点,并且另一个主机 NUMA 节点上已存在只读副本,则该副本将被迁移到目标主机 NUMA 节点。如果任何处理器写入此区域,则除了写入发生的页面之外,所有相应页面的副本都将失效。如果写入处理器是 CPU,并且页面的首选位置是主机 NUMA 节点,则页面也将迁移到该主机 NUMA 节点。该location参数在此建议中被忽略。请注意,为了使页面被读取重复,访问处理器必须是 CPU 或 GPU,其设备属性 CU_DEVICE_ATTRIBUTE_CONCURRENT_MANAGED_ACCESS 的值必须为非零。此外,如果在不具有设备属性 CU_DEVICE_ATTRIBUTE_CONCURRENT_MANAGED_ACCESS 集的设备上创建上下文,则在销毁所有此类上下文之前,不会发生读取重复。如果内存区域引用有效的系统分配的可分页内存,则访问设备必须具有设备属性 CU_DEVICE_ATTRIBUTE_PAGEABLE_MEMORY_ACCESS 的非零值,以便在该设备上创建只读副本。但是请注意,如果访问设备也具有设备属性 CU_DEVICE_ATTRIBUTE_PAGEABLE_MEMORY_ACCESS_USES_HOST_PAGE_TABLES 的非零值,则设置此建议不会在该设备访问此内存区域时创建只读副本。
-
CU_MEM_ADVISE_UNSET_READ_MOSTLY:撤销 CU_MEM_ADVISE_SET_READ_MOSTLY 的效果,并阻止统一内存驱动程序尝试对内存范围进行启发式读取复制。数据的任何读取重复副本都将被折叠为单个副本。如果页面具有首选位置,并且其中一个读取重复副本驻留在该位置,则折叠副本的位置将是首选位置。否则,选择的位置是任意的。注意:location此建议忽略参数。
-
CU_MEM_ADVISE_SET_PREFERRED_LOCATION:此建议将数据的首选位置设置为属于以下设备的内存location。当 CUmemLocation::type 为 CU_MEM_LOCATION_TYPE_HOST 时,CUmemLocation::id 将被忽略,并且首选位置将设置为主机内存。要将首选位置设置为特定的主机 NUMA 节点,应用程序必须将 CUmemLocation::type 设置为 CU_MEM_LOCATION_TYPE_HOST_NUMA,并且 CUmemLocation::id 必须指定主机 NUMA 节点的 NUMA ID。如果 CUmemLocation::type 设置为 CU_MEM_LOCATION_TYPE_HOST_NUMA_CURRENT,则 CUmemLocation::id 将被忽略,并且最接近调用线程 CPU 的主机 NUMA 节点将用作首选位置。如果 CUmemLocation::type 是 CU_MEM_LOCATION_TYPE_DEVICE,则 CUmemLocation::id 必须是有效的设备序号,并且该设备必须具有设备属性 CU_DEVICE_ATTRIBUTE_CONCURRENT_MANAGED_ACCESS 的非零值。设置首选位置不会导致数据立即迁移到该位置。相反,当在该内存区域上发生错误时,它会指导迁移策略。如果数据已在其首选位置,并且发生错误的处理器可以建立映射而无需迁移数据,则将避免数据迁移。另一方面,如果数据不在其首选位置,或者无法建立直接映射,则数据将被迁移到访问它的处理器。重要的是要注意,设置首选位置不会阻止使用 cuMemPrefetchAsync 完成的数据预取。拥有首选位置可以覆盖统一内存驱动程序中的页面抖动检测和解决逻辑。通常,如果检测到页面在主机内存和设备内存之间不断抖动,则统一内存驱动程序最终可能会将页面固定到主机内存。但是,如果首选位置设置为设备内存,则页面将继续无限期地抖动。如果 CU_MEM_ADVISE_SET_READ_MOSTLY 也在此内存区域或其任何子集上设置,则与该建议关联的策略将覆盖此建议的策略,除非来自location将不会导致在该处理器上创建只读副本,如建议 CU_MEM_ADVISE_SET_READ_MOSTLY 的描述中所述。如果内存区域引用有效的系统分配的可分页内存,并且 CUmemLocation::type 是 CU_MEM_LOCATION_TYPE_DEVICE,则 CUmemLocation::id 必须是具有设备属性 CU_DEVICE_ATTRIBUTE_PAGEABLE_MEMORY_ACCESS 的非零值的有效设备。
-
CU_MEM_ADVISE_UNSET_PREFERRED_LOCATION:撤销 CU_MEM_ADVISE_SET_PREFERRED_LOCATION 的效果,并将首选位置更改为无。该location此建议忽略参数。
-
CU_MEM_ADVISE_SET_ACCESSED_BY:此建议表示数据将由处理器访问location。CUmemLocation::type 必须是 CU_MEM_LOCATION_TYPE_DEVICE,其中 CUmemLocation::id 表示有效的设备序号,或者 CU_MEM_LOCATION_TYPE_HOST,并且 CUmemLocation::id 将被忽略。所有其他位置类型均无效。如果 CUmemLocation::id 是 GPU,则设备属性 CU_DEVICE_ATTRIBUTE_CONCURRENT_MANAGED_ACCESS 必须为非零。此建议不会导致数据迁移,并且对数据的位置本身没有影响。相反,它导致数据始终映射到指定处理器的页表中,只要数据的位置允许建立映射即可。如果数据由于任何原因迁移,映射也会相应更新。在数据局部性不重要但要避免错误的情况下,建议使用此建议。例如,考虑一个包含启用对等访问的多个 GPU 的系统,其中位于一个 GPU 上的数据偶尔会被对等 GPU 访问。在这种情况下,将数据迁移到其他 GPU 并不那么重要,因为访问不频繁,并且迁移的开销可能太高。但是,防止错误仍然可以帮助提高性能,因此预先设置映射是有用的。请注意,在 CPU 访问此数据时,数据可能会迁移到主机内存,因为 CPU 通常无法直接访问设备内存。任何为此数据设置了 CU_MEM_ADVISE_SET_ACCESSED_BY 标志的 GPU 现在都将更新其映射以指向主机内存中的页面。如果 CU_MEM_ADVISE_SET_READ_MOSTLY 也在此内存区域或其任何子集上设置,则与该建议关联的策略将覆盖此建议的策略。此外,如果此内存区域或其任何子集的首选位置也是location,则与 CU_MEM_ADVISE_SET_PREFERRED_LOCATION 关联的策略将覆盖此建议的策略。如果内存区域引用有效的系统分配的可分页内存,并且 CUmemLocation::type 是 CU_MEM_LOCATION_TYPE_DEVICE,则 CUmemLocation::id 中的设备必须具有设备属性 CU_DEVICE_ATTRIBUTE_PAGEABLE_MEMORY_ACCESS 的非零值。此外,如果 CUmemLocation::id 具有设备属性 CU_DEVICE_ATTRIBUTE_PAGEABLE_MEMORY_ACCESS_USES_HOST_PAGE_TABLES 的非零值,则此调用无效。
-
CU_MEM_ADVISE_UNSET_ACCESSED_BY:撤消 CU_MEM_ADVISE_SET_ACCESSED_BY 的效果。来自以下的任何数据映射location可能会在任何时候删除,导致访问导致非致命页面错误。如果内存区域引用有效的系统分配的可分页内存,并且 CUmemLocation::type 是 CU_MEM_LOCATION_TYPE_DEVICE,则 CUmemLocation::id 中的设备必须具有设备属性 CU_DEVICE_ATTRIBUTE_PAGEABLE_MEMORY_ACCESS 的非零值。此外,如果 CUmemLocation::id 具有设备属性 CU_DEVICE_ATTRIBUTE_PAGEABLE_MEMORY_ACCESS_USES_HOST_PAGE_TABLES 的非零值,则此调用无效。
另请参阅
cuMemcpy、cuMemcpyPeer、cuMemcpyAsync、cuMemcpy3DPeerAsync、cuMemPrefetchAsync、cuMemAdvisecudaMemAdvise
- CUresult cuMemPrefetchAsync ( CUdeviceptr devPtr, size_t count, CUdevice dstDevice, CUstream hStream )
-
将内存预取到指定的目标设备。
参数
- devPtr
- - 要预取的指针
- count
- - 字节大小
- dstDevice
- - 要预取到的目标设备
- hStream
- - 将预取操作排队的流
描述
请注意,此 API 有一个较新的版本,即 cuMemPrefetchAsync_v2。它将在 13.0 版本中取代此版本,此版本保留是为了实现次要版本兼容性。
将内存预取到指定的目标设备。devPtr是要预取的内存的基本设备指针,而dstDevice是目标设备。count指定要复制的字节数。hStream是将操作排队的流。内存范围必须引用通过 cuMemAllocManaged 分配或通过 __managed__ 变量声明的托管内存,或者它也可以引用 CU_DEVICE_ATTRIBUTE_PAGEABLE_MEMORY_ACCESS 为非零的系统上的系统分配内存。
为dstDevice传入 CU_DEVICE_CPU 将把数据预取到主机内存。如果dstDevice是 GPU,则设备属性 CU_DEVICE_ATTRIBUTE_CONCURRENT_MANAGED_ACCESS 必须为非零。此外,hStream必须与具有设备属性 CU_DEVICE_ATTRIBUTE_CONCURRENT_MANAGED_ACCESS 的非零值的设备关联。
在预取操作排入流之前,内存范围的起始地址和结束地址将分别向下和向上舍入,以与 CPU 页面大小对齐。
如果此区域尚未分配物理内存,则将在此目标设备上填充和映射此内存区域。如果内存不足以预取所需的区域,则统一内存驱动程序可能会从其他 cuMemAllocManaged 分配中逐出页面到主机内存,以便腾出空间。使用 cuMemAlloc 或 cuArrayCreate 分配的设备内存不会被逐出。
默认情况下,将删除到迁移页面的先前位置的任何映射,并且仅在dstDevice上设置新位置的映射。但是,确切的行为还取决于通过 cuMemAdvise 应用于此内存范围的设置,如下所述
如果在该内存范围的任何子集上设置了 CU_MEM_ADVISE_SET_READ_MOSTLY,则该子集将在dstDevice.
上创建页面的只读副本。如果在该内存范围的任何子集上调用了 CU_MEM_ADVISE_SET_PREFERRED_LOCATION,则页面将迁移到dstDevice,即使dstDevice不是内存范围中任何页面的首选位置。
如果在该内存范围的任何子集上调用了 CU_MEM_ADVISE_SET_ACCESSED_BY,则来自所有适当处理器的这些页面的映射都会更新,以引用新位置(如果可以建立此类映射)。否则,这些映射将被清除。
请注意,此 API 不是功能必需的,仅通过允许应用程序在访问数据之前将数据迁移到合适的位置来提高性能。对此范围的内存访问始终是连贯的,即使在数据正在主动迁移时也允许访问。
请注意,此函数相对于主机和所有其他设备上的工作是异步的。
另请参阅
cuMemcpy、cuMemcpyPeer、cuMemcpyAsync、cuMemcpy3DPeerAsync、cuMemAdvise、cuMemPrefetchAsynccudaMemPrefetchAsync_v2
- CUresult cuMemPrefetchAsync_v2 ( CUdeviceptr devPtr, size_t count, CUmemLocation location, unsigned int flags, CUstream hStream )
-
将内存预取到指定的目标位置。
参数
- devPtr
- - 要预取的指针
- count
- - 字节大小
- location
- flags
- - 供将来使用的标志,现在必须为零。
- hStream
- - 将预取操作排队的流
描述
将内存预取到指定的目标位置。devPtr是要预取的内存的基本设备指针,而location指定目标位置。count指定要复制的字节数。hStream是将操作排队的流。内存范围必须引用通过 cuMemAllocManaged 分配或通过 __managed__ 变量声明的托管内存。
为 CUmemLocation::type 指定 CU_MEM_LOCATION_TYPE_DEVICE 将把内存预取到设备序号 CUmemLocation::id 指定的 GPU,该 GPU 必须具有设备属性 CU_DEVICE_ATTRIBUTE_CONCURRENT_MANAGED_ACCESS 的非零值。此外,hStream必须与具有设备属性 CU_DEVICE_ATTRIBUTE_CONCURRENT_MANAGED_ACCESS 的非零值的设备关联。为 CUmemLocation::type 指定 CU_MEM_LOCATION_TYPE_HOST 作为 CUmemLocation::type 将把数据预取到主机内存。应用程序可以通过为 CUmemLocation::type 指定 CU_MEM_LOCATION_TYPE_HOST_NUMA 并为 CUmemLocation::id 指定有效的主机 NUMA 节点 ID,从而请求将内存预取到特定的主机 NUMA 节点。用户还可以通过为 CUmemLocation::type 指定 CU_MEM_LOCATION_TYPE_HOST_NUMA_CURRENT,从而请求将内存预取到最接近当前线程 CPU 的主机 NUMA 节点。请注意,当 CUmemLocation::type 为 CU_MEM_LOCATION_TYPE_HOST 或 CU_MEM_LOCATION_TYPE_HOST_NUMA_CURRENT 时,CUmemLocation::id 将被忽略。
在预取操作排入流之前,内存范围的起始地址和结束地址将分别向下和向上舍入,以与 CPU 页面大小对齐。
如果此区域尚未分配物理内存,则将在此目标设备上填充和映射此内存区域。如果内存不足以预取所需的区域,则统一内存驱动程序可能会从其他 cuMemAllocManaged 分配中逐出页面到主机内存,以便腾出空间。使用 cuMemAlloc 或 cuArrayCreate 分配的设备内存不会被逐出。
默认情况下,将删除到迁移页面的先前位置的任何映射,并且仅在目标位置上设置新位置的映射。但是,确切的行为还取决于通过 cuMemAdvise 应用于此内存范围的设置,如下所述
如果在该内存范围的任何子集上设置了 CU_MEM_ADVISE_SET_READ_MOSTLY,则该子集将在目标位置上创建页面的只读副本。但是,如果目标位置是主机 NUMA 节点,则该子集的任何已在另一个主机 NUMA 节点中的页面都将传输到目标位置。
上创建页面的只读副本。如果在该内存范围的任何子集上调用了 CU_MEM_ADVISE_SET_PREFERRED_LOCATION,则页面将迁移到location,即使location不是内存范围中任何页面的首选位置。
如果在该内存范围的任何子集上调用了 CU_MEM_ADVISE_SET_ACCESSED_BY,则来自所有适当处理器的这些页面的映射都会更新,以引用新位置(如果可以建立此类映射)。否则,这些映射将被清除。
请注意,此 API 不是功能必需的,仅通过允许应用程序在访问数据之前将数据迁移到合适的位置来提高性能。对此范围的内存访问始终是连贯的,即使在数据正在主动迁移时也允许访问。
请注意,此函数相对于主机和所有其他设备上的工作是异步的。
另请参阅
cuMemcpy、cuMemcpyPeer、cuMemcpyAsync、cuMemcpy3DPeerAsync、cuMemAdvise、cuMemPrefetchAsynccudaMemPrefetchAsync_v2
- CUresult cuMemRangeGetAttribute ( void* data, size_t dataSize, CUmem_range_attribute attribute, CUdeviceptr devPtr, size_t count )
-
查询给定内存范围的属性。
参数
- data
- - 指向内存位置的指针,每个属性查询的结果将写入到该位置。
- dataSize
- - 包含数据大小的数组
- attribute
- - 要查询的属性
- devPtr
- - 要查询的范围的开始
- count
- - 要查询的范围的大小
描述
查询有关从devPtr大小为count字节开始的内存范围的属性。内存范围必须引用通过 cuMemAllocManaged 分配或通过 __managed__ 变量声明的托管内存。
Theattribute参数可以采用以下值
-
CU_MEM_RANGE_ATTRIBUTE_READ_MOSTLY:如果指定此属性,data将被解释为 32 位整数,并且dataSize必须为 4。如果给定内存范围中的所有页面都启用了读取重复,则返回的结果为 1,否则为 0。
-
CU_MEM_RANGE_ATTRIBUTE_PREFERRED_LOCATION:如果指定此属性,data将被解释为 32 位整数,并且dataSize必须为 4。如果内存范围中的所有页面都将该 GPU 作为其首选位置,则返回的结果将是 GPU 设备 ID,如果内存范围中的所有页面都将 CPU 作为其首选位置,则返回的结果将是 CU_DEVICE_CPU,如果所有页面都没有相同的首选位置,或者某些页面根本没有首选位置,则返回的结果将是 CU_DEVICE_INVALID。请注意,查询时内存范围中页面的实际位置可能与首选位置不同。
-
CU_MEM_RANGE_ATTRIBUTE_ACCESSED_BY:如果指定此属性,data将被解释为 32 位整数数组,并且dataSize必须是非零的 4 的倍数。返回的结果将是已为整个内存范围设置 CU_MEM_ADVISE_SET_ACCESSED_BY 的设备 ID 列表。如果任何设备未为整个内存范围设置该建议,则将不包括该设备。如果data大于为该内存范围设置该建议的设备数量,则 CU_DEVICE_INVALID 将在提供的所有额外空间中返回。例如,如果dataSize为 12(即data有 3 个元素),并且只有设备 0 设置了该建议,则返回的结果将是 { 0, CU_DEVICE_INVALID, CU_DEVICE_INVALID }。如果data小于设置了该建议的设备数量,则只会返回尽可能多的设备,以适应数组。但是,不能保证将返回哪些特定设备。
-
CU_MEM_RANGE_ATTRIBUTE_LAST_PREFETCH_LOCATION:如果指定此属性,data将被解释为 32 位整数,并且dataSize必须为 4。返回的结果将是最后一次显式通过 cuMemPrefetchAsync 预取内存范围中所有页面的位置。这将是 GPU ID 或 CU_DEVICE_CPU,具体取决于预取的最后一个位置是 GPU 还是 CPU。如果内存范围中的任何页面从未显式预取,或者所有页面都未预取到同一位置,则将返回 CU_DEVICE_INVALID。请注意,这只是返回应用程序请求预取内存范围到的最后一个位置。它不指示到该位置的预取操作是否已完成甚至开始。
-
CU_MEM_RANGE_ATTRIBUTE_PREFERRED_LOCATION_TYPE:如果指定此属性,data将被解释为 CUmemLocationType,并且dataSize必须为 sizeof(CUmemLocationType)。如果内存范围中的所有页面都将同一 GPU 作为其首选位置,则返回的 CUmemLocationType 将为 CU_MEM_LOCATION_TYPE_DEVICE;如果内存范围中的所有页面都将 CPU 作为其首选位置,则 CUmemLocationType 将为 CU_MEM_LOCATION_TYPE_HOST;如果内存范围中的所有页面都将同一主机 NUMA 节点 ID 作为其首选位置,则为 CU_MEM_LOCATION_TYPE_HOST_NUMA;如果所有页面都没有相同的首选位置,或者某些页面根本没有首选位置,则为 CU_MEM_LOCATION_TYPE_INVALID。请注意,查询时内存范围中页面的实际位置类型可能与首选位置类型不同。
-
CU_MEM_RANGE_ATTRIBUTE_PREFERRED_LOCATION_ID:如果指定此属性,data将被解释为 32 位整数,并且dataSize必须为 4。如果同一地址范围的 CU_MEM_RANGE_ATTRIBUTE_PREFERRED_LOCATION_TYPE 查询返回 CU_MEM_LOCATION_TYPE_DEVICE,则它将是有效的设备序号;如果它返回 CU_MEM_LOCATION_TYPE_HOST_NUMA,则它将是有效的主机 NUMA 节点 ID;如果它返回任何其他位置类型,则应忽略该 ID。
-
-
CU_MEM_RANGE_ATTRIBUTE_LAST_PREFETCH_LOCATION_TYPE:如果指定此属性,data将被解释为 CUmemLocationType,并且dataSize必须为 sizeof(CUmemLocationType)。返回的结果将是最后一次显式通过 cuMemPrefetchAsync 预取内存范围中所有页面的位置。如果最后一个预取位置是 GPU,则返回的 CUmemLocationType 将为 CU_MEM_LOCATION_TYPE_DEVICE;如果最后一个预取位置是 CPU,则为 CU_MEM_LOCATION_TYPE_HOST;如果最后一个预取位置是特定的主机 NUMA 节点,则为 CU_MEM_LOCATION_TYPE_HOST_NUMA。如果内存范围中的任何页面从未显式预取,或者所有页面都未预取到同一位置,则 CUmemLocationType 将为 CU_MEM_LOCATION_TYPE_INVALID。请注意,这只是返回应用程序请求预取内存范围到的最后一个位置类型。它不指示到该位置的预取操作是否已完成甚至开始。
-
CU_MEM_RANGE_ATTRIBUTE_LAST_PREFETCH_LOCATION_ID:如果指定此属性,data将被解释为 32 位整数,并且dataSize必须为 4。如果同一地址范围的 CU_MEM_RANGE_ATTRIBUTE_LAST_PREFETCH_LOCATION_TYPE 查询返回 CU_MEM_LOCATION_TYPE_DEVICE,则它将是有效的设备序号;如果它返回 CU_MEM_LOCATION_TYPE_HOST_NUMA,则它将是有效的主机 NUMA 节点 ID;如果它返回任何其他位置类型,则应忽略该 ID。
-
另请参阅
cuMemRangeGetAttributes、cuMemPrefetchAsync、cuMemAdvise、cudaMemRangeGetAttribute
- CUresult cuMemRangeGetAttributes ( void** data, size_t* dataSizes, CUmem_range_attribute* attributes, size_t numAttributes, CUdeviceptr devPtr, size_t count )
-
查询给定内存范围的属性。
参数
- data
- - 一个二维数组,其中包含指向内存位置的指针,每个属性查询的结果将写入到该位置。
- dataSizes
- - 包含每个结果大小的数组
- attributes
- - 要查询的属性数组(numAttributes 和此数组中的属性数应匹配)
- numAttributes
- - 要查询的属性数
- devPtr
- - 要查询的范围的开始
- count
- - 要查询的范围的大小
返回值
CUDA_SUCCESS, CUDA_ERROR_DEINITIALIZED, CUDA_ERROR_INVALID_CONTEXT, CUDA_ERROR_INVALID_VALUE, CUDA_ERROR_INVALID_DEVICE
描述
查询起始于devPtr大小为count字节的内存范围的属性。内存范围必须引用通过 cuMemAllocManaged 分配或通过 __managed__ 变量声明的托管内存。attributes数组将被解释为具有numAttributes个条目。dataSizes数组也将被解释为具有numAttributes个条目。查询结果将存储在data.
下面给出了支持的属性列表。有关属性描述和限制,请参阅 cuMemRangeGetAttribute。
注意请注意,此函数也可能返回来自先前异步启动的错误代码。
另请参阅
cuMemRangeGetAttribute, cuMemAdvise, cuMemPrefetchAsync, cudaMemRangeGetAttributes
- CUresult cuPointerGetAttribute ( void* data, CUpointer_attribute attribute, CUdeviceptr ptr )
-
返回关于指针的信息。
参数
- data
- - 返回的指针属性值
- attribute
- - 要查询的指针属性
- ptr
- - 指针
返回值
CUDA_SUCCESS, CUDA_ERROR_DEINITIALIZED, CUDA_ERROR_NOT_INITIALIZED, CUDA_ERROR_INVALID_CONTEXT, CUDA_ERROR_INVALID_VALUE, CUDA_ERROR_INVALID_DEVICE
描述
支持的属性有
在*data中返回 CUcontext,其中ptr被分配或注册。data的类型必须是 CUcontext *。
如果ptr不是由使用统一虚拟寻址的 CUcontext 分配、映射或注册的,则返回 CUDA_ERROR_INVALID_VALUE。
在*data作为 CUmemorytype 枚举值的ptr寻址的物理内存类型。data的类型必须是 unsigned int。
如果ptr寻址设备内存,则*data设置为 CU_MEMORYTYPE_DEVICE。内存所在的特定 CUdevice 是 CUcontext 的 CUdevice,由 CU_POINTER_ATTRIBUTE_CONTEXT 属性返回。ptr.
如果ptr寻址主机内存,则*data设置为 CU_MEMORYTYPE_HOST。
如果ptr不是由使用统一虚拟寻址的 CUcontext 分配、映射或注册的,则返回 CUDA_ERROR_INVALID_VALUE。
如果当前的 CUcontext 不支持统一虚拟寻址,则返回 CUDA_ERROR_INVALID_CONTEXT。
在*data设备指针值,通过它可以从当前 CUcontext 中运行的内核访问ptr。data的类型必须是 CUdeviceptr *。
如果不存在设备指针值,通过它可以从当前 CUcontext 中运行的内核访问ptr,则返回 CUDA_ERROR_INVALID_VALUE。
如果没有当前的 CUcontext,则返回 CUDA_ERROR_INVALID_CONTEXT。
除了下面讨论的特殊的不相交寻址情况外,在*data中返回的值将等于输入值ptr.
在*data主机指针值,通过它可以被主机程序访问ptr。data的类型必须是 void **。如果不存在主机指针值,通过它可以被主机程序直接访问ptr,则返回 CUDA_ERROR_INVALID_VALUE。
除了下面讨论的特殊的不相交寻址情况外,在*data中返回的值将等于输入值ptr.
在*data两个令牌,用于 nv-p2p.h Linux 内核接口。data必须是 CUDA_POINTER_ATTRIBUTE_P2P_TOKENS 类型的结构体。
ptr必须是指向从 :cuMemAlloc() 获取的内存的指针。请注意,p2pToken 和 vaSpaceToken 仅在源分配的生命周期内有效。在相同地址的后续分配可能会返回完全不同的令牌。查询此属性具有设置属性 CU_POINTER_ATTRIBUTE_SYNC_MEMOPS 副作用,针对ptr指向的内存区域。
一个布尔属性,当设置时,确保在ptr指向的内存区域上启动的同步内存操作始终同步。有关同步内存操作何时可能表现出异步行为的更多信息,请参阅标题为“API 同步行为”的部分中的进一步文档。
在*data一个缓冲区 ID,保证在进程内是唯一的。data必须指向一个 unsigned long long。
ptr必须是指向从 CUDA 内存分配 API 获取的内存的指针。来自任何 CUDA 内存分配 API 的每个内存分配都将在进程生命周期内具有唯一的 ID。后续分配不会重用先前释放的分配中的 ID。ID 仅在单个进程内是唯一的。
在*data一个布尔值,指示指针是否指向托管内存。
如果ptr不是有效的 CUDA 指针,则返回 CUDA_ERROR_INVALID_VALUE。
在*data一个整数,表示内存分配或注册到的设备的设备序号。
在*data一个布尔值,指示此指针是否映射到适用于 cudaIpcGetMemHandle 的分配。
在*data设备指针引用的分配的起始地址ptr。请注意,这不一定是映射区域的地址,而是ptr引用的可映射地址范围的地址(例如,来自 cuMemAddressReserve)。
在*data设备指针引用的分配的大小ptr。请注意,这不一定是映射区域的大小,而是ptr引用的可映射地址范围的大小(例如,来自 cuMemAddressReserve)。要检索映射区域的大小,请参阅 cuMemGetAddressRange
在*data一个布尔值,指示此指针是否在映射到后备分配的有效地址范围内。
返回可以传递给 cuMemExportToShareableHandle 的分配的允许句柄类型的位掩码。
在*data从中获取分配的内存池的句柄。
在*data一个布尔值,指示指针是否指向能够用于硬件加速解压缩的内存。
请注意,对于统一虚拟地址空间中的大多数分配,用于访问分配的主机和设备指针将是相同的。此规则的例外情况是
-
使用 cuMemHostRegister 注册的用户内存
-
使用 cuMemHostAlloc 和 CU_MEMHOSTALLOC_WRITECOMBINED 标志分配的主机内存。对于这些类型的分配,将存在单独的、不相交的主机和设备地址用于访问分配。特别是
-
主机地址将对应于无效的未映射设备地址(如果从设备访问,将导致异常)
-
设备地址将对应于无效的未映射主机地址(如果从主机访问,将导致异常)。对于这些类型的分配,查询 CU_POINTER_ATTRIBUTE_HOST_POINTER 和 CU_POINTER_ATTRIBUTE_DEVICE_POINTER 可用于从任一地址检索主机和设备地址。
注意请注意,此函数也可能返回来自先前异步启动的错误代码。
另请参阅
cuPointerSetAttribute, cuMemAlloc, cuMemFree, cuMemAllocHost, cuMemFreeHost, cuMemHostAlloc, cuMemHostRegister, cuMemHostUnregister, cudaPointerGetAttributes
- CUresult cuPointerGetAttributes ( unsigned int numAttributes, CUpointer_attribute* attributes, void** data, CUdeviceptr ptr )
-
返回关于指针的信息。
参数
- numAttributes
- - 要查询的属性数
- attributes
- - 要查询的属性数组(numAttributes 和此数组中的属性数应匹配)
- data
- - 一个二维数组,其中包含指向内存位置的指针,每个属性查询的结果将写入到该位置。
- ptr
- - 要查询的指针
返回值
CUDA_SUCCESS, CUDA_ERROR_DEINITIALIZED, CUDA_ERROR_INVALID_CONTEXT, CUDA_ERROR_INVALID_VALUE, CUDA_ERROR_INVALID_DEVICE
描述
支持的属性有(有关属性描述和限制,请参阅 cuPointerGetAttribute)
与 cuPointerGetAttribute 不同,当ptr遇到的不是有效的 CUDA 指针时,此函数不会返回错误。相反,属性被分配默认的 NULL 值,并返回 CUDA_SUCCESS。
如果ptr不是由使用 UVA(统一虚拟寻址)的 CUcontext 分配、映射或注册的,则返回 CUDA_ERROR_INVALID_CONTEXT。
注意请注意,此函数也可能返回来自先前异步启动的错误代码。
另请参阅
cuPointerGetAttribute, cuPointerSetAttribute, cudaPointerGetAttributes
- CUresult cuPointerSetAttribute ( const void* value, CUpointer_attribute attribute, CUdeviceptr ptr )
-
在先前分配的内存区域上设置属性。
参数
- value
- - 指向包含要设置的值的内存的指针
- attribute
- - 要设置的指针属性
- ptr
- - 指向使用 CUDA 内存分配 API 分配的内存区域的指针
返回值
CUDA_SUCCESS, CUDA_ERROR_DEINITIALIZED, CUDA_ERROR_NOT_INITIALIZED, CUDA_ERROR_INVALID_CONTEXT, CUDA_ERROR_INVALID_VALUE, CUDA_ERROR_INVALID_DEVICE
描述
支持的属性有
一个布尔属性,可以设置为 (1) 或取消设置 (0)。当设置时,ptr指向的内存区域保证始终同步同步内存操作。如果在设置此属性时,有一些先前启动的同步内存操作正在挂起,则该函数将不会返回,直到这些内存操作完成。有关同步内存操作何时可能表现出异步行为的更多信息,请参阅标题为“API 同步行为”的部分中的进一步文档。value将被视为指向无符号整数的指针,要将此属性设置为该整数。
注意请注意,此函数也可能返回来自先前异步启动的错误代码。
另请参阅
cuPointerGetAttribute, cuPointerGetAttributes, cuMemAlloc, cuMemFree, cuMemAllocHost, cuMemFreeHost, cuMemHostAlloc, cuMemHostRegister, cuMemHostUnregister