背景:我的任务是用 C 语言编写一个 MPI 程序,用于计算给定数字之前的所有素数。该程序运行正确。
我使用 openmpi 和 -O3 优化编译程序。
当使用 1 个进程在我的个人计算机 (Ubuntu 11.10 x64) 上运行它时,我得到了预期的结果(对于 4E9 之前的所有素数大约需要 13 秒)。我CS部门的机器也是如此。
但是,当我在 NERSC 的 Carver 上运行它时,时间急剧跳跃(1 个进程约 61 秒)。
我尝试过使用 openmpi 和 intel 编译器......没有区别。我让它以正确的时间运行一次,但我不记得我做了什么(如果有的话)不同,并且我的代码中有一个轻微的索引错误,我已经修复了(与实际执行计算无关,所以时间是准确的)。
我已经尽量说得清楚;如果您还有其他问题,我很乐意回答。谢谢!
#include <stdio.h>
#include <mpi.h>
#include <stdlib.h>
#include <math.h>
#define MAX(x,y) ((x)>(y) ? (x) : (y) )
#define MIN(x,y) ((x)>(y) ? (y) : (x) )
#define A(i,j) A[(i)*M+j]
#define b(i) b[i]
#define c(i) c[i]
long* preamble(long N,char* mark){
N = sqrt(N)+1;
long size;
long curr, index;
long i, j,n;
long count;
long* primes;
//Pierre Dusart proven upper bound for number of primes up to N
//found at http://primes.utm.edu/howmany.shtml
size = (N/log(N))*(1+(1.2762/log(N)))*sizeof(long);
primes = (long *)malloc(size);
if(N%2)
n=N/2 - 2;
else
n=(N-1)/2 -1;
index = 0;
curr = 3;
while (curr*curr<=N) {
for (i=(curr*curr-3)/2; i<=n; i+=curr){
mark[i]=1;
}
while (mark[++index]) ;
curr = index*2+3;
}
/*number of primes*/
count = 0;
for(i = 0; i <=n; i+=1){
if(mark[i] == 0) {
primes[++count]=i*2+3;
}
}
primes[0]=count;
return primes;
}
long FMIB(long p, long b){
if(b%p==0 && b!=p) return b;
long i = b + p - b % p;
if(i%2){return i;}else{return i+p;}
}
int main(int argc, char **argv) {
long N = 4000000000;
long BKSIZE = 500000;
char *mark;
long *primes;
long *loopprimes;
long size, offset;
long numprimes;
long i, j, n, ii, start, index;
long count, total;
double time;
if ( argc > 1 ) N = atol(argv[1]);
if ( argc > 2 ) BKSIZE = atol(argv[2]);
int id, p;
BKSIZE = (BKSIZE-3)/2 +1;
if(N%2)
n=N/2 - 2;
else
n=(N-1)/2 -1;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &id);
MPI_Comm_size(MPI_COMM_WORLD, &p);
MPI_Barrier(MPI_COMM_WORLD);
if(id==0) time = MPI_Wtime();
size = (n/p+1)*sizeof(char);
mark = (char *)malloc(size);
for (i=1; i<=n/p+1; i++){
mark[i]=0;
}
primes = preamble(N,mark);
if(id!=0){
for (i=0; i<=n/p+1; i++){
mark[i]=0;
}
}
offset = (1+n/p)*id;
numprimes=primes[0];
if(id==0){
start = (sqrt(N)-3)/2+1; //mark index to start at
}else{
start = offset;
}
//MAIN COMPUTATION - BLOCKING
for(ii=start; ii<=MIN(ii+BKSIZE,offset+n/p); ii+=BKSIZE){
for(j=0; j < numprimes; j++){
for(i=(FMIB(primes[j+1],ii*2+3)-3)/2; i<=MIN(ii+BKSIZE,offset+n/p); i+=primes[j+1]){
mark[i-offset]=1;
}
}
}
/*number of primes*/
if(id==0){
count = 1;
}else{
count = 0;
}
for(i = 0; i <= n/p && (i+offset)*2+3 <= N; i++){
if(mark[i] == 0) {
++count;
}
}
MPI_Barrier(MPI_COMM_WORLD);
MPI_Reduce(&count, &total, 1, MPI_LONG, MPI_SUM, 0, MPI_COMM_WORLD);
MPI_Barrier(MPI_COMM_WORLD);
if(id==0){
time = MPI_Wtime() - time;
printf("There are %ld primes less than %ld\n", total, N);
printf("First three primes:");
j = 1;
printf(" %d", 2);
for ( i=0 ; i <= n && j < 3; i+=1 ) {
if (mark[i]==0){
printf(" %ld", (i*2+3));
++j;
}
}
printf("\n");
}
MPI_Barrier(MPI_COMM_WORLD);
if(id == p-1){
printf("Last three primes:");
j = 0;
for (i = n-offset; i >= 0 && j < 3; i--){
if (mark[i]==0){
printf(" %ld", ((offset+i)*2+3));
j++;
}
}
if(j < 3){
printf(" %d",2);
}
printf("\n");
}
MPI_Barrier(MPI_COMM_WORLD);
if(id == 0){
printf("Elapsed time: %f seconds\n",time);
fflush(stdout);
}
MPI_Finalize();
//free(mark);
return 0;
}
脚本:
#!/bin/csh
#used for intel compiler
#module unload pgi openmpi
#module load intel openmpi-intel mkl
make clean
make
set x = "sieve_mpi"
set n = 4000000000
set b = 500000
foreach p ( 1 2 3 4 5 6 7 8 )
cat > ${x}${p}.pbs <<EOF
#PBS -q regular
#PBS -l nodes=1:ppn=8
#PBS -l walltime=00:01:00
#PBS -N ${x}${p}
#PBS -e err/${x}${p}.err
#PBS -o out/${x}${p}.out
#used when using intel compiler
#module unload pgi openmpi
#module load intel openmpi-intel mkl
cd \$PBS_O_WORKDIR
echo ${x}
echo ${p}
mpirun -np ${p} ${x} ${n} ${b}
EOF
qsub ${x}${p}.pbs
end
生成文件:
CC = mpicc
EXEC = pi_cyc pi_block sieve_mpi
OBJS =
H_FILE =
MATHFLAG = -lm
FLAGS = -O3
SEQFLAGS = -O3
all: $(EXEC)
pi_cyc: pi_cyc.c $(OBJS) $(H_FILE)
$(CC) $(FLAGS) -o $@ pi_cyc.c $(OBJS) $(MATHFLAG)
pi_block: pi_block.c $(OBJS) $(H_FILE)
$(CC) $(FLAGS) -o $@ pi_block.c $(OBJS) $(MATHFLAG)
sieve_mpi: sieve_mpi.c $(OBJS) $(H_FILE)
$(CC) $(FLAGS) -o $@ sieve_mpi.c $(OBJS) $(MATHFLAG)
clean:
rm -f *.o *.pgm $(OBJS) $(EXEC)
你的障碍太多了,不是吗? 删除其中每一个。
如果您想测量时间,请在完成后从每个进程和 MPI_Reduce 和 MPI_MAX 中获取时间,将其排名为 0。
围绕 MPI_Reduce 的障碍毫无作用。 MPI_Reduce 是集体的,将强加任何需要的同步
您正在尝试获得排名 0 和最后一个排名来打印内容。 您能否让 0 级接收来自最后一级的这三个素数并将其与 0 级输出的其余部分一起打印出来?
编辑:抱歉,忘记回答问题了。 我认为这些障碍正在减慢你对卡弗的兴趣。