如何同时在CPU和GPU设备上运行任务?

qua*_*ant 5 c++ c++-amp

我有这段代码作为分析,优化和缓存效率,因为我很可能通过我的知识水平得到它.它在概念上在CPU上运行如下:

#pragma omp parallel for schedule(dynamic)
  for (int i = 0; i < numberOfTasks; ++i)
  {
    result[i] = RunTask(i); // result is some array where I store the result of RunTask.
  }
Run Code Online (Sandbox Code Playgroud)

它只是恰巧,RunTask()本质上是一组在每一次一样,非常大的数据集反复操作线性代数运算的,所以它适合在GPU上运行.所以我想实现以下目标:

  1. 将一些任务卸载到GPU
  2. 当GPU忙时,处理CPU上的其余任务
  3. 对于CPU级别的操作,请保持我的super-duper RunTask()功能,而不必修改它以符合restrict(amp).我当然可以restrict(amp)为GPU任务设计一个兼容的lambda.

最初我想过做以下事情:

// assume we know exactly how much time the GPU/CPU needs per task, and this is the 
// most time-efficient combination:
int numberOfTasks = 1000;
int ampTasks = 800;

// RunTasksAMP(start,end) sends a restrict(amp) kernel to the GPU, and stores the result in the
// returned array_view on the GPU
Concurrency::array_view<ResulType, 1> concurrencyResult = RunTasksAMP(0,ampTasks);

// perform the rest of the tasks on the CPU while we wait
#pragma omp parallel for schedule(dynamic)
  for (int i = ampTasks; i < numberOfTasks; ++i)
  {
    result[i] = RunTask(i); // this is a thread-safe
  }

// do something to wait for the parallel_for_each in RunTasksAMP to finish.
concurrencyResult.synchronize();
//... now load the concurrencyResult array into the first elements of "result"
Run Code Online (Sandbox Code Playgroud)

但我怀疑你可以做这样的事情,因为

对parallel_for_each的调用表现得好像是同步的

(http://msdn.microsoft.com/en-us/library/hh305254.aspx)

那么有可能实现我的1-3个请求,还是我必须放弃3号?即便如此,我该如何实施呢?

Ade*_*ler 4

请参阅我对array_view.synchronize_asynch 是否会等待 parallel_for_each 完成?解释为什么parallel_for_each可以将其视为排队或调度操作而不是同步操作。这解释了为什么您的代码应该满足要求 1 和 2。它还应该满足要求 3,尽管您可能需要考虑拥有一个函数,因为restrict(cpu, amp)这将使您需要维护的代码更少。

但是,您可能需要考虑您的方法对性能的一些影响。

首先,parallel_for_each唯一的队列工作,来自主机和 GPU 内存的数据复制使用主机资源(假设您的 GPU 是离散的和/或不支持直接复制)。如果您在主机上的工作占用了保持 GPU 工作所需的所有资源,那么您实际上可能会减慢 GPU 计算速度。

其次,对于许多数据并行且适合在 GPU 上运行的计算来说,它们的速度要快得多,以至于尝试在 CPU 上运行工作的额外开销不会导致整体加速。开销包括第一项(上面)和在主机上协调工作的额外开销(调度线程、合并结果等)。

最后,上面的实现没有考虑在 GPU 和 CPU 上运行任务所需时间的任何变化。它假设 800 个 AMP 任务将花费与 200 个 cpu 任务一样长的时间。这在某些硬件上可能是正确的,但在其他硬件上则不然。如果一组任务花费的时间比预期长,那么您的应用程序将阻塞并等待较慢的一组任务完成。您可以使用主/工作模式从队列中提取任务,直到没有更多可用任务来避免这种情况。这种方法意味着在最坏的情况下,您的应用程序将不得不等待最终任务完成,而不是任务块。使用主/从程序方法还意味着无论相对 CPU/GPU 性能如何,您的应用程序都将以相同的效率运行。

我的书讨论了使用主/工作线程(n-body)和并行队列(cartoonizer)跨多个 GPU 调度工作的示例。您可以从CodePlex下载源代码。请注意,出于与 C++ AMP 产品团队讨论的上述原因,它故意不涵盖 CPU 和 GPU 上的共享工作。