我编写了一个混合的OpenMP / MPI程序,它基本上通过MPI将for(){...}
循环的迭代分发到非共享内存系统。在一台机器中,我使用静态计划专门调用openMP。
我的代码抽象地如下所示:
#pragma omp parallel for schedule(static) collapse(2) nowait
for(j=1;j>-2;j-=2){
for(i=0;i<n;i++){
... // nested loop code here
}
}
我将MATLAB上完全相同的代码段的运行时间与parfor
循环进行了比较,并且使用C
代码使运行时间始终减慢了30%。
我希望C
代码的运行时间至少相等。
我通过shell函数time
监视运行时间,如下所示
time matlab script.m
time mpirun -np 1 --bind-to none -x OMP_NUM_THREADS=32 ./script
我正在使用openmp 3.1和gcc 4.7.3以及openMPI v1.10.3
我在openMPI中使用--bind-to none
选项调用该程序,为openMP调用OMP_PROC_BIND=TRUE
有什么想法会发生这种情况吗?
假设32个线程,在MATLAB中,循环如下所示:
parfor k=1:nWorkers
for j=[-1,1]
for i=1:n
... % nested loop here
end
end
end
答案 0 :(得分:1)
你的并列化循环是 for(j=1;j>-2;j-=2)
,它只是j=1
和j=-1
。因此,您只能获得两个执行n
循环的线程。我可以想象你在MATLAB中做了其他的事情,但你没有提供任何代码,所以我不能说你的MATLAB代码。
此外,您正在将MPI(只有一个线程)与openMP结合使用,您确定这是您正在寻找的吗?
答案 1 :(得分:1)
TL; DR; - 下面列出了MATLAB和C-lang的最佳实践。
(进入HPC和分布式计算领域需要一些新的自律,因为玩具变得越来越复杂,如果纯粹依赖于我们之前的纯粹,网络效应不容易解构为各自的根本原因[SERIAL]来自常见编程语言的调度经验。)
time
来认真衡量/比较性能:一旦分布式并发进程达到大量openMP线程/ MPI进程,在Amdahl's Law denominator中设置除数 N
就越多。
1
processSPEEDUP = _______________________________
( 1 - SEQ_part ) <---- CONCURRENCY MAY HELP
SEQ_part + _________________
^^^ N <---- CONCURRENCY HARNESSED
|||
SEQ____________________________________ CONCURRENCY IMMUNE PART
预期应该是现实的:
永远不要使用shell时间来认真测量/比较性能:
一旦分布式并发进程达到大量openMP线程/ MPI进程,在Amdahl定律分母中设置除数 N
就越多。
1
processSPEEDUP = ___________________________________
( 1 - SEQ_part ) <-- CONCURRENCY MAY HELP
SEQ_part + _________________ + CoST
^^^ N ^^^
||| ^ |||
||| | |||
||| +------------------ CONCURRENCY HARNESSED
||| |||
||| ||| A GAIN WITHOUT PAIN?
||| |||
||| ||| NEVER, SORRY,
||| ||| COMMUNISM DOES NOT WORK,
||| ||| ALL GOT AT THE COST OF
||| +++----- COSTS-OF-ALL-OVERHEADS
||| ++++++++++++++++++++++
||| +N job SETUPs
||| +N job DISTRIBUTIONs
||| +N job COLLECT RESULTs
||| +N job TERMINATIONs
|||
|||
SEQ____________________________________ CONCURRENCY IMMUNE PART
For more details on the impacts from add-on costs-of-overheads, may like to read this,或者可以直接进入一个交互式GUI工具,用于基于现实,量化的基于现实的插图,说明任何数量的CPU将如何加速“昂贵“分布式作业,在this post, where SPEEDUPs are shown
WHY they actually turn out to become SLOWDOWNs, on any amount of N
Q.E.D.的预告片部分中引用。
另外还有一些关于实际约束的更多细节(与线程模型相关,与硬件域相关,特定于NUMA),它们共同决定了所产生的调度以及这种声明的执行流程的可实现的加速:
独立于细节如何通过分布式处理并发加速进程,此处讨论了测量质量。
系统中可用的任何高分辨率计时器。作为快速模拟的例子,可以:
#include <time.h>
struct timespec {
time_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
timespec diff( timespec start, timespec end ) {
timespec temp;
if ( ( end.tv_nsec - start.tv_nsec ) < 0 ) {
temp.tv_sec = end.tv_sec - start.tv_sec - 1;
temp.tv_nsec = end.tv_nsec - start.tv_nsec + 1000000000;
} else {
temp.tv_sec = end.tv_sec - start.tv_sec;
temp.tv_nsec = end.tv_nsec - start.tv_nsec;
}
return temp;
}
// /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
struct timespec start_ts, end_ts, duration_ts;
clock_gettime( CLOCK_THREAD_CPUTIME_ID, &start_ts );
// clock_gettime( CLOCK_PROCESS_CPUTIME_ID, &start_ts );
// clock_gettime( CLOCK_MONOTONIC, &start_ts );
// ____MEASURED-SECTION_START____________________
...
..
.
// ____MEASURED-SECTION_END______________________
clock_gettime( CLOCK_THREAD_CPUTIME_ID, &end_ts );
// clock_gettime( CLOCK_PROCESS_CPUTIME_ID, &end_ts );
// clock_gettime( CLOCK_MONOTONIC, &end_ts );
// _____SECTION__________
// duration_ts = diff( start_ts, end_ts );
// \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
tic; ...; delta = toc;
MathWorks技术文章对此主题的论述非常明确:
总之,使用
tic
和toc
来测量MATLAB中的经过时间,因为这些函数具有最高的准确性和最可预测的行为。基本语法是
tic;
... % … computation …
..
.
toc;
MATLAB识别
tic
和toc
行以获得最小开销。