我有这段代码,这些代码具有分析,优化和缓存效率,因为我很可能通过我的知识水平获得它。它在概念上在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.
}
恰好,RunTask()
本质上是一组线性代数运算,每次都在相同的非常大的数据集上重复运行,因此适合在GPU上运行。所以我想实现以下目标:
RunTask()
功能,而不必修改它以符合restrict(amp)
。我当然可以为GPU任务设计一个restrict(amp)
兼容的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"
但我怀疑你可以做这样的事情,因为
对parallel_for_each的调用表现得好像是同步的
(http://msdn.microsoft.com/en-us/library/hh305254.aspx)
那么有可能实现我的1-3个请求,还是我必须放弃3号?即便如此,我将如何实施呢?
答案 0 :(得分:4)
请参阅我对will array_view.synchronize_asynch wait for parallel_for_each completion?的回答,了解为什么parallel_for_each
可以作为排队或调度操作而不是同步操作。这解释了为什么您的代码应满足您的要求1&amp; 2.它也应该满足要求3,尽管你可能想要考虑使用一个restrict(cpu, amp)
函数,因为这样可以减少维护代码。
但是,您可能需要考虑您的方法的一些性能影响。
首先,parallel_for_each
仅排队工作,来自主机和GPU内存的数据副本使用主机资源(假设您的GPU是离散的和/或不支持直接复制)。如果您在主机上的工作使保持GPU工作所需的所有资源饱和,那么您实际上可能会降低GPU计算速度。
其次,对于许多数据并行且易于在GPU上运行的计算,它们要快得多,以至于尝试在CPU上运行工作的额外开销不会导致整体加速。开销包括第一项(上图)和协调主机工作的额外开销(调度线程,合并结果等)。
最后,您的实现不会考虑在GPU和CPU上运行任务所花费的时间的任何变化。它假设800个AMP任务将花费200个cpu任务。在某些硬件上可能是这样,但在其他硬件上则不然。如果一组任务花费的时间超过预期,那么您的应用程序将阻塞并等待较慢的任务集完成。您可以使用主/工作模式来避免这种情况,从队列中提取任务,直到没有更多可用任务。这种方法意味着在最坏的情况下,您的应用程序必须等待最终任务完成,而不是一块任务。使用主/工作方法也意味着无论相对CPU / GPU性能如何,您的应用程序都将以相同的效率运行。
My book讨论了使用主/工作人员(n-body)和并行队列(cartoonizer)跨多个GPU调度工作的示例。您可以从CodePlex下载源代码。请注意,基于与C ++ AMP产品团队的讨论,出于上述原因故意不包括CPU和GPU上的共享工作。