【问题标题】:Why is parallelization with openmp slower on some machines为什么在某些机器上使用 openmp 的并行化速度较慢
【发布时间】:2012-04-12 14:19:09
【问题描述】:

我正在开发一个可以并行运行以提高速度的数值模拟。我通常多次运行模拟,然后对各个结果进行平均。这个循环,多次运行,使用 openmp 并行化:

    // set the number of threads
    omp_set_num_threads (prms.nthreads);

#pragma omp parallel if(prms.parallel) shared(total) private(iRun)
    {
#pragma omp for schedule(dynamic)
        for (iRun = 1; iRun <= prms.number_runs; iRun++)
        {
            // perform the simulation
        }
    }

实际上没有共享变量,除了total,它是一个大小为iRun 的数组,其中每个元素保存相应运行的结果。到目前为止,在我测试的所有机器上,速度都与内核数量成正比;所以使用 4 个线程比没有并行化快 4 倍。但是,在我们的计算集群上,情况并非如此(第二次运行是并行化并使用 2 个线程,因此速度应该是原来的两倍):

$ time hop ...

real    0m50.595s
user    0m50.484s
sys 0m0.088s

$ time hop ... -P

real    1m35.505s
user    3m9.238s
sys 0m0.134s

如您所见,并行计算比串行计算慢得多,即使总体而言也是如此。我确信这不是内存问题,并且计算机具有多个内核。

可能是什么问题?可能是openmp实现吗?还是系统中的某些内容配置错误?我真的不知道要找什么。

【问题讨论】:

  • 实际上,我看到的是您的集群实现 real、user 和 sys 报告的时间高于测试机器上的相应值。当你使用办公室墙上的时钟时,你会得到什么时间?或者,也许更重要的是,如果你在程序的开始和结束处插入对时钟例程的调用,你会得到什么时间?
  • 两次运行都在同一台机器上,我只设置了一次 -P 标志,使程序并行运行。第二次运行真的/感觉更长。例如,在我的笔记本电脑上,第二次运行大约需要 25 或 30 秒,比第一次快两倍……
  • 您的模拟是否执行大量 I/O 操作?在并行运行期间,您的线程是否不断地从一个内核跳到另一个内核?您的计算是否涉及随机数生成(这可以解释为什么您需要多次运行它)?如果是这样,您如何生成所有这些数字? (取决于你如何做事,可能有一个隐藏的共享变量)。
  • 你确定两台机器上的随机数生成库是一样的吗?
  • 您能否为所有线程使用不同的 RNG 实例(使用 gsl_rng_alloc)并重做您的计时以查看是否有变化?

标签: parallel-processing openmp


【解决方案1】:

缓存一致性似乎是个问题。如果total 是您的共享数组,并且每个线程在total 中更新自己的单元格,由于线程正在动态挑选工作,因此线程很可能必须更新total 中的相邻值,这可能在相同的缓存行。

在您的测试机器上,这可能不会造成太大伤害,因为total 在共享 L3 中可能是连贯的,但在需要通过网络来回传输的集群中,这应该会造成伤害。

【讨论】:

    【解决方案2】:

    由于我没有足够的声誉,我将其添加为答案而不是评论:

    您是否确保为不同的模拟同时初始化数据而不是串行?

    我知道这可能会产生巨大的差异,具体取决于您的架构。也许您可以提供有关架构的提示。

    准确地说: 如果你这样做了

    for(i = 1; i < prms.number_runs; ++i)
       allocAndInitializeSimulationData( i )
    
    #pragma omp parallel if(prms.parallel) shared(total) private(iRun)
    {
    #pragma omp for schedule(dynamic)
        for (iRun = 1; iRun <= prms.number_runs; iRun++)
        {
            // perform the simulation
        }
    }
    

    这可能比

    慢得多
    #pragma omp parallel if(prms.parallel) shared(total) private(iRun)
    {
       #pragma omp for schedule(dynamic)
       for(i = 1; i < prms.number_runs; ++i)
          initializeAndAllocSimulation( i )
    
       #pragma omp for schedule(dynamic)
       for (iRun = 1; iRun <= prms.number_runs; iRun++)
       {
          // perform the simulation
       }
    }
    

    【讨论】:

    • 我按照我的问题的 cmets 中的说明解决了这个问题。还是谢谢。
    猜你喜欢
    • 1970-01-01
    • 2017-04-10
    • 1970-01-01
    • 2011-07-20
    • 2020-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多