1

我正在开发一个可以并行运行以提高速度的数值模拟。我通常多次运行模拟,然后对各个结果进行平均。这个循环,多次运行,使用 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实现吗?还是系统中的某些内容配置错误?我真的不知道要找什么。

4

2 回答 2

0

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

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

于 2012-04-20T05:46:21.113 回答
0

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

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

我知道这会根据您的架构产生巨大的影响。也许您可以提供有关架构的提示。

准确地说:如果你这样做

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
   }
}
于 2012-09-28T18:06:48.097 回答