【问题标题】:Difference between openMP's target and target data?openMP的目标数据和目标数据的区别?
【发布时间】:2014-04-10 11:14:28
【问题描述】:

目标构造将代码区域从主机卸载到目标设备。 变量 p,v1,v2 使用 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);
}

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

【问题讨论】:

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


    【解决方案1】:

    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 是从设备复制的

    现在假设// 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 构造创建的环境(实际上它们确实创建了新的数据环境,但它们与来自@987654339 的环境合并@ 并且它们不包含任何新的引用)。所以操作顺序是:

    1. data 被复制到设备中
    2. 第一个循环在设备上运行
    3. data 是从设备显式复制的
    4. 主机执行// Do something else
    5. 第二个循环在设备上运行
    6. data 是从设备复制的

    由于在// Do something else 中需要data,但它只是在target data 构造结束时从设备自动传输,因此在步骤中使用显式target update 将其复制到遇到任务的数据环境中3.

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

    【讨论】:

      【解决方案2】:

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

      所以,在你的例子中:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-08-20
        • 1970-01-01
        • 2018-09-18
        • 2013-10-10
        • 1970-01-01
        • 2011-08-18
        • 1970-01-01
        相关资源
        最近更新 更多