Difference between revisions of "CSC352 Homework 4 Solutions"

From dftwiki3
Jump to: navigation, search
 
Line 484: Line 484:
  
 
=Problem 3=
 
=Problem 3=
 +
<br />
 +
A good program by Danae for the MPI question.  Note the use of '''perworker''' and '''permanager''' to make sure the total number of samples adds up ''exactly'' to '''numsamples'''.  Nice touch.
 
<br />
 
<br />
 
<source lang="C">
 
<source lang="C">
 +
[352a@beowulf 352a-aa]$ cat mpiMonteCarlo4.c
 +
/* mpiMonteCarlo4.c
 +
// danae
 +
//
 +
// Computes Pi using the Monte Carlo method with MPI,
 +
// NP (user-specified) processes, and N random samples.
 +
// Note that N should be evenly divisible by NP in order
 +
// to truly calculate N samples.
 +
//
 +
// To compile and run:
 +
// mpicc -o mpiMonteCarlo4 mpiMonteCarlo4.c
 +
// mpirun -np [NP] ./mpiMonteCarlo [N]
 +
//
 +
*/
 +
 +
#include "mpi.h"
 +
#include <stdio.h>
 +
#include <stdlib.h>
 +
 +
#define MANAGER 0
 +
 +
//--------------------------------------------------------------------
 +
//                        P R O T O T Y P E S
 +
//--------------------------------------------------------------------
 +
void doManager(int,int);
 +
void doWorker();
 +
 +
//--------------------------------------------------------------------
 +
//                          M  A  I  N
 +
//--------------------------------------------------------------------
 +
int main(int argc, char *argv[]) {
 +
  int myId, noProcs, nameLen;
 +
  char procName[MPI_MAX_PROCESSOR_NAME];
 +
  int numsamples;
 +
 +
  if ( argc<2 ) {
 +
    printf( "Please Use Correct Syntax: mpirun -np [NP] ./pi2 [N]\n" );
 +
    return 1;
 +
  }
 +
 +
  // get the number of samples to generate
 +
  numsamples = atoi(argv[1]);
 +
 
 +
  //--- start MPI ---
 +
  MPI_Init(&argc, &argv);
 +
  MPI_Comm_rank(MPI_COMM_WORLD, &myId);
 +
  MPI_Comm_size(MPI_COMM_WORLD, &noProcs);
 +
  MPI_Get_processor_name(procName, &nameLen);
 +
 
 +
  //--- display which process we are on ---
 +
  printf( "Process %d of %d started.\n", myId,  noProcs);
 +
 +
  //--- farm out the work: 1 manager, several workers ---
 +
  if ( myId == MANAGER )
 +
    doManager(noProcs, numsamples);
 +
  else
 +
    doWorker();
 +
 
 +
  //--- close up MPI ---
 +
  MPI_Finalize();
 +
 
 +
  return 0;
 +
}
 +
 +
//--------------------------------------------------------------------
 +
// The manager's main work function
 +
//--------------------------------------------------------------------
 +
void doManager(int noProcs, int numsamples ) {
 +
  double incircle = 0;
 +
  double workersum;
 +
  int i;
 +
  MPI_Status status;
 +
 +
  int perworker = (1.0)*numsamples/noProcs;
 +
  int permanager = numsamples - perworker*noProcs; //manager picks up slack
 +
 +
  // printf("perworker: %d\n", perworker);
 +
  //--- first to all workers ---
 +
  for(i=1; i<noProcs; i++) {
 +
    MPI_Send( &perworker, 1, MPI_INT, i, 0, MPI_COMM_WORLD );
 +
  }
 +
 +
  //calculate manager portion
 +
  srand(time(NULL)); //seed the random number generator with time
 +
  float x, y;
 +
  for(i=0; i<permanager+perworker; i++) {
 +
    x = 1 - (((float)rand()/(float)(RAND_MAX)) * 2.0); //random float [-1,1]
 +
    y = 1 - (((float)rand()/(float)(RAND_MAX)) * 2.0); //random float [-1,1]
 +
    if ((float)x*x + (float)y*y <= (float)(1.0)) {
 +
      incircle += 1;
 +
    }
 +
  }
 +
 
 +
  //--- wait for worker sums ---
 +
  for(i=1; i<noProcs; i++) {
 +
    MPI_Recv( &workersum, 1, MPI_DOUBLE, MPI_ANY_SOURCE, 0, MPI_COMM_WORLD, &status );
 +
    incircle += workersum;
 +
  }
 +
 +
  //--- output result ---
 +
  printf( "%d iterations: Pi = %f\n", permanager + noProcs*perworker, 4.0*(incircle)/(noProcs*perworker));
 +
}
 +
 +
//--------------------------------------------------------------------
 +
// The worker's main work function
 +
//--------------------------------------------------------------------
 +
void doWorker( ) {
 +
  int numthrows, i;
 +
 +
  //--- get n from manager ---
 +
  MPI_Status status;
 +
  MPI_Recv( &numthrows, 1, MPI_INT, MPI_ANY_SOURCE, 0, MPI_COMM_WORLD, &status );
 +
 +
  //--- do portion of the work ---
 +
  double incircle = 0;
 +
  float x, y;
 +
  for (i=0; i<numthrows; i++) {
 +
    // generate random x, y as float [0,2], subtracts 1 to be in range [-1,1]
 +
    x = 1 - (((float)rand()/(float)(RAND_MAX)) * 2.0); //random float [-1,1]
 +
    y = 1 - (((float)rand()/(float)(RAND_MAX)) * 2.0); //random float [-1,1]
 +
    if ((float)x*x + (float)y*y <= (float)(1.0))
 +
      incircle += 1;
 +
  }
 +
 +
  //-- send result to manager ---
 +
  MPI_Send( &incircle, 1, MPI_DOUBLE, MANAGER, 0, MPI_COMM_WORLD );
 +
}
 +
  
 
</source>
 
</source>

Latest revision as of 14:46, 8 November 2013

--D. Thiebaut (talk) 14:41, 8 November 2013 (EST)



This section is only visible to computers located at Smith College