openMP的target和target data之间有什么区别?

6

目标构造将代码区域从主机转移到目标设备。变量 pv1v2 使用 map 子句显式地映射到目标设备。

那么,“该构造创建将持续存在于目标数据区域中的变量”和“新设备数据环境创建”这两个说法暗示了什么呢?

  • “该构造创建将持续存在于目标数据区域中的变量”
  • “新设备数据环境创建”

就“目标数据”构造而言,这些代码在卸载机制方面有何不同之处?

void vec_mult1(float *p, float *v1, float *v2, int N)
{
    int i;
    init(v1, v2, N);
#pragma omp target map(to: v1[0:N], v2[:N]) map(from: p[0:N])
#pragma omp parallel for
    for (i=0; i<N; i++)
        p[i] = v1[i] * v2[i];
    output(p, N);
}


void vec_mult2(float *p, float *v1, float *v2, int N)
{
    int i;
    init(v1, v2, N);
#pragma omp target device(mic0) data map(to: v1[0:N], v2[:N]) map(from: p[0:N])
    {
    //this code runs on accelerator card
#pragma omp target //if we omit it what difference will it make ? 
#pragma omp parallel for
        for (i=0; i<N; i++)
            p[i] = v1[i] * v2[i];
    }
    output(p, N);
}

void vec_mult3(float *p, float *v1, float *v2, int N)
{
    int i;
    init(v1, v2, N);
#pragma omp target data map(to: v1[0:N], v2[:N]) map(from: p[0:N])
    {

        //target construct omitted
#pragma omp parallel for
        for (i=0; i<N; i++)
            p[i] = v1[i] * v2[i];
    }
    output(p, N);
}

我试图执行它们,但是我无法注意到它们之间的显着区别。

2个回答

9
目标数据结构仅创建一个持续到该区域的设备数据环境。它仅设置了在设备数据环境和遇到任务的数据环境之间的变量映射。采用单独的结构背后的原理是,在许多情况下,希望某些数据保留在设备上,而不是不断地传输到设备和从设备中传输出来。
想象以下非常人为的例子:
int data[N];

#pragma omp target
#pragma omp for
for (int i = 0; i < N; i++)
   data[i] *= 2;

// Do something else

#pragma omp target
#pragma omp for
for (int i = 0; i < N; i++)
   data[i] += 5;

现在,在这种情况下,两个target构造也会创建两个数据环境。data变量会自动映射为tofrom。这意味着以下一系列操作将发生:
  1. data被复制到设备上
  2. 第一个循环在设备上运行
  3. data从设备中复制出来
  4. 主机执行// Do something else
  5. data被复制到设备上
  6. 第二个循环在设备上运行
  7. data从设备中复制出来
现在假设// Do something else读取data但从不修改它。这使得在步骤5中将data传输到设备上变得多余-它可以保留在步骤2后的状态中。这就是target data构造发挥作用的地方。它允许您创建跨越target构造的范围的数据环境。然后可以重写上面的示例:
int data[N];

#pragma omp target data map(tofrom: data)
{
   #pragma omp target
   #pragma omp for
   for (int i = 0; i < N; i++)
      data[i] *= 2;

   #pragma omp target update from(data)

   // Do something else

   #pragma omp target
   #pragma omp for
   for (int i = 0; i < N; i++)
      data[i] += 5;
}

在这种情况下,target结构不会创建新的设备数据环境,而是利用由target data结构创建的环境(实际上它们确实会创建新的数据环境,但是这些环境会与target data中的环境合并,并且不包含任何新的引用)。因此,操作的顺序如下:
  1. data被复制到设备上
  2. 第一个循环在设备上运行
  3. data从设备上显式地复制
  4. 主机执行// Do something else
  5. 第二个循环在设备上运行
  6. data从设备上复制
由于data// Do something else中需要使用,但只有在target data结构的末尾才会自动从设备传输回来,因此在第3步中使用了显式的target update将其复制到遇到任务的数据环境中。
现在这只是一个小的、非常人工的例子,但在现实生活中,节省不必要的数据传输可以显著提高将计算卸载到协处理器和/或加速器的OpenMP应用程序的性能。

1

#pragma omp target data只将变量映射到目标设备,但不在目标设备上执行任何代码。#pragma omp target将变量映射并在目标设备上执行目标区域。

因此,在您的示例中:

  • vec_mult1和vec_mult2将在目标设备上执行循环;
  • vec_mult3将将变量映射到目标设备,但在主机上执行循环。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接