OpenMP 减少,变量不是私有的?
OpenMP reduction, variable not private?
我有一个这样的数组(0,0 在左下方):
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0
0 0 1 0 1 0 1 0 0
0 0 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1
我的目标是获取未完全设置为0
的更高行的索引。为此,我编写了以下代码(效果很好):
max=0;
for (i=0 ; i<width ; ++i) {
for (j=max ; j<height ; ++j) {
if (array[i*height+j]!=0) {
max=j;
}
}
}
对于第二个循环,我将 j
初始化为最大值,因为全局最大值不能小于局部最大值。这样我就可以减少测试次数。
我尝试将其与 OpenMp
并行化。我的代码现在是:
max=0;
#pragma omp parallel for default(none) \
shared(spec, width, height) \
collapse(2) \
reduction(max:max)
for (i=0 ; i<width ; ++i) {
for (j=max ; j<height ; ++j) {
if (array[i*height+j]!=0) {
max=j;
}
}
}
这会导致分段错误。为了让它起作用,我将 j=max
更改为 j=0
。所以问题似乎来自 max
变量。
我不明白为什么,因为随着减少,这个变量在每个线程之间应该是私有的(或 lastprivate)。那么为什么它会崩溃呢?我如何将我的 "optimization" 与 OpenMP 一起使用?
首先,High Performance Mark 用户的评论是正确的。如果您的循环索引值取决于计算值,则不应使用 collapse。在您的示例中,"j" 取决于 "max",这将产生不正确的结果。但是,这不是您的分段错误的原因。
我建议你调试你的例子,这样你就可以找到崩溃的根源; "max" 默认用负数初始化,这导致 "j" 也有上述值。因此,当尝试访问数组 [i*height+(-2147483648)] 时,您会遇到分段错误。
发生这种情况是因为 OpenMP 为每个归约运算符指定了一个初始值。对于max运算符,可以在specification of OpenMP 3.1中找到如下描述:
max Least representable value in the reduction list item type
在我们的例子中,这意味着每个线程在并行区域的开始处都有一个 max 变量的私有副本,该副本保存可以存储为 int 的最小数字的值(通常是 -2147483648)。
我已经为您的示例编写了一个非常基本的解决方法。我删除了 collapse 子句,并在并行区域的开头手动初始化 max 变量:
#pragma omp parallel default(none) private(j) shared(array, width, height) reduction(max:max)
{
// Explicit initialization
max = 0;
#pragma omp for
for (i=0 ; i<width ; ++i) {
for (j=max ; j<height ; ++j) {
if (array[i*height+j]!=0) {
max=j;
}
}
}
}
额外说明一下,您不需要每次都使用 max=j。您可以尝试检查何时找到第一个 0 并使用之前的位置。
希望对您有所帮助
我有一个这样的数组(0,0 在左下方):
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0
0 0 1 0 1 0 1 0 0
0 0 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1
我的目标是获取未完全设置为0
的更高行的索引。为此,我编写了以下代码(效果很好):
max=0;
for (i=0 ; i<width ; ++i) {
for (j=max ; j<height ; ++j) {
if (array[i*height+j]!=0) {
max=j;
}
}
}
对于第二个循环,我将 j
初始化为最大值,因为全局最大值不能小于局部最大值。这样我就可以减少测试次数。
我尝试将其与 OpenMp
并行化。我的代码现在是:
max=0;
#pragma omp parallel for default(none) \
shared(spec, width, height) \
collapse(2) \
reduction(max:max)
for (i=0 ; i<width ; ++i) {
for (j=max ; j<height ; ++j) {
if (array[i*height+j]!=0) {
max=j;
}
}
}
这会导致分段错误。为了让它起作用,我将 j=max
更改为 j=0
。所以问题似乎来自 max
变量。
我不明白为什么,因为随着减少,这个变量在每个线程之间应该是私有的(或 lastprivate)。那么为什么它会崩溃呢?我如何将我的 "optimization" 与 OpenMP 一起使用?
首先,High Performance Mark 用户的评论是正确的。如果您的循环索引值取决于计算值,则不应使用 collapse。在您的示例中,"j" 取决于 "max",这将产生不正确的结果。但是,这不是您的分段错误的原因。
我建议你调试你的例子,这样你就可以找到崩溃的根源; "max" 默认用负数初始化,这导致 "j" 也有上述值。因此,当尝试访问数组 [i*height+(-2147483648)] 时,您会遇到分段错误。
发生这种情况是因为 OpenMP 为每个归约运算符指定了一个初始值。对于max运算符,可以在specification of OpenMP 3.1中找到如下描述:
max Least representable value in the reduction list item type
在我们的例子中,这意味着每个线程在并行区域的开始处都有一个 max 变量的私有副本,该副本保存可以存储为 int 的最小数字的值(通常是 -2147483648)。
我已经为您的示例编写了一个非常基本的解决方法。我删除了 collapse 子句,并在并行区域的开头手动初始化 max 变量:
#pragma omp parallel default(none) private(j) shared(array, width, height) reduction(max:max)
{
// Explicit initialization
max = 0;
#pragma omp for
for (i=0 ; i<width ; ++i) {
for (j=max ; j<height ; ++j) {
if (array[i*height+j]!=0) {
max=j;
}
}
}
}
额外说明一下,您不需要每次都使用 max=j。您可以尝试检查何时找到第一个 0 并使用之前的位置。
希望对您有所帮助