# include # include # include # include using namespace std; int main ( int argc, char *argv[] ); void ring_io ( int p, int id ); //****************************************************************************80 int main ( int argc, char *argv[] ) //****************************************************************************80 // // Purpose: // // MAIN is the main program for RING_MPI. // // Discussion: // // RING_MPI sends messages of various size from process 0 to 1 to 2 to // ...the last process and then back to 0. // // Licensing: // // This code is distributed under the MIT license. // // Modified: // // 16 June 2016 // // Author: // // John Burkardt // // Reference: // // Peter Pacheco, // Parallel Programming with MPI, // Morgan Kaufman, 1996, // ISBN: 1558603395, // LC: QA76.642.P3. // { int id; int p; // // Initialize MPI. // MPI_Init ( &argc, &argv ); // // Get the number of processes. // MPI_Comm_size ( MPI_COMM_WORLD, &p ); // // Get the individual process ID. // MPI_Comm_rank ( MPI_COMM_WORLD, &id ); // // Print a message. // if ( id == 0 ) { cout << "\n"; cout << "RING_MPI:\n"; cout << " C++/MPI version\n"; cout << " Measure time required to transmit data around\n"; cout << " a ring of processes\n"; cout << "\n"; cout << " The number of processes is " << p << "\n"; } ring_io ( p, id ); // // Shut down MPI. // MPI_Finalize ( ); // // Terminate. // if ( id == 0 ) { cout << "\n"; cout << "RING_MPI:\n"; cout << " Normal end of execution.\n"; } return 0; } //****************************************************************************80 void ring_io ( int p, int id ) //****************************************************************************80 // // Purpose: // // RING_IO carries out the tasks of process ID, of a total of P processes. // // Licensing: // // This code is distributed under the MIT license. // // Modified: // // 20 October 2012 // // Author: // // John Burkardt // // Reference: // // Peter Pacheco, // Parallel Programming with MPI, // Morgan Kaufman, 1996, // ISBN: 1558603395, // LC: QA76.642.P3. // { int dest; int i; int j; int n; int n_test[5] = { 100, 1000, 10000, 100000, 1000000 }; int n_test_num = 5; int source; MPI_Status status; double tave; int test; int test_num = 10; double tmax; double tmin; double wtime; double *x; if ( id == 0 ) { cout << "\n"; cout << " Timings based on " << test_num << " experiments\n"; cout << " N double precision values were sent\n"; cout << " in a ring transmission starting and ending at process 0\n"; cout << " and using a total of " << p << " processes.\n"; cout << "\n"; cout << " N T min T ave T max\n"; cout << "\n"; } // // Choose message size. // for ( i = 0; i < n_test_num; i++ ) { n = n_test[i]; x = new double[n]; // // Process 0 sends very first message, // then waits to receive the "echo" that has gone around the world. // if ( id == 0 ) { dest = 1; source = p - 1; tave = 0.0; tmin = 1.0E+30; tmax = 0.0; for ( test = 1; test <= test_num; test++ ) { // // Just in case, set the entries of X in a way that identifies // which iteration of the test is being carried out. // for ( j = 0; j < n; j++ ) { x[j] = ( double ) ( test + j ); } wtime = MPI_Wtime ( ); MPI_Send ( x, n, MPI_DOUBLE, dest, 0, MPI_COMM_WORLD ); MPI_Recv ( x, n, MPI_DOUBLE, source, 0, MPI_COMM_WORLD, &status ); wtime = MPI_Wtime ( ) - wtime; // // Record the time it took. // tave = tave + wtime; if ( wtime < tmin ) { tmin = wtime; } if ( tmax < wtime ) { tmax = wtime; } } tave = tave / ( double ) ( test_num ); cout << " " << setw(8) << n << " " << setw(14) << tmin << " " << setw(14) << tave << " " << setw(14) << tmax << "\n"; } // // Worker ID must receive first from ID-1, then send to ID+1. // else { source = id - 1; dest = ( ( id + 1 ) % p ); for ( test = 1; test <= test_num; test++ ) { MPI_Recv ( x, n, MPI_DOUBLE, source, 0, MPI_COMM_WORLD, &status ); MPI_Send ( x, n, MPI_DOUBLE, dest, 0, MPI_COMM_WORLD ); } } delete [] x; } return; }