00001 #include "copyright.h" 00002 /*============================================================================*/ 00003 /*! \file baton.c 00004 * \brief Stage independent processes by passing a baton. 00005 * 00006 * PURPOSE: Stage independent processes by passing a baton. The 00007 * functions here assume that no MPI communication will proceed 00008 * between baton_start() and baton_stop() and that the arguments to 00009 * the functions will be identical. This is easy enough to 00010 * accomplish, but can be error prone. Use these functions with 00011 * caution! 00012 * 00013 * These functions were written and added to athena by T. A. Gardiner 00014 * in March, 2008. 00015 * 00016 * CONTAINS PUBLIC FUNCTIONS: 00017 * - baton_start() 00018 * - baton_stop() */ 00019 /*============================================================================*/ 00020 #include "defs.h" 00021 #include "prototypes.h" 00022 00023 00024 #ifdef MPI_PARALLEL 00025 00026 /* ========================================================================== */ 00027 00028 /*! \fn void baton_start(const int Nb, const int tag) 00029 * \brief This function starts off a "Baton Passing" scheme for regulating 00030 * the maximum number of processes active at a given moment. 00031 * 00032 * NOTES on baton_start() and baton_stop(): 00033 * 00034 * The values for Nb and tag MUST be the same in the call to 00035 * baton_start() and in baton_stop(). 00036 * 00037 * - Nb -> Number of Batons = max number of ranks in action at a given time. 00038 * - tag -> MPI message tag to use for this baton passing. 00039 * 00040 * This function starts off a "Baton Passing" scheme for regulating 00041 * the maximum number of processes active at a given moment. It works 00042 * by handing out Nb batons to the first (0 -> Nb-1) ranks. Then 00043 * ranks (Nb -> 2Nb-1) wait for a signal from the ranks (0 -> Nb-1) 00044 * which is sent by the baton_stop() function and so the process 00045 * continues until all of the MPI ranks have completed. */ 00046 void baton_start(const int Nb, const int tag){ 00047 00048 MPI_Status stat; 00049 int status, isig, fr_id, my_id; 00050 00051 status = MPI_Comm_rank(MPI_COMM_WORLD, &my_id); 00052 if(status != MPI_SUCCESS) 00053 ath_error("[baton_start]: MPI_Comm_rank error = %d\n",status); 00054 00055 fr_id = my_id - Nb; 00056 00057 if(Nb > 0 && fr_id >= 0){ 00058 /* Wait for another process to signal before beginning. */ 00059 status = MPI_Recv(&isig, 0, MPI_INT, fr_id, tag, MPI_COMM_WORLD, &stat); 00060 00061 if(status != MPI_SUCCESS) 00062 ath_error("[baton_start]: MPI_Recv error = %d\n",status); 00063 } 00064 00065 return; 00066 } 00067 00068 00069 /* ========================================================================== */ 00070 00071 00072 /*! \fn void baton_stop(const int Nb, const int tag) 00073 * \brief This function marks the end of a section of code which is regulated 00074 * by "Baton Passing". It signals the next process to start, i.e. it 00075 * hands off the Baton. */ 00076 void baton_stop(const int Nb, const int tag){ 00077 00078 int status, isig, to_id, my_id, nproc; 00079 00080 status = MPI_Comm_rank(MPI_COMM_WORLD, &my_id); 00081 if(status != MPI_SUCCESS) 00082 ath_error("[baton_stop]: MPI_Comm_rank error = %d\n",status); 00083 00084 status = MPI_Comm_size(MPI_COMM_WORLD, &nproc); 00085 if(status != MPI_SUCCESS) 00086 ath_error("[baton_stop]: MPI_Comm_size error = %d\n",status); 00087 00088 to_id = my_id + Nb; 00089 00090 if(Nb > 0 && to_id < nproc){ 00091 /* Signal the next process to begin. */ 00092 status = MPI_Send(&isig, 0, MPI_INT, to_id, tag, MPI_COMM_WORLD); 00093 00094 if(status != MPI_SUCCESS) 00095 ath_error("[baton_stop]: MPI_Send error = %d\n",status); 00096 } 00097 00098 return; 00099 } 00100 00101 00102 /* ========================================================================== */ 00103 00104 00105 #endif /* MPI_PARALLEL */