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

标签 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);
}

我尝试执行它们,但我无法注意到它们之间的显着差异。

最佳答案

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. 数据被复制到设备
  2. 第一个循环在设备上运行
  3. data 从设备复制
  4. 宿主执行//Do something else
  5. 数据被复制到设备
  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. 数据被复制到设备
  2. 第一个循环在设备上运行
  3. data 明确地从设备复制
  4. 宿主执行//Do something else
  5. 第二个循环在设备上运行
  6. data 从设备复制

因为 data//Do something else 中需要,但它只会在 target data 末尾自动从设备传输构造,显式目标更新用于在第 3 步将其复制到遇到的任务的数据环境中。

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

关于c++ - openMP 的目标和目标数据之间的区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22247855/

相关文章:

c++ - 如何判断包含头文件的位置?

c++ - 搜索数据文件 : coding in python vs c++

C 命令行密码

objective-c - 将字符串添加到数组

ruby 线程#allocate TypeError

spring - 我无法以任何方式从 Spring Boot 中的 application.properties 获取值(value)

c++ - 图片上的文字

c++ - 避免在一对几乎相同的基 > 派生类中重复代码

c - 线条和纹理不会一起出现

c++ - 对线程C++使用类数组的奇怪错误