在openmp中设计一个包含任务的算法

问题描述 投票:0回答:1

我目前有一个代码可以处理大型数据集,最后生成一个数组。这是必须将数组添加到全局缓冲区中,这一切都发生在循环内。例如。

for(i=0;i<10000;i++)
{   <1. do some processing, generate a 1M-sized array>
    <2. update this array into global buffer>
}

任务1发生在GPU上,我希望第二部分在CPU上并行发生,即1个线程控制GPU执行任务1,而所有其他线程在1个缓冲区准备好处理时执行任务2。对于基本情况,如何使用缓冲区的一个副本(即GPU侧的一个副本和CPU侧的一个副本来接收GPU副本)?

c++ multithreading task gpu openmp
1个回答
0
投票

你可以做的是拥有一组生产者 - 消费者的任务,这样第1步产生一个缓冲区,第2步消耗该缓冲区,同时将结果合并到你的全局数组中。

像(通常的parallel + single里面):

const int buffer_size = 100000;
type global[buffer_size];
type buffer[2][buffer_size];

for(int i=0;i<10000;i++)
{
    type *buf[buffer_size] = buffer[i % 2];
    #pragma omp task depend(out: [buffer_size]buf)
    {
        <1. write to buf>
    }

    #pragma omp task depend(in: [buffer_size]buf) depend(inout: [buffer_size]global)
    {
        <2. update global using buf>
    }
}

这允许步骤2与步骤1重叠,一次迭代为“滞后”,即迭代的步骤1,i = 1将同时运行到步骤2的迭代i = 0.每次重叠迭代将需要一个缓冲区,以便每个同时操作可以彼此独立地发生。

现在buf(in / out)的语义很简单,因为它们是简单的procuder-consumer关系。对于全局,您需要inout,因为您就地更新缓冲区:获取当前数组(in)并为其分配新值(out)。这意味着由于这种依赖性,步骤2的所有任务都将被序列化,这意味着最多可以重叠2次迭代(并且使用多于2个缓冲区没有意义)。

这是当前OpenMP(4.5)任务的限制,但存在可解决此问题的a proposal for task reductions。另一种方法是将global声明为shared,在这种情况下,您需要使用原子操作来修改它。

您可以使用target子句在GPU上执行任务1。确保卸载的设备(即GPU)中的数据被复制到CPU。在步骤2的任务中,您可以使用并行构造或任务再次并行化步骤2本身。

© www.soinside.com 2019 - 2024. All rights reserved.