【问题标题】:OpenMP in Ubuntu: parallel program works on double core processor in two times slower than single-threaded. Why?Ubuntu 中的 OpenMP:并行程序在双核处理器上运行,比单线程慢两倍。为什么?
【发布时间】:2011-08-08 11:48:36
【问题描述】:

我从wikipedia得到代码:

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

#define N 100

int main(int argc, char *argv[])
{
  float a[N], b[N], c[N];
  int i;
  omp_set_dynamic(0);
  omp_set_num_threads(10); 


  for (i = 0; i < N; i++)
  {
      a[i] = i * 1.0;
      b[i] = i * 2.0;
  }

#pragma omp parallel shared(a, b, c) private(i)
  {
#pragma omp for
    for (i = 0; i < N; i++)
      c[i] = a[i] + b[i];
  }
  printf ("%f\n", c[10]);
  return 0;
}

我尝试使用 gcc4.5(我的配置:Intel C2D T7500M 2.2GHz,2048Mb RAM)在我的 Ubuntu 11.04 中编译和运行它,该程序的运行速度比单线程慢两倍。为什么?

【问题讨论】:

  • omp_set_num_threads(10) 和“双核”并不是一个好的组合(很多上下文切换对任何事情都没有好处)。除此之外,请参阅this answer to a related question
  • 你可能想看看this question接受的答案。

标签: performance gcc ubuntu openmp


【解决方案1】:

非常简单的答案:增加 N。并将线程数设置为等于您拥有的处理器数。

对于您的机器,100 是一个非常低的数字。尝试更高几个数量级。

另一个问题是:您如何测量计算时间?通常需要花费程序时间来获得可比较的结果。

【讨论】:

    【解决方案2】:

    我想编译器在非 smp 情况下优化了 for 循环(例如使用 SSE 指令),而在 OMP 变体中却不能。

    使用 gcc -S(或 objdump -S)查看不同变体的程序集。

    无论如何,您可能需要注意共享变量,因为它们需要同步,这会使事情变得非常缓慢。如果您可以“智能”块(查看 schedule pragma),您可能会减少争用,但同样:

    • 验证发出的代码
    • 个人资料
    • 不要低估单线程代码的效率(因为缓存局部性和缺乏上下文切换)
    • 将线程数设置为 CPU 数(让 openMP 为您决定!);除非您的线程团队有一个具有专用任务的主线程,在这种情况下,分配一个额外的线程可能是有价值的

    在我尝试应用 OMP 进行并行化的所有情况下,大约 70% 的情况较慢。明确加速的情况是

    • 粗粒度平行度(您的样品处于光谱的细粒度端)
    • 没有共享数据

    【讨论】:

      【解决方案3】:

      您面临的问题是错误的内存共享。每个线程都应该有自己的私有 c[i]。

      试试这个:#pragma omp parallel shared(a, b) private(i, c)

      【讨论】:

        【解决方案4】:

        运行下面的代码,看看有什么不同。

        1.) OpenMP 有开销,因此运行时必须超过开销才能看到好处。

        2.) 不要自己设置线程数。一般来说,我使用默认线程。但是,如果您的处理器具有超线程,则可以通过将线程数设置为等于内核数来获得更好的性能。使用超线程,默认线程数将是内核数的两倍。例如,在我的机器上,我有四个内核,默认线程数是八个。通过将其设置为 4,在某些情况下我会得到更好的结果,而在其他情况下我会得到更差的结果。

        3.) 在 c 中存在一些错误共享,但只要 N 足够大(它需要克服开销),错误共享不会造成太大问题。您可以使用块大小,但我认为这不会有帮助。

        4.) 缓存问题。您至少有四个内存级别(这些值适用于我的系统):L1 (32Kb)、L2(256Kb)、L3(12Mb) 和主内存 (>>12Mb)。随着您进入更高级别,并行性的好处将会减少。但是,在下面的示例中,我将 N 设置为 1 亿个浮点数,即 4 亿字节或大约 381Mb,使用多线程仍然明显更快。尝试调整N 看看会发生什么。例如,尝试将N 设置为缓存级别/4(一个浮点数为 4 字节)(数组 a 和 b 也需要在缓存中,因此您可能需要将 N 设置为缓存级别/12)。但是,如果 N 太小,您将与 OpenMP 开销作斗争(这是您问题中的代码所做的)。

        #include <stdio.h>
        #include <omp.h>
        
        #define N 100000000
        
        int main(int argc, char *argv[]) {
            float *a = new float[N];
            float *b = new float[N];
            float *c = new float[N];
        
            int i;
            for (i = 0; i < N; i++) {
                a[i] = i * 1.0;
                b[i] = i * 2.0;
            }
            double dtime;
            dtime = omp_get_wtime();
            for (i = 0; i < N; i++) {
                c[i] = a[i] + b[i];
            }
            dtime = omp_get_wtime() - dtime;
            printf ("time %f, %f\n", dtime, c[10]);
        
            dtime = omp_get_wtime();
            #pragma omp parallel for private(i)
            for (i = 0; i < N; i++) {
                c[i] = a[i] + b[i];
            }
            dtime = omp_get_wtime() - dtime;
            printf ("time %f, %f\n", dtime, c[10]);
        
            return 0;
        }
        

        【讨论】:

          猜你喜欢
          • 2023-04-03
          • 2019-02-20
          • 1970-01-01
          • 2023-03-28
          • 2021-03-27
          • 2019-10-15
          • 1970-01-01
          • 1970-01-01
          • 2021-06-18
          相关资源
          最近更新 更多