我如何知道在 OpenMP 中"为指令"完成了多少工作?



我想知道使用 OpenMP 的 for 循环的进度。我知道减少指令不起作用,但我是这样写的:

#pragma omp for reduction (+:sum)
    for (int i=0; i < size; i++){
    // do something that takes about 10seconds 
    sum++;
#pragma omp critical
    cout << sum << " / " << size << endl; 
    }

这将返回如下内容:

1 / 100
1 / 100
2 / 100
1 / 100
...

但我想要这个:

1 / 100
2 / 100
3 / 100

. ..

有没有办法在指令reduction期间获得正确的sum值?还是我应该使用其他方法?

reduction 子句具有非常明确定义的含义,在最新 OpenMP 标准的第 2.9.3.6 节中有详细说明。我怀疑您是否能够将其用于上述目的。

无论如何,只需对源代码稍作修改即可实现该行为:

sum = 0
#pragma omp for shared(sum) schedule(guided)
for (int i=0; i < size; i++){
    // do something that takes about 10seconds 
#pragma omp critical(PRINT)
    {
      sum++;
      cout << sum << " / " << size << endl;     
    }
}

通过这种方式,您可以确保一次只有一个线程尝试增加"总和"并将其打印在屏幕上。鉴于每次迭代需要很长时间,这种同步不应引起性能问题。

你应该使用另一种方法。缩减会创建一个线程私有变量(在您的情况下sum),它仅在所有线程加入时结束时减少。减少与实施高度相关。它可以等待所有线程完成,它可以在线程完成时减少,它可以创建一个缩减树,等等。

相反,为了跟踪进度,您可以有另一个变量numDone,每个线程原子增加。

编辑

维基百科解释得很好:

reduction(operator | ininsic : list):变量有一个本地副本 在每个线程中,但将汇总本地副本的值 (缩减)为全局共享变量。

为了避免通信的需要(通过更新共享计数器),您可以打印出线程编号以及到目前为止已处理的项目数,即

#pragma omp parallel
{
   int count = 0;
#pragma omp for schedule(dynamic)           // or whatever schedule you want
  for(int i=0; i<size; ++i) {
    // ...
    printf("@ %d: done %d loopsn",
           omp_get_thread_num(),++count);   // should not need a critical section
  }
}

在您的特定情况下,由于工作大约需要 10 秒,因此任何通信都不重要,但使用动态时间表可能是值得的,特别是如果工作在不同i之间可能有所不同。

最新更新