/* this include file is mandatory */ #include /* MPI sample program; NOT INTENDED TO BE EFFICIENT as a prime finder, either in algorithm or implementation MPI (Message Passing Interface) is a popular package using the "message passing" paradigm for communicating between processors in parallel applications; as the name implies, processors communicate by passing messages using "send" and "receive" functions finds and reports the number of primes less than or equal to N each node works on a range of Chunk numbers at a time, testing them for primeness by straight division; if a potential divisor has already been found to be composite (i.e. nonprime), then we skip it */ #define MAX_N 1000000 #define NEW_MSG 0 /* type of message containing the new composites */ #define COUNT_MSG 0 /* type of message containing the local composite count */ int NNodes, /* number of nodes in computation*/ N, /* find all primes from 2 to N */ Chunk, /* chunk size */ Block, /* number of integers checked in each iteration */ Me, /* my node number */ Composite[MAX_N], /* "global" array of composites found so far, code 1 for composite, 0 otherwise */ NNew, /* number of new composites found in this iteration*/ New[MAX_N], /* new composites found (first component is NNew */ MyComposites = 0; /* total number of composites my node has found, in all iterations so far */ double T1,T2; /* start and finish times */ Init(Argc,Argv) int Argc; char **Argv; { int DebugWait; /* mandatory to begin any MPI program */ MPI_Init(&Argc,&Argv); /* do not access command-line arguments until after MPI_Init() is called */ N = atoi(Argv[1]); Chunk = atoi(Argv[2]); DebugWait = atoi(Argv[3]); /* this loop is there to synchronize all nodes for debugging */ while (DebugWait) ; /* C library function for convenient initialization to 0 */ bzero(Composite,MAX_N*sizeof(int)); /* puts the number of nodes in NNodes */ MPI_Comm_size(MPI_COMM_WORLD,&NNodes); /* puts the node number of this node in Me */ MPI_Comm_rank(MPI_COMM_WORLD,&Me); Block = NNodes * Chunk; /* if N is not an even multiple of Block, then leave, and have node 0 explain why (we don't want all nodes to print out redundant versions of this message) */ if (N % Block > 0) { if (Me == 0) printf("N must be divisible by Block\n"); exit(1); } /* OK, get started; first record current time in T1 */ if (Me == 0) T1 = MPI_Wtime(); } int IsComposite(K) /* returns 1 if K is found to be composite */ int K; { int J; for (J = 2; J*J <= K; J++) { /* if J is known to be composite, don't bother dividing by it */ if (!Composite[J]) if (K % J == 0) return 1; } return 0; } void UpdateComposite() /* receive the lists of newly-discovered composites and update my copy of the array */ { int Node,Them,I,Error; MPI_Status Status; for (Node = 0; Node < NNodes; Node++) { if (Node != Me) { /* MPI_Recv -- receive a message parameters: pointer to place to store message number of items in message (see notes on this at the end of this file) item type accept message from which node(s) message type ("tag"), programmer-defined; here it 0, so we are telling MPI to wait until a message of type 0 comes in (all others will be queued) node group number (in this case all nodes) status (see notes on this at the end of this file) */ Error = MPI_Recv(New,Chunk,MPI_INT,MPI_ANY_SOURCE,NEW_MSG, MPI_COMM_WORLD,&Status); MPI_Get_count(&Status,MPI_INT,&NNew); for (I = 0; I < NNew; I++) Composite[New[I]] = 1; } } } PerformIterations() { int First,Last,Iter,NIters,I,Node,NNew,Error; First = 1 + Me * Chunk; Last = First + Chunk - 1; NIters = N / Block; for (Iter = 0; Iter < NIters; Iter++) { NNew = 0; for (I = First; I <= Last; I++) if (IsComposite(I)) { New[NNew++] = I; Composite[I] = 1; MyComposites++; } /* now send all our newfound composites to all the other nodes; we could use MPI_BROADCAST() for this, but not with any appreciable gain in speed, since MPI will still send out separate messages to each node (except in a special implementation), so we will do this explicitly: */ for (Node = 0; Node < NNodes; Node++) if (Node != Me) /* MPI_Send -- send a message parameters: pointer to place where message is to be drawn from number of items in message item type destination node message type ("tag") programmer-defined; here we are sending a message of type 0, which we will signify a list of new composities node group number (in this case all nodes) */ Error = MPI_Send(New,NNew,MPI_INT,Node,NEW_MSG,MPI_COMM_WORLD); UpdateComposite(); First += Block; Last += Block; } } WrapUp() { int Count,Node; MPI_Status Status; /* if not node 0, send node 0 our composite counts; if node 0, then receive and process them; note we have called this message type 1 */ if (Me != 0) MPI_Send(&MyComposites,1,MPI_INT,0,COUNT_MSG,MPI_COMM_WORLD); else { Count = MyComposites; for (Node = 1; Node