OpenMP:并行程序不是更快(或不是非常快)然后串行。我究竟做错了什么?

时间:2012-04-10 15:49:12

标签: c performance gcc openmp

看看这段代码:

#include <stdio.h>
#include <omp.h>

int main()
{
    long i, j;

    #pragma omp for
    for(i=0;i<=100000;i++)
    {
        for(j=0;j<=100000;j++)
        {
            if((i ^ j) == 5687)
            {
                //printf("%ld ^ %ld\n", i, j);
                break;
            }
        }
    }
}

所以,结果:

robotex@robotex-work:~/Projects$ gcc test.c -fopenmp -o test_openmp
robotex@robotex-work:~/Projects$ gcc test.c -o test_noopenmp
robotex@robotex-work:~/Projects$ time ./test_openmp
real    0m11.785s
user    0m11.613s
sys 0m0.008s
robotex@robotex-work:~/Projects$ time ./test_noopenmp

real    0m13.364s
user    0m13.253s
sys 0m0.008s
robotex@robotex-work:~/Projects$ time ./test_noopenmp

real    0m11.955s
user    0m11.853s
sys 0m0.004s
robotex@robotex-work:~/Projects$ time ./test_openmp

real    0m15.048s
user    0m14.949s
sys 0m0.004s

怎么了?为什么OpenMP程序更慢?我该如何纠正?

我使用OS Ubuntu在多台计算机(工作中的Intel Core i5,家中的Intel Core2Duo T7500)上测试了它,并且总是得到相同的结果:OpenMP不会显着提高性能。

我还测试了维基百科的例子并得到了相同的结果。

1 个答案:

答案 0 :(得分:17)

您的代码中存在两个问题:

  1. 你错过了pragma中的parallel。所以它只使用1个线程。
  2. 您在j上遇到竞争条件,因为它已声明在并行区域之外。

  3. 首先,您需要parallel来实际并行运行OpenMP:

    #pragma omp parallel for
    

    其次,您在并行区域外声明j。这将使它在所有线程之间共享。所以所有线程都在并行区域内读取和修改它。

    因此,您不仅具有竞争条件,而且所有失效导致的缓存一致性流量正在扼杀您的表现。

    您需要做的是为每个帖子设置j本地。这可以通过以下任一方式完成:

    1. 在并行区域内声明j
    2. 或者将private(j)添加到pragma:#pragma omp parallel for private(j)
      (正如@ArjunShankar在评论中指出的那样)

    3. 请改为尝试:

      int main()
      {
          double start = omp_get_wtime();
      
          long i;
      
      #pragma omp parallel for
          for(i=0;i<=100000;i++)
          {
              long j;
              for(j=0;j<=100000;j++)
              {
                  if((i ^ j) == 5687)
                  {
                      //printf("%ld ^ %ld\n", i, j);
                      break;
                  }
              }
          }
      
          double end = omp_get_wtime();
      
          printf("%f\n",end - start);
          return 0;
      }
      

      No OpenMP:            6.433378
      OpenMP with global j: 9.634591
      OpenMP with local j:  2.266667