【问题标题】:Does the nVidia RDMA GPUDirect always operate only physical addresses (in physical address space of the CPU)?nVidia RDMA GPUDirect 是否总是只操作物理地址(在 CPU 的物理地址空间中)?
【发布时间】:2013-11-19 10:41:04
【问题描述】:

据我们所知:http://en.wikipedia.org/wiki/IOMMU#Advantages

IOMMU 可以支持外设内存分页。外围设备 使用 PCI-SIG PCIe 地址转换服务 (ATS) 页面请求 接口 (PRI) 扩展可以检测并发出对内存的需求 经理服务。

但是当我们使用 CUDA >= 5.0 的 nVidia GPU 时,我们可以使用 RDMA GPUDirect,并且知道:

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

传统上,像 BAR 窗口这样的资源被映射到用户或内核 使用 CPU 的 MMU 作为内存映射 I/O (MMIO) 的地址空间 地址。但是,由于当前的操作系统没有 在驱动程序之间交换 MMIO 区域的足够机制, NVIDIA 内核驱动程序导出函数以执行必要的 地址转换和映射。

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

GPUDirect 的 RDMA 目前依赖于所有物理地址 从 PCI 设备的角度来看是相同的。这使它 与 IOMMU 不兼容,因此必须为 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 的物理区域来使用 IOMMU - 另一个内存映射通过 PCIe 的设备?

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

【问题讨论】:

    标签: cuda gpgpu pci-e memory-mapping gpudirect


    【解决方案1】:

    IOMMU 非常有用,因为它提供了一组映射寄存器。它可以安排任何物理内存出现在设备可访问的地址范围内,并且还可以使物理上分散的缓冲区看起来与设备相邻。这对于尝试访问 nVidia GPU 的原始物理偏移量的第 3 方 PCI/PCI-Express 卡或远程计算机不利,因为这可能导致无法实际上访问预期的内存区域或禁止访问/ IOMMU 单元在每张卡的基础上限制此类访问。那么,这必须被禁用,因为

    “GPUDirect 的 RDMA 当前依赖于所有物理地址 从 PCI 设备的角度来看也是如此。”

    -nVidia,Design Considerations for rDMA and GPUDirect

    当驱动程序尝试利用 CPU 的 MMU 并映射内存映射 I/O (MMIO) 区域以在内核空间内使用时,它们通常会将返回的内存映射地址保留给它们自己。由于每个驱动程序都在其自己的上下文或命名空间中运行,因此在 nVidia 的驱动程序和希望支持 rDMA+GPUDirect 的其他第 3 方供应商的驱动程序之间交换这些映射将非常困难,并且会产生特定于供应商的解决方案(甚至可能是产品- 如果驱动程序在第 3 方的产品之间有很大差异)。此外,今天的操作系统目前没有任何好的解决方案来交换驱动程序之间的 MMIO 映射,因此 nVidia 导出了几个函数,允许 3rd 方驱动程序轻松地从内核空间内访问这些信息。

    nVidia 强制使用“物理寻址”来通过 rDMA 访问每个卡以实现 GPUDirect。这大大简化了通过使用该计算机的物理寻址方案将数据从一台计算机移动到远程系统的 PCI-Express 总线的过程,而不必担心与虚拟寻址相关的问题(例如,将虚拟地址解析为物理地址)。每张卡都有一个它所在的物理地址,并且可以在这个偏移量处访问;只需向尝试执行 rDMA 操作的第 3 方驱动程序添加一小部分逻辑。此外,这些 32 位或 64 位基地址寄存器是标准 PCI 配置空间的一部分,因此卡的物理地址可以通过简单地读取其 BAR 轻松获得,而不必获得 nVidia 驱动程序获得的映射地址在附加到卡上。 nVidia 的通用虚拟寻址 (UVA) 负责将上述物理地址映射到 用户空间 应用程序的看似连续的内存区域,如下所示:

    这些内存区域进一步分为三种类型:CPU、GPU 和 FREE,均记录在 here

    不过,回到您的使用案例:由于您在 用户空间 中,因此您无法直接访问系统的物理地址空间以及您正在使用的地址可能是 nVidia 的 UVA 提供给您的虚拟地址。假设之前没有进行分配,您的内存分配应该位于偏移量 +0x00000000,这将导致您看到 GPU 本身的相同偏移量。如果您要分配第二个缓冲区,我想您会在第一个缓冲区结束后立即看到这个缓冲区(在您的情况下,距离 GPU 的基本 虚拟地址 偏移 +0x00100000 1 MB 分配)。

    但是,如果您在 内核空间 中,并且正在为您公司的卡编写驱动程序以将 rDMA 用于 GPUDirect,那么您将使用分配给GPU 由系统的 BIOS 和/或操作系统将 rDMA 数据直接传入和传出 GPU。

    此外,值得注意的是,并非所有 DMA 引擎实际上都支持虚拟地址进行传输——事实上,大多数需要物理地址,因为从 DMA 引擎can get complex(第 7 页)处理虚拟地址,因此许多 DMA引擎对此缺乏支持。

    不过,要回答您帖子标题中的问题:nVidia 目前仅支持 rDMA+GPUDirect 内核空间中的物理寻址。对于用户空间应用程序,您将始终使用由 nVidia 的 UVA 提供给您的 GPU 的虚拟地址,该地址位于 CPU 的虚拟地址空间中。


    关于您的应用程序,以下是您可以为 rDMA 操作执行的流程的简化细分:

    1. 您的用户空间应用程序会创建缓冲区,这些缓冲区在 nVidia 提供的统一虚拟寻址空间(虚拟地址)的范围内。
    2. 拨打cuPointerGetAttribute(...)获取P2P代币;这些标记与 CUDA 上下文中的内存有关。
    3. 以某种方式将所有这些信息发送到 内核空间(例如 IOCTL、读/写驱动程序等)。至少,您希望在 kernel-space 驱动程序中完成这三件事:
      • cuPointerGetAttribute(...) 返回的 P2P 令牌
      • 缓冲区的UVA虚拟地址
      • 缓冲区大小
    4. 现在通过调用 nVidia 的内核空间函数将这些虚拟地址转换为它们对应的物理地址,因为这些地址保存在 nVidia 的页表中,并且可以通过函数的 nVidia 导出来访问,例如:nvidia_p2p_get_pages(...)nvidia_p2p_put_pages(...)、和nvidia_p2p_free_page_table(...)
    5. 使用在上一步中获取的这些物理地址来初始化将操作这些缓冲区的 DMA 引擎。

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

    【讨论】:

    • 非常感谢! 1. 即在内核空间中我们总是必须使用物理寻址并禁用 IOMMU,但在用户空间中我们总是必须通过启用 IOMMU 来使用虚拟寻址,但是我们在启动时禁用 IOMMU,然后虚拟寻址 (UVA) 是如何工作的? 2. “因为每个驱动程序都在它自己的上下文或命名空间中运行” - 但据我所知,所有内核空间的驱动程序都在单个地址空间(上下文)中运行,那么“自己的上下文”是什么意思?
    • 3. “这对于尝试访问 nVidia GPU 的原始物理偏移量的第 3 方 PCI/PCI-Express 卡或远程机器不利” - 你的意思是3rd 方卡可能不使用 IOMMU,但 3rd 卡在物理地址内运行,如果 GPU 使用 IOMMU 或不使用,如果 GPU 仍然运行虚拟地址,会有什么问题?对比一下:即使我们使用 RDMA(CPU-CPU),当 CPU 使用虚拟地址时,我们也没有看到使用传统 MMU 的任何障碍。
    • 1:在许多系统(例如 x86)上,实际上没有 IOMMU 可供所有设备使用。大多数情况下,设备本身将具有用于进行页表查找的功能块,并且基本上用作 IOMMU。此外,您可以在内核空间中使用虚拟和物理寻址。这与问题 2 相关,因为现在每个驱动程序都负责在该设备的 IOMMU 中设置这些映射——第 3 方驱动程序无权访问它。我所说的“上下文”只是指功能驱动程序本身引用的私有资源。
    • 3:由于大多数设备实际上实现了自己的自己的 IOMMU,因此该设备的驱动程序必须管理该设备的 IOMMU 内发生的地址解析。 nVidia 的意思是,如果系统中存在 所有 设备用于访问 其他 卡和/或物理内存的内存区域的通用 IOMMU,则需要禁用此功能因为应该使用卡的物理地址,而不是在系统的通用 IOMMU 中解析到的其他地址。
    • 通过存在通用 IOMMU,这将打破从 PCI 设备的角度来看所有物理地址相同的假设;因此需要禁用它。我确定如果 IOMMU 存在并且只是被禁用或配置为根本不实际解析地址,这种情况会起作用,但通常情况并非如此 :(
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-23
    • 1970-01-01
    • 2014-03-14
    • 2020-04-16
    • 2014-12-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多