/* File: global_sum_rp.c * Purpose: Driver for MPI global sum function that uses a ring pass * Input: None * Output: Random values generated by processes and sum of these * values. * * Algorithm: * 1. Each process computes a random int x from 0 to MAX_CONTRIB-1 * 2. Processes call Global_sum function which sums the local * values on each process * 3. Results are collected and printed by process 0 * * Compile: mpicc -g -Wall -o global_sum_rp global_sum_rp.c * Run: mpiexec -n global_sum_rp * * Notes: * 1. This version has no restriction on the number of processes. * 2. The value returned by global_sum is valid on all processes. * 3. DEBUG flag can be used to print information on pairing * of processes. * 4. The Global_sum function is unsafe. */ #include #include #include const int MAX_CONTRIB = 20; int Global_sum(int myContrib, int my_rank, int p, MPI_Comm comm); void Print_results(char title[], int value, int my_rank, int p, MPI_Comm comm); int main(void) { int p, my_rank; MPI_Comm comm; int x, total; MPI_Init(NULL, NULL); comm = MPI_COMM_WORLD; MPI_Comm_size(comm, &p); MPI_Comm_rank(comm, &my_rank); /* Generate a random value */ srandom(my_rank); x = random() % MAX_CONTRIB; Print_results("Process Values", x, my_rank, p, comm); total = Global_sum(x, my_rank, p, comm); Print_results("Process Totals", total, my_rank, p, comm); MPI_Finalize(); return 0; } /* main */ /*--------------------------------------------------------------- * Function: Print_results * Purpose: Gather an int from each process onto process 0 and * print the values. * In args: * title: the title of the output * value: the int contributed by each process * my_rank, p, comm: the usual MPI values */ void Print_results(char title[], int value, int my_rank, int p, MPI_Comm comm) { int* vals = NULL, q; if (my_rank == 0) { vals = malloc(p*sizeof(int)); MPI_Gather(&value, 1, MPI_INT, vals, 1, MPI_INT, 0, comm); printf("%s:\n", title); for (q = 0; q < p; q++) printf("Proc %d > %d\n", q, vals[q]); printf("\n"); free(vals); } else { MPI_Gather(&value, 1, MPI_INT, vals, 1, MPI_INT, 0, comm); } } /* Print_results */ /*--------------------------------------------------------------- * Function: Global_sum * Purpose: Compute global sum of values distributed across * processes * Input args: * my_contrib: the calling process' contribution to the global sum * my_rank: the calling process' rank in the communicator * p: the number of processes in the communicator * comm: the communicator used for sends and receives * * Return val: the sum of the my_contrib values contributed by * each process. * * Algorithm: Use a ring-pass to communicate: each process executes * a send of themost recently received value and a receive * of the ``previous'' process' most recently received value * * Notes: * 1. The value returned by global_sum is valid on all processes. * 2. The communication is unsafe. */ int Global_sum(int my_contrib, int my_rank, int p, MPI_Comm comm) { int sum = my_contrib; int temp = my_contrib; int source, dest, stage; source = (my_rank + p - 1) % p; dest = (my_rank + 1) % p; # ifdef DEBUG printf("Proc %d > source = %d, dest = %d, sum = %d, temp = %d\n", my_rank, source, dest, sum, temp); fflush(stdout); # endif for (stage = 0; stage < p-1; stage++) { MPI_Send(&temp, 1, MPI_INT, dest, 0, comm); MPI_Recv(&temp, 1, MPI_INT, source, 0, comm, MPI_STATUS_IGNORE); sum += temp; # ifdef DEBUG printf("Proc %d > sum = %d, temp = %d, stage = %d\n", my_rank, sum, temp, stage); fflush(stdout); # endif } return sum; } /* Global_sum */