我正在开发一种可以并行运行以提高速度的数值模拟。我通常多次运行模拟,然后对各个结果进行平均。这个循环,多次运行,使用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实现吗?或者系统中的某些内容是否配置错误?我真的不知道该找什么。
答案 0 :(得分:0)
缓存一致性似乎是一个问题。如果total
是您的共享数组,并且每个线程都在total
中更新自己的单元格,由于线程正在动态选择工作,因此线程很可能必须更新{{1}中的相邻值这可能在同一个缓存行中。
在您的测试计算机上,这可能不会造成太大伤害,因为total
可能在共享L3中是连贯的,但在群集中,它需要在网络上来回传递,这应该是伤。
答案 1 :(得分: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
}
}