目标构造将代码区域从主机卸载到目标设备。
变量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);
}
我试图执行它们,但我无法注意到它们之间存在显着差异。
答案 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
。这意味着会发生以下一系列操作:
data
已复制到设备data
已从设备中复制// Do something else
data
已复制到设备data
已从设备中复制现在假设// 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
并且它们不包含任何新引用。所以操作顺序是:
data
已复制到设备data
已明确从设备中复制// Do something else
data
已从设备中复制由于data
中需要// Do something else
,但它只是从target data
结构末尾的设备自动传输,因此显式target update
用于复制它在步骤3中进入遇到任务的数据环境。
现在这只是一个小而且非常人为的例子,但在现实生活中,节省不必要的数据传输可以显着提高OpenMP应用程序的性能,将计算卸载到协处理器和/或加速器。
答案 1 :(得分:1)
#pragma omp target data
仅将变量映射到目标设备,但它不会在目标设备上执行任何代码。 #pragma omp target
映射变量并在目标设备上执行目标区域。
所以,在你的例子中: