据我们所知: http://en.wikipedia.org/wiki/iommu#advantages

外围记忆分页可以由 iommu. 。使用PCI-SIG PCIE地址转换服务(ATS)请求接口(PRI)扩展程序的外围设备可以检测并发出对内存管理器服务的需求。

enter image description here

但是,当我们将NVIDIA GPU与CUDA> = 5.0一起使用时,我们可以使用RDMA GPUDIRECT,并知道:

http://docs.nvidia.com/cuda/gpudirect-rdma/index.html#how-gpudirect-rdma-works

传统上,使用CPU的MMU将诸如条形窗口之类的资源映射到用户或内核地址空间,作为内存映射I/O(MMIO)地址。但是,因为 当前的操作系统没有足够的机制来交换驱动程序之间的MMIO区域, ,NVIDIA内核驱动程序导出功能以执行必要的地址翻译和映射。

http://docs.nvidia.com/cuda/gpudirect-rdma/index.html#supported-systems

GPudirect的RDMA当前依赖所有物理地址从PCI设备的角度出发。这使其与Iommus不兼容,因此必须禁用RDMA才能使Gpudirect工作。

如果我们将CPU-RAM分配并映射到UVA,如下所示:

#include <iostream>
#include "cuda_runtime.h"
#include "device_launch_parameters.h"

int main() {
    // Can Host map memory
    cudaSetDeviceFlags(cudaDeviceMapHost);  

    // Allocate memory
    unsigned char *host_src_ptr = NULL;
    cudaHostAlloc(&host_src_ptr, 1024*1024, cudaHostAllocMapped);
    std::cout << "host_src_ptr = " << (size_t)host_src_ptr << std::endl;

    // Get UVA-pointer
    unsigned int *uva_src_ptr = NULL;
    cudaHostGetDevicePointer(&uva_src_ptr, host_src_ptr, 0);
    std::cout << "uva_src_ptr  = " << (size_t)uva_src_ptr << std::endl;

    int b;  std::cin >> b;
    return 0;
}

我们在Windwos7x64中获得平等的指针,这意味着 cudaHostGetDevicePointer() 没做什么:

host_src_ptr = 68719476736

UVA_SRC_PTR = 68719476736

这是什么意思是“足够的机制来交换驱动程序之间的MMIO区域”,这里是什么含义,以及为什么我无法通过使用虚拟地址通过PCIE访问BAR的物理区域 - 另一个通过PCIE映射的设备来使用IOMMU。 ?

这是否意味着RDMA gpudirect始终仅操作物理地址(在CPU的物理地址空间中),但是为什么我们发送到内核功能 uva_src_ptr 等于 host_src_ptr - CPU虚拟地址空间中的简单指针?

有帮助吗?

解决方案

IOMMU非常有用,因为它提供了一组映射寄存器。它可以安排任何物理内存出现在设备上可访问的地址范围内的任何物理内存,并且也可能导致物理散射的缓冲区与设备看起来连续。这对第三方PCI/PCI Express卡或试图访问NVIDIA GPU的原始物理偏移的远程机器不利,因为这可能不会导致 实际上 访问预期的内存区域或由IOMMU单元以每张XARD限制/限制/限制此类访问。因此,必须禁用这

“ Gpudirect的RDMA目前依赖 从PCI设备的角度来看,所有物理地址都是相同的."

-nvidia, RDMA和GPUDIRECT的设计注意事项

当驾驶员尝试利用CPU的MMU和映射内存映射I/O(MMIO)的映射区域以在内核空间内使用时,他们通常将返回的地址从内存映射到自己的内存映射中。因为每个驱动程序都在其自己的上下文或名称空间内运行,所以在NVIDIA的驱动程序和其他希望支持RDMA+GPUDIRECT的驱动程序之间交换这些映射将非常困难,并且会导致供应商特定的解决方案(甚至可能是产品的产品 - 特定于第三方产品之间的驱动因素会大不相同)。此外,当今的操作系统目前没有任何良好的解决方案来交换驱动程序之间的MMIO映射,因此NVIDIA导出了几个功能,这些功能使第三方驱动程序可以轻松地从内核空间内的内核空间轻松访问此信息。

NVIDIA强制使用“物理地址”通过RDMA访问GPudirect的每张卡。这大大简化了将数据从一台计算机转移到远程系统的PCI-Express BUS的过程,而不必担心与虚拟地址有关的问题(例如将虚拟地址解析到物理上的地址)。每张卡都有一个物理地址所在的物理地址,可以在此偏移时访问;只需将一小部分逻辑添加到试图执行RDMA操作的第三方驱动程序中。另外,这32或64位的基础地址寄存器是标准PCI配置空间的一部分,因此可以通过简单地从酒吧阅读而不是必须获得NVIDIA驱动程序获得的映射地址来轻松获得卡的物理地址连接到卡后。 NVIDIA的通用虚拟寻址(UVA)将上述物理地址映射到看似连续的内存区域 用户空间 像这样的应用程序:

CUDA Virtual Address Space

这些记忆区域进一步分为三种类型:CPU,GPU和免费的,它们都记录在案 这里.

但是,回到您的使用情况:因为您在 用户空间, ,您无法直接访问系统的物理地址空间,并且您使用的地址可能是Nvidia的UVA提供的虚拟地址。假设没有进行以前的分配,则您的内存分配应位于Offset +0x00000000,这将导致您看到GPU的相同偏移本身。如果您要分配第二个缓冲区,我想您会在第一个缓冲区结束后立即开始(在offset +0x00100000)开始 虚拟地址 在您的1 MB分配的情况下,GPU的)。

如果你在 内核空间, 但是,并且正在为您的公司卡编写驱动程序来利用RDMA进行GPUDIRECT,您将使用系统的BIOS和/或OS分配给GPU的32或64位物理地址直接与RDMA数据直接从GPU,本身。

此外,可能值得注意的是,并非所有DMA发动机实际上都支持转移的虚拟地址 - 实际上,大多数都需要物理地址,因为处理DMA引擎的虚拟地址 可以变得复杂 (第7页),因此许多DMA引擎对此缺乏支持。

但是,要回答您帖子标题的问题:NVIDIA当前仅支持RDMA+GPUDIRECT的物理地址 在内核空间. 。为了 用户空间 应用程序,您将始终使用NVIDIA的UVA给您的GPU的虚拟地址,该地址在CPU的虚拟地址空间中。


关于您的应用程序,这是您可以为RDMA操作所做的过程的简化分解:

  1. 您的 用户空间 应用程序创建缓冲区,该缓冲区处于统一虚拟地址空间NVIDIA提供的范围(虚拟地址)。
  2. 打电话 cuPointerGetAttribute(...) 获得P2P令牌;这些令牌与CUDA上下文中的内存有关。
  3. 将所有这些信息发送给 内核空间 不知何故(例如,读/写给您的驱动程序等)。至少,您将需要这三件事,最终进入您的 内核空间 司机:
    • P2P令牌(S)返回 cuPointerGetAttribute(...)
    • 缓冲区的UVA虚拟地址(ES)
    • 缓冲区的大小
  4. 现在,通过调用NVIDIA的内核空间函数,将这些虚拟地址转换为相应的物理地址,因为这些地址在NVIDIA的页面表中保存,并且可以通过Function的Nvidia的导出,例如:: nvidia_p2p_get_pages(...), nvidia_p2p_put_pages(...), , 和 nvidia_p2p_free_page_table(...).
  5. 使用上一步中获得的这些物理地址来初始化您的DMA引擎,以操纵这些缓冲区。

可以找到这个过程的更深入的解释 这里.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top