【问题标题】:GPU & CPU concurrency: Producer Consumer Bounded BufferGPU & CPU 并发:生产者消费者有界缓冲区
【发布时间】:2015-07-03 06:06:09
【问题描述】:

考虑以下问题:

您有一个具有单个 gpu 和单个 cpu 的计算环境。 在 gpu 上,您运行一个程序,该程序对 1e6 个浮点数的数组执行计算。该计算步骤重复 n 次(过程 1)。在每个计算步骤之后,我将数组从设备内存传输到主机内存。传输完成后,将在 CPU 上调用串行算法分析数据(过程 2)。

此程序连续运行。我想知道如何并行化进程 1 和 2,以减少整个程序的运行时间。进程 1 必须等待进程 2 完成,反之亦然。

我知道 CUDA 内核是异步调用的,并且我知道存在带有固定主机内存的异步复制操作。但是,在这种情况下,我需要等待 GPU 完成,然后 CPU 才能开始处理该输出。 我怎样才能传递这些信息?

我尝试修改多线程 cpu 生产者/消费者代码,但没有成功。我最终序列化了两个管理 gpu 和 cpu 工作负载的 cpu 线程。 但是,在这里我的 GPU 在继续之前等待 CPU 完成...

#include <mutex>
#include <condition_variable>

#include "ProducerConsumerBuffer.hpp"

ProducerConsumerBuffer::ProducerConsumerBuffer(int capacity_in, int n): capacity(capacity_in), count(0) {
    c_bridge = new float[n];
    c_CPU = new float[n];
}

ProducerConsumerBuffer::~ProducerConsumerBuffer(){
    delete[] c_bridge;
    delete[] c_CPU;
}

void ProducerConsumerBuffer::upload(device_pointers *d, params &p, streams *s){
    std::unique_lock<std::mutex> l(lock);

    not_full.wait(l, [this](){return count != 1; });

    copy_GPU_to_CPU(d,c_bridge,p,s);
    count++;

    not_empty.notify_one();
}



void ProducerConsumerBuffer::fetch(){
    std::unique_lock<std::mutex> l(lock);

    not_empty.wait(l, [this](){return count != 0; });

    std::swap(c_bridge,c_CPU);
    count--;

    not_full.notify_one();

}

我希望有一种方法可以使用 cudastreams 做到这一点。但我认为它们只适用于设备函数调用。我是否需要改用 MPI,或者是否有其他选项可以在异构计算平台上同步进程?我阅读了有关支持此操作的 OpenCL,因为所有计算设备都组织在一个“上下文”中。 CUDA不能做同样的事情吗?

如果我的序列化 CPU 操作的运行时间是 GPU 操作的 4 倍,我计划创建 4 个 CPU 使用者。

任何见解将不胜感激!

编辑:CPU 函数包含不可并行化的串行代码。

【问题讨论】:

  • 只是附注:为什么需要在主机上进行“数据分析”?如果您可以在设备上执行它,根据此分析步骤的输出,您可以节省内存带宽...
  • 为了在 CPU 和 GPU 之间获得设备并发,通常的习惯用法是双缓冲区:让 CPU 和 GPU 在 2 个不同的缓冲区上运行,然后在两个设备都完成后切换缓冲区的意义。您描述的工作负载听起来需要 4 个缓冲区和 4 个 CPU 线程来进行 CPU 处理。目标是让 2 台设备(CPU 和 GPU)中的每台都花费相等的时间处理,否则其中一个或另一个会浪费时间等待。此处的可分页 memcpy 示例应该会有所帮助。 github.com/ArchaeaSoftware/cudahandbook/tree/master/concurrency
  • @oscillon 请确保标记答案并投票,以便我们关闭它

标签: concurrency cuda


【解决方案1】:

如果不使用多个线程或进程或显着复杂化您的 CPU 算法以实现可容忍的调度延迟,就无法做您想做的事。这是因为您必须能够以正确的频率以低延迟命令 GPU 来处理您为 GPU 工作负载所拥有的数据,但 CPU 工作负载听起来并不重要,并且必须考虑到循环的运行时间.

因此,为了确保 CPU 和 GPU 都在持续处理并实现最高吞吐量和最低延迟,您必须将 GPU 指挥部分和昂贵的 CPU 计算部分分成不同的线程 - 在这两个线程之间存在某种IPC - 最好是共享内存。如果专用 CPU 处理线程以与 CUDA 类似的方式工作并在线程间使用它的 cudaEvent_t 并使 GPU 命令线程也命令 CPU 线程,那么您可能能够简化一些任务 - 即 1 个命令线程和 2 个处理从属(GPU、CPU)。

【讨论】:

  • 听起来支持 cuda 的 MPI 将是当时的选择。对吗?
  • 我没有广泛使用 MPI,因此我无法评论该特定策略,除非传递数据块的消息不会随大块扩展,并且大多数 MPI 是基于我天真的知识的套接字他们。我只是制作我自己的线程/服务器,但如果它适合你和你习惯的,继续使用 MPI/cuda - 如果它是一个新的瓶颈,这只是一个问题。
猜你喜欢
  • 1970-01-01
  • 2016-06-29
  • 1970-01-01
  • 2018-05-05
  • 2015-06-08
  • 2011-03-21
  • 2014-05-13
  • 2017-04-07
  • 1970-01-01
相关资源
最近更新 更多