/*
* lbpi_q.c
*
* load balanced version of PI
*
* computes pi by a Montecarlo method
* state of computation can be queried
*
* usage:
*
* lbpi <no_blocks> <blocksize>
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/utsname.h>
#include <mpi.h>
#include <strings.h>
#include <sys/types.h>
#include "query.h"
#define TAG_WORK 1
#define TAG_RESULT 2
#define TAG_INFO 3
#define DEFAULT_N_BLOCKS 10 /* default number of blocks */
#define DEFAULT_BLOCKSIZE 200000 /* number of iterations per block */
#define MASTER 1
#define SERVER 0
char port_name[MPI_MAX_PORT_NAME];
/*
* auxiliary routines
*/
long calc(long total) {
/*
* compute total random points in the unit square
* and return the number of hits in the sector (x*x + y*y < 1)
*/
double x, y; /* random coordinates */
long hits = 0; /* number of hits */
int i;
for(i=0; i<total; i++) {
x = ((double) rand())/RAND_MAX;
y = ((double) rand())/RAND_MAX;
if ( x*x + y*y <= 1.0 ) {
hits++;
}
}
return(hits);
}
/*
* task routines
*/
void master(int argc, char *argv[], int nslaves) {
long n_blocks; /* total number of blocks */
long blocksize; /* no. of points per block */
long blockcount; /* no. of blocks left */
long server_info[4];
long hits; /* number of hits per process */
long totalhits = 0; /* total number of hits */
int slaveid;
double pi;
MPI_Status status;
int i;
/* get total work and work per job */
if (argc != 3) {
n_blocks = DEFAULT_N_BLOCKS;
blocksize = DEFAULT_BLOCKSIZE;
} else {
n_blocks = atol(argv[1]);
blocksize = atol(argv[2]);
}
blockcount = n_blocks;
/* start with one block per slave (assuming nproc < n_blocks!) */
for (i=2; i<2+nslaves; i++) {
MPI_Send(&blocksize, 1, MPI_LONG, i, TAG_WORK, MPI_COMM_WORLD);
}
blockcount -= nslaves;
/* receive results and send additional blocks */
while (blockcount > 0) {
MPI_Recv(&hits, 1, MPI_LONG, MPI_ANY_SOURCE, TAG_RESULT,
MPI_COMM_WORLD, &status);
slaveid = status.MPI_SOURCE;
if (slaveid == SERVER) { /* send status info to server task */
server_info[0] = blocksize;
server_info[1] = n_blocks;
server_info[2] = n_blocks - blockcount;
server_info[3] = totalhits;
MPI_Send(&server_info, 4, MPI_LONG, slaveid, TAG_INFO, MPI_COMM_WORLD);
} else { /* send new work to slave task */
totalhits += hits;
MPI_Send(&blocksize, 1, MPI_LONG, slaveid, TAG_WORK, MPI_COMM_WORLD);
blockcount--;
}
}
/* get last results */
for (i = 2; i < 2+nslaves; i++) {
MPI_Recv(&hits, 1, MPI_LONG, MPI_ANY_SOURCE, TAG_RESULT,
MPI_COMM_WORLD, &status);
totalhits += hits;
}
/* print result */
pi = 4 * totalhits/(double)(n_blocks * blocksize);
printf("\nPI = %lf\n", pi);
return;
}
void slave(int myid) {
long mytotal; /* no. of points per block */
long myhits; /* no. of hits per block */
MPI_Status status;
/* initialize random generator */
srand(getpid());
/* get work from master */
do {
MPI_Recv(&mytotal, 1, MPI_LONG, MASTER, MPI_ANY_TAG,
MPI_COMM_WORLD, &status);
/* compute partial result */
myhits = calc(mytotal);
/* send result to master */
MPI_Send(&myhits, 1, MPI_LONG, MASTER, TAG_RESULT, MPI_COMM_WORLD);
}
while (1);
return; /* never returns */
}
void query_server(void) {
/* waits for query client and provides it with status info */
MPI_Comm servcomm;
long infos[4];
MPI_Status status;
MPI_Open_port(MPI_INFO_NULL, port_name);
MPI_Publish_name(SERVICE_NAME, MPI_INFO_NULL, port_name);
printf("server: ready\n");
while (1) {
MPI_Comm_accept(port_name, MPI_INFO_NULL, 0, MPI_COMM_SELF, &servcomm);
printf("server: connection established\n");
/* get infos from master */
MPI_Send(infos, 1, MPI_LONG, MASTER, TAG_RESULT, MPI_COMM_WORLD);
MPI_Recv(infos, 4, MPI_LONG, MASTER, TAG_INFO, MPI_COMM_WORLD, &status);
/* send infos to client and disconnect */
MPI_Send(infos, 4, MPI_LONG, 0, 0, servcomm);
MPI_Comm_disconnect(&servcomm);
printf("server: disconnected\n");
}
}
/*
* main program
*/
void main(int argc, char *argv[]) {
int myid, nproc;
/* start MPI */
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
MPI_Comm_size(MPI_COMM_WORLD, &nproc);
if (myid == MASTER) {
master(argc, argv, nproc - 2);
} else if (myid == SERVER) {
query_server();
}else {
slave(myid);
}
/* leave MPI the hard way */
MPI_Unpublish_name(SERVICE_NAME, MPI_INFO_NULL, port_name);
MPI_Abort(MPI_COMM_WORLD, 0);
}