【问题标题】:CUDA Unified Memory Programming - Can I pass a pointer to modules which are not aware of CUDA?CUDA 统一内存编程 - 我可以将指针传递给不知道 CUDA 的模块吗?
【发布时间】:2015-06-24 03:01:15
【问题描述】:

我会用cudaMallocManaged 分配一些内存。我可以安全地将这个指针传递给另一个不知道 CUDA 的程序模块(它被编译成另一个 .o 文件),并且只会使用普通的 memcpy 或其他东西来操作指针后面的数据吗?

类似的东西

// compiled into A.o
class A{
  void* getMem(int size){
    void* ptr;
    cudaMallocManaged(*ptr, size);
    return ptr;
  }

  // some kernels here

}


// compiled into B.o
class B{
  void manipulateMem(void* ptr, void* source, int size){
    memcpy(ptr, source, size);
  }

}

然后是这样的代码,可能会编译到 main.o:

A a;
B b;
void* mem = a.getMem(100);
b.manipulateMem(mem, source, 100);

我没有发现自动复制/同步在这种情况下不起作用的任何通知。

【问题讨论】:

    标签: cuda


    【解决方案1】:

    我可以安全地将这个指针传递给另一个不知道 CUDA 的程序模块(它被编译成另一个 .o 文件),并且只会使用普通的 memcpy 或其他东西来操作指针后面的数据吗?

    是的,您可以,但仍必须遵守Unified Memory access rules(当前是:

    1. 最初,在分配时(使用托管分配器,例如 cudaMallocManaged),在调用任何内核之前,可以从主机 CPU(运行的代码)访问托管指针。
    2. 一旦调用了任何内核,直到调用了后续的cudaDeviceSynchronize(),主机代码中的数据无法访问,任何尝试在主机代码中使用它都会导致 UB,这可能包括段错误。
    3. 在同步事件(例如cudaDeviceSynchronize())之后,主机对托管指针引用的数据的访问被恢复。 (从技术上讲,在当前的实现中,此时主机访问数据通常会导致页面错误,这是一个操作系统可见的事件。这些页面错误基本上会调用 CUDA 运行时,然后在hood,将数据返回给主机,服务页面错误。但括号中的这些 cmets 对于理解一般行为规则不是必需的。)

    因此,CUDA 运行时基本上具有明确的标记(内核启动 -> 同步),这些标记明确地向它指明如何管理数据(何时迁移以及迁移的方向)。因此,即使您在某些“模块......不知道 CUDA”中运行代码,如果遵守上述规则,该模块中的代码也将有权访问数据,因为 CUDA 运行时有足够的、显式的标识它如何管理数据的标记。

    对于计算能力 6.0 或更高的 GPU,上述规则基本上不适用。对于这些 GPU,主机和设备的并发访问 是可能的,但是对公共资源的多次访问仍然存在竞争条件的可能性,就像在任何多处理器/多线程环境中一样。 目前,CUDA 运行时不会在主机和设备访问同一内存之间强制执行任何特定的访问顺序规则。

    【讨论】:

    • 请注意,此答案需要针对 Pascal 和更高版本的 GPU 进行更新,更改 1-3。 Pascal GPU 和 CPU 可以同时访问托管内存,但需要注意的是,必须像在任何多处理器共享内存代码中一样正确处理竞争条件。 1-3 仍然适用于早期的 GPU。
    • c++ host atomics 能否与 cuda device atomics 一起使用统一的 mem 实现 volta?例如,细粒度的工作卸载?使用 gpu 端原子 spinwait 和 cpu 端原子增量向 gpu 发出信号?比内核启动开销更快?
    【解决方案2】:

    是的,CUDA 统一内存模型明确允许这种访问:GPU 不仅可以直接访问统一内存指针。同样,在主机 CPU 上运行的部分程序将具有统一的访问权限,包括 GPU 内存。但请注意总线带宽瓶颈。

    【讨论】:

    • 谢谢!但这对我来说仍然很神奇。你能补充几句这实际上是如何工作的吗?在完全不知道 CUDA 的情况下,程序模块如何知道它必须同步内存?
    • @Michael:我不相信。 GPU 操作会导致页面级同步,而主机操作不会。
    • @Michael:程序“知道”其地址空间的某些部分实际上不在 RAM 中,而是在硬盘上,或者在一块或硬件的某些控制寄存器上:虚拟记忆。您的程序看到的地址空间是虚拟的。每当进行访问时,CPU 都会使用地址转换表中的数据来决定访问地址实际位于何处。如果它在 GPU 上,那么它会跳转到驱动程序,该驱动程序将其转换为物理 PCI 空间地址,该地址映射到 GPU 上的内存。
    • @Michael:“页面”是虚拟内存的固有概念。并且取决于驱动程序如何实现它,事情可能发生在页面级别。但是在 CUDA 的情况下,不,没有页面级同步。 GPU 内存的相关部分(将裸 CPU 视为物理地址空间的另一部分,就在另一个位置)被映射到进程中。虚拟内存负责其余的工作。
    • @Michael:从你的角度来看,答案仍然成立。该过程对过程是完全透明的。不同之处在于细节,即数据如何在 GPU 和 CPU 之间传输。在 UVA/映射内存情况下,当主机处理器访问与 GPU 内存相关的某个地址范围时,访问会直接转到 GPU。在托管内存情况下,当访问与内存关联的地址空间时,CUDA 驱动程序将在后台执行同步复制操作。然而,对于进程来说,这与交换空间一样透明。
    猜你喜欢
    • 2017-04-30
    • 1970-01-01
    • 1970-01-01
    • 2021-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-06
    • 2020-06-03
    相关资源
    最近更新 更多