2

我正在启动一个通过 OpenMP 并行化的给定问题。它对处理大量数据的同一段代码运行给定次数的迭代。处于应用 OpenMP 的那个级别,使每个线程处理一个子卷。每个迭代都应该具有相同的工作负载,以及每个子卷。

当使用 ICC 编译时,迭代的持续时间总是与预期的相同。但奇怪的是:当使用 GCC 编译时,每次迭代的时间开始增加,达到最大值,然后再次减少,直到达到稳定的给定值。没有 OpenMP 编译的相同程序在使用 ICC 或 GCC 时没有区别。

有没有人在这些编译器中观察到 OpenMP 中的这种行为?

[编辑 1]:指导和静态调度策略已经过测试。

[编辑 2]:代码看起来有点像这样:

 #pragma omp parallel for schedule(static) private(i,j,k)
 for(i = 0; i < N; i++)
    for(j = 0; j < N; j++)
       for(k = 0; k < N; k++){
            a[ k+j*N+i*NN] =  0.f;
            b[ k+j*N+i*NN] =  0.f;
            c[ k+j*N+i*NN] =  0.f;
            d[ k+j*N+i*NN] =  0.f;
  }
 for( t = 0; t  < T; t+=dt){
   /* ... change some discrete values in a,b,c .... */
   /*       and propagate changes                   */    
  #pragma omp parallel for schedule(static) private(i,j,k)
    for(i = 0; i < N; i++)
       for(j = 0; j < N; j++)
          for(k = 0; k < N; k++){
            d[ k+j*N+i*NN ] = COMP( a,b,c,k+j*N+i*NN );
      }
  }

其中 COMP 在 k+j*N+i*NN (以及它们的一些邻居)位置对 a、b、c 中的值进行某种线性应用。关键是 GCC 和 ICC 中的这段代码导致了我描述的问题。关键是我发现我将 a,b,c,d 的初始化更改为 0.0f (f.ex, 0.5f) 以外的某个值,即不会发生每个时间步所花费的时间增加的事情。

[编辑 3]:似乎不是 GOMP 的错。禁用 OpenMP 时也会发生同样的情况。再一次,使用 ICC(没有或使用 openmp)根本不会发生。有什么办法可以关闭这个线程吗?

4

1 回答 1

1

可能是,COMP 正在执行一些 非正规操作,这些操作是在软件中完成的,而不是在硬件中完成的。

与清零模式(当每个非正规都舍入为零时)相比,处理非正规可以改变运行时间。在公平地进行非规范化计算的编译器中将有更多工作要做。迭代之间的工作量可能会有所不同。

默认情况下,英特尔编译器禁用非规范化操作,并在任何-O级别(-O0、-O1、-O2 等)设置刷新为零和非规范化为零。

要打开非规范化,请使用:-no-ftzintel 编译器(docs1) (docs2)的选项,或者可能是-fp-model precise

GCC中,denormals-are-zero 仅由 -ffast-math选项打开,该选项不由任何-O1, -O2, -O3: (grep a -ffast-math)设置。包括不规范的-ffast-math忽略(bug36821,comment#1)

所以,如果你在 COMP 中有很多非规范化,ICC 会忽略它们为零,而 GCC 会做很多软件处理。

非规范化可能不是这种情况,但其他浮点处理差异是。

于 2012-01-23T21:03:58.857 回答