openMP的目标数据和目标数据之间的区别?

时间:2014-03-07 10:42:55

标签: c++ c multithreading parallel-processing openmp

目标构造将代码区域从主机卸载到目标设备。 变量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 个答案:

答案 0 :(得分:5)

target data构造仅创建一个持续该区域范围的设备数据环境。它仅设置设备数据环境中的变量与遇到任务的数据环境之间的映射。具有单独构造的基本原理是,在许多情况下,希望某些数据保留在设备上而不是不断地传输到设备上。

想象一下以下非常人为的例子:

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已从设备中复制
  8. 现在假设// Do something else读取data但从未修改过它。这使得data在步骤5中向设备的传输变得多余 - 它可以保留在步骤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已从设备中复制
    7. 由于data中需要// Do something else,但它只是从target data结构末尾的设备自动传输,因此显式target update用于复制它在步骤3中进入遇到任务的数据环境。

      现在这只是一个小而且非常人为的例子,但在现实生活中,节省不必要的数据传输可以显着提高OpenMP应用程序的性能,将计算卸载到协处理器和/或加速器。

答案 1 :(得分:1)

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

所以,在你的例子中:

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