【问题标题】:omp max reduction with storage of indexomp 最大减少与索引的存储
【发布时间】:2014-07-16 13:25:33
【问题描述】:

使用 c++ openmp 3.1 我实现了一个最大缩减,它存储了一个对象向量的整数变量(分数)的最大值。但我也想存储向量索引以访问具有最高分数的 (s) 对象。 我目前不成功的实现如下所示:

//s is a vector of sol objects which contain apart from other variables an  integer     score    variable s[].score            
int bestscore = 0;
int bestant = 0;                
#pragma omp parallel shared(bestant)
{//start parallel session
    #pragma omp for    nowait reduction(max : bestscore)
    for (int ant = 0; ant<maxsols; ++ant) // for all ants
    {
        //procedures on s[ant] object which update the  int s[ant].score
        if (s[ant].score > bestscore)
        {
            //find the object with the highest score
            bestscore = s[ant].score;
            bestant = ant;//i also want know which ant has the highest score
        }
    }
}

代码编译并运行。找到了最大的 bestscore,但 bestant 得到了一个随机索引。链接到最快完成线程的蚂蚁被存储在 bestant 中。 bestscore 从值 0 开始,因此在大多数情况下 s[ant].score 将具有更高的分数,并且 bestscore 和 bestant 会更新。 我想我需要一个减少运算符来处理 bestant,比如“on update of bestscore”。

【问题讨论】:

  • 你的问题是什么?当您编译/链接/运行该代码时会发生什么?是否有任何错误或崩溃?您是否尝试过调试它?你有真正的问题要问吗?
  • @JoachimPileborg,我认为 OP 说明了他的问题“但 bestant 得到一个随机索引”。我在答案中修复了它。

标签: c++ reduction openmp


【解决方案1】:

试试这个

int bestscore = 0;
int bestant = 0;
#pragma omp parallel
{
    int bestscore_private = 0;
    int bestant_private = 0;
    #pragma omp for nowait
    for (int ant = 0; ant<maxsols; ++ant) {         
        if (s[ant].score > bestscore_private) {
            bestscore_private = s[ant].score;
            bestant_private = ant;
        }
    }
    #pragma omp critical 
    {
        if(bestscore_private>bestscore) {
            bestscore = bestscore_private;
            bestant = besant_private;
        }
    }
}

【讨论】:

  • 感谢您的意见。然而,由于临界区,与顺序查找最佳蚂蚁相比,这并没有提高速度。但是当我需要扩展我的代码时我会记住这一点(更高的 maxsol 值)
  • 由于您的解决方案,我获得了超过 30% 的性能提升(与最初与 OP 的代码几乎相同的代码相比)
【解决方案2】:

两个观察结果:

  • 我想你只需要在bestscore_privatebestscore的值发生变化时进行比较,这样就减少了比较的次数。

  • 另外,至少在今天的 omp 中,您可以在 if 条件中使用 inside 临界区,这样bestscore_privatebestscore 之间的比较将并行进行,并且不频繁(希望所以)对bestscore的更新将以关键的方式进行。

    int 最佳分数 = 0; int bestant = 0; #pragma omp 并行 {

      int bestscore_private = 0;
      int bestant_private = 0;
      #pragma omp for nowait
      for (int ant = 0; ant<maxsols; ++ant) {         
          if (s[ant].score > bestscore_private) {
              bestscore_private = s[ant].score;
              bestant_private = ant;   
              if(bestscore_private>bestscore){   
                #pragma omp critical 
                {
    
                bestscore = bestscore_private;
                bestant = besant_private;
                }
              }
          }
      }
    

    }

【讨论】:

  • 您可以按照示例使用嵌套循环(以及内部循环的本地定义归约变量)来实现,因此关键不需要在内部循环中。这对于二维数组来说是很自然的。原则上,内部循环可能是用户定义的 simd 缩减,但我还没有看到它有效地完成。
【解决方案3】:

bestant 获得随机索引i 的原因(正如您所怀疑的)是因为bestant 是共享的,并且不像bestscore 那样从减少子句中受益。 Z boson 提出的方案很好:critical 指令块线程只执行一次,这样开销应该是有限的。

当时您使用的是 OpenMP 3.1 运行时。我想发帖解释自 OpenMP 4.0 以来已解决此限制。您现在可以编写user defined operator(参见2.19.5.7 声明缩减指令)。

在您的情况下,解决方案可以是将两个值打包在一个结构中,然后 定义两个这样的结构元素如何在 #pragma parallel for 循环结束时组合。

//s is a vector of sol objects which contain apart from other variables an  integer     score    variable s[].score

typedef struct {
  int score;
  int ant;
} best_t;

best_t best = { 0, 0 };

// we declare our user reduction operator :
// it is called get_max, return a a value of type best_t.
// omp_out and omp_in are the predefined names of two private elements
// to combine in the end to the final shared variable.

#pragma omp declare reduction(get_max : best_t :\
    omp_out = omp_out.score > omp_in.score ? omp_out : omp_in)\
    initializer (omp_priv=(omp_orig))

                
#pragma omp parallel 
{//start parallel session
    #pragma omp for    nowait reduction(get_max : best)
    for (int ant = 0; ant<maxsols; ++ant) // for all ants
    {
        //procedures on s[ant] object which update the  int s[ant].score
        if (s[ant].score > best.score)
        {
            //find the object with the highest score
            best.score = s[ant].score;
            best.ant = ant;
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-09
    • 1970-01-01
    • 2016-08-28
    • 2011-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-09
    相关资源
    最近更新 更多