root/ompi/runtime/ompi_spc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. SET_SPC_BIT
  2. IS_SPC_BIT_SET
  3. CLEAR_SPC_BIT
  4. ompi_spc_notify
  5. ompi_spc_get_count
  6. ompi_spc_events_init
  7. ompi_spc_init
  8. ompi_spc_dump
  9. ompi_spc_fini
  10. ompi_spc_record
  11. ompi_spc_timer_start
  12. ompi_spc_timer_stop
  13. ompi_spc_user_or_mpi
  14. ompi_spc_update_watermark
  15. ompi_spc_cycles_to_usecs

   1 /*
   2  * Copyright (c) 2018      The University of Tennessee and The University
   3  *                         of Tennessee Research Foundation.  All rights
   4  *                         reserved.
   5  *
   6  * Copyright (c) 2018      Cisco Systems, Inc.  All rights reserved
   7  * Copyright (c) 2018      Research Organization for Information Science
   8  *                         and Technology (RIST).  All rights reserved.
   9  * $COPYRIGHT$
  10  *
  11  * Additional copyrights may follow
  12  *
  13  * $HEADER$
  14  */
  15 
  16 #include "ompi_spc.h"
  17 
  18 opal_timer_t sys_clock_freq_mhz = 0;
  19 
  20 static void ompi_spc_dump(void);
  21 
  22 /* Array for converting from SPC indices to MPI_T indices */
  23 OMPI_DECLSPEC int mpi_t_offset = -1;
  24 OMPI_DECLSPEC bool mpi_t_enabled = false;
  25 
  26 OPAL_DECLSPEC ompi_communicator_t *ompi_spc_comm = NULL;
  27 
  28 typedef struct ompi_spc_event_t {
  29     const char* counter_name;
  30     const char* counter_description;
  31 } ompi_spc_event_t;
  32 
  33 #define SET_COUNTER_ARRAY(NAME, DESC)   [NAME] = { .counter_name = #NAME, .counter_description = DESC }
  34 
  35 static ompi_spc_event_t ompi_spc_events_names[OMPI_SPC_NUM_COUNTERS] = {
  36     SET_COUNTER_ARRAY(OMPI_SPC_SEND, "The number of times MPI_Send was called."),
  37     SET_COUNTER_ARRAY(OMPI_SPC_BSEND, "The number of times MPI_Bsend was called."),
  38     SET_COUNTER_ARRAY(OMPI_SPC_RSEND, "The number of times MPI_Rsend was called."),
  39     SET_COUNTER_ARRAY(OMPI_SPC_SSEND, "The number of times MPI_Ssend was called."),
  40     SET_COUNTER_ARRAY(OMPI_SPC_RECV, "The number of times MPI_Recv was called."),
  41     SET_COUNTER_ARRAY(OMPI_SPC_MRECV, "The number of times MPI_Mrecv was called."),
  42     SET_COUNTER_ARRAY(OMPI_SPC_ISEND, "The number of times MPI_Isend was called."),
  43     SET_COUNTER_ARRAY(OMPI_SPC_IBSEND, "The number of times MPI_Ibsend was called."),
  44     SET_COUNTER_ARRAY(OMPI_SPC_IRSEND, "The number of times MPI_Irsend was called."),
  45     SET_COUNTER_ARRAY(OMPI_SPC_ISSEND, "The number of times MPI_Issend was called."),
  46     SET_COUNTER_ARRAY(OMPI_SPC_IRECV, "The number of times MPI_Irecv was called."),
  47     SET_COUNTER_ARRAY(OMPI_SPC_SENDRECV, "The number of times MPI_Sendrecv was called."),
  48     SET_COUNTER_ARRAY(OMPI_SPC_SENDRECV_REPLACE, "The number of times MPI_Sendrecv_replace was called."),
  49     SET_COUNTER_ARRAY(OMPI_SPC_PUT, "The number of times MPI_Put was called."),
  50     SET_COUNTER_ARRAY(OMPI_SPC_RPUT, "The number of times MPI_Rput was called."),
  51     SET_COUNTER_ARRAY(OMPI_SPC_GET, "The number of times MPI_Get was called."),
  52     SET_COUNTER_ARRAY(OMPI_SPC_RGET, "The number of times MPI_Rget was called."),
  53     SET_COUNTER_ARRAY(OMPI_SPC_PROBE, "The number of times MPI_Probe was called."),
  54     SET_COUNTER_ARRAY(OMPI_SPC_IPROBE, "The number of times MPI_Iprobe was called."),
  55     SET_COUNTER_ARRAY(OMPI_SPC_BCAST, "The number of times MPI_Bcast was called."),
  56     SET_COUNTER_ARRAY(OMPI_SPC_IBCAST, "The number of times MPI_Ibcast was called."),
  57     SET_COUNTER_ARRAY(OMPI_SPC_BCAST_INIT, "The number of times MPIX_Bcast_init was called."),
  58     SET_COUNTER_ARRAY(OMPI_SPC_REDUCE, "The number of times MPI_Reduce was called."),
  59     SET_COUNTER_ARRAY(OMPI_SPC_REDUCE_SCATTER, "The number of times MPI_Reduce_scatter was called."),
  60     SET_COUNTER_ARRAY(OMPI_SPC_REDUCE_SCATTER_BLOCK, "The number of times MPI_Reduce_scatter_block was called."),
  61     SET_COUNTER_ARRAY(OMPI_SPC_IREDUCE, "The number of times MPI_Ireduce was called."),
  62     SET_COUNTER_ARRAY(OMPI_SPC_IREDUCE_SCATTER, "The number of times MPI_Ireduce_scatter was called."),
  63     SET_COUNTER_ARRAY(OMPI_SPC_IREDUCE_SCATTER_BLOCK, "The number of times MPI_Ireduce_scatter_block was called."),
  64     SET_COUNTER_ARRAY(OMPI_SPC_REDUCE_INIT, "The number of times MPIX_Reduce_init was called."),
  65     SET_COUNTER_ARRAY(OMPI_SPC_REDUCE_SCATTER_INIT, "The number of times MPIX_Reduce_scatter_init was called."),
  66     SET_COUNTER_ARRAY(OMPI_SPC_REDUCE_SCATTER_BLOCK_INIT, "The number of times MPIX_Reduce_scatter_block_init was called."),
  67     SET_COUNTER_ARRAY(OMPI_SPC_ALLREDUCE, "The number of times MPI_Allreduce was called."),
  68     SET_COUNTER_ARRAY(OMPI_SPC_IALLREDUCE, "The number of times MPI_Iallreduce was called."),
  69     SET_COUNTER_ARRAY(OMPI_SPC_ALLREDUCE_INIT, "The number of times MPIX_Allreduce_init was called."),
  70     SET_COUNTER_ARRAY(OMPI_SPC_SCAN, "The number of times MPI_Scan was called."),
  71     SET_COUNTER_ARRAY(OMPI_SPC_EXSCAN, "The number of times MPI_Exscan was called."),
  72     SET_COUNTER_ARRAY(OMPI_SPC_ISCAN, "The number of times MPI_Iscan was called."),
  73     SET_COUNTER_ARRAY(OMPI_SPC_IEXSCAN, "The number of times MPI_Iexscan was called."),
  74     SET_COUNTER_ARRAY(OMPI_SPC_SCAN_INIT, "The number of times MPIX_Scan_init was called."),
  75     SET_COUNTER_ARRAY(OMPI_SPC_EXSCAN_INIT, "The number of times MPIX_Exscan_init was called."),
  76     SET_COUNTER_ARRAY(OMPI_SPC_SCATTER, "The number of times MPI_Scatter was called."),
  77     SET_COUNTER_ARRAY(OMPI_SPC_SCATTERV, "The number of times MPI_Scatterv was called."),
  78     SET_COUNTER_ARRAY(OMPI_SPC_ISCATTER, "The number of times MPI_Iscatter was called."),
  79     SET_COUNTER_ARRAY(OMPI_SPC_ISCATTERV, "The number of times MPI_Iscatterv was called."),
  80     SET_COUNTER_ARRAY(OMPI_SPC_SCATTER_INIT, "The number of times MPIX_Scatter_init was called."),
  81     SET_COUNTER_ARRAY(OMPI_SPC_SCATTERV_INIT, "The number of times MPIX_Scatterv_init was called."),
  82     SET_COUNTER_ARRAY(OMPI_SPC_GATHER, "The number of times MPI_Gather was called."),
  83     SET_COUNTER_ARRAY(OMPI_SPC_GATHERV, "The number of times MPI_Gatherv was called."),
  84     SET_COUNTER_ARRAY(OMPI_SPC_IGATHER, "The number of times MPI_Igather was called."),
  85     SET_COUNTER_ARRAY(OMPI_SPC_IGATHERV, "The number of times MPI_Igatherv was called."),
  86     SET_COUNTER_ARRAY(OMPI_SPC_GATHER_INIT, "The number of times MPIX_Gather_init was called."),
  87     SET_COUNTER_ARRAY(OMPI_SPC_GATHERV_INIT, "The number of times MPIX_Gatherv_init was called."),
  88     SET_COUNTER_ARRAY(OMPI_SPC_ALLTOALL, "The number of times MPI_Alltoall was called."),
  89     SET_COUNTER_ARRAY(OMPI_SPC_ALLTOALLV, "The number of times MPI_Alltoallv was called."),
  90     SET_COUNTER_ARRAY(OMPI_SPC_ALLTOALLW, "The number of times MPI_Alltoallw was called."),
  91     SET_COUNTER_ARRAY(OMPI_SPC_IALLTOALL, "The number of times MPI_Ialltoall was called."),
  92     SET_COUNTER_ARRAY(OMPI_SPC_IALLTOALLV, "The number of times MPI_Ialltoallv was called."),
  93     SET_COUNTER_ARRAY(OMPI_SPC_IALLTOALLW, "The number of times MPI_Ialltoallw was called."),
  94     SET_COUNTER_ARRAY(OMPI_SPC_ALLTOALL_INIT, "The number of times MPIX_Alltoall_init was called."),
  95     SET_COUNTER_ARRAY(OMPI_SPC_ALLTOALLV_INIT, "The number of times MPIX_Alltoallv_init was called."),
  96     SET_COUNTER_ARRAY(OMPI_SPC_ALLTOALLW_INIT, "The number of times MPIX_Alltoallw_init was called."),
  97     SET_COUNTER_ARRAY(OMPI_SPC_NEIGHBOR_ALLTOALL, "The number of times MPI_Neighbor_alltoall was called."),
  98     SET_COUNTER_ARRAY(OMPI_SPC_NEIGHBOR_ALLTOALLV, "The number of times MPI_Neighbor_alltoallv was called."),
  99     SET_COUNTER_ARRAY(OMPI_SPC_NEIGHBOR_ALLTOALLW, "The number of times MPI_Neighbor_alltoallw was called."),
 100     SET_COUNTER_ARRAY(OMPI_SPC_INEIGHBOR_ALLTOALL, "The number of times MPI_Ineighbor_alltoall was called."),
 101     SET_COUNTER_ARRAY(OMPI_SPC_INEIGHBOR_ALLTOALLV, "The number of times MPI_Ineighbor_alltoallv was called."),
 102     SET_COUNTER_ARRAY(OMPI_SPC_INEIGHBOR_ALLTOALLW, "The number of times MPI_Ineighbor_alltoallw was called."),
 103     SET_COUNTER_ARRAY(OMPI_SPC_NEIGHBOR_ALLTOALL_INIT, "The number of times MPIX_Neighbor_alltoall_init was called."),
 104     SET_COUNTER_ARRAY(OMPI_SPC_NEIGHBOR_ALLTOALLV_INIT, "The number of times MPIX_Neighbor_alltoallv_init was called."),
 105     SET_COUNTER_ARRAY(OMPI_SPC_NEIGHBOR_ALLTOALLW_INIT, "The number of times MPIX_Neighbor_alltoallw_init was called."),
 106     SET_COUNTER_ARRAY(OMPI_SPC_ALLGATHER, "The number of times MPI_Allgather was called."),
 107     SET_COUNTER_ARRAY(OMPI_SPC_ALLGATHERV, "The number of times MPI_Allgatherv was called."),
 108     SET_COUNTER_ARRAY(OMPI_SPC_IALLGATHER, "The number of times MPI_Iallgather was called."),
 109     SET_COUNTER_ARRAY(OMPI_SPC_IALLGATHERV, "The number of times MPI_Iallgatherv was called."),
 110     SET_COUNTER_ARRAY(OMPI_SPC_ALLGATHER_INIT, "The number of times MPIX_Allgather_init was called."),
 111     SET_COUNTER_ARRAY(OMPI_SPC_ALLGATHERV_INIT, "The number of times MPIX_Allgatherv_init was called."),
 112     SET_COUNTER_ARRAY(OMPI_SPC_NEIGHBOR_ALLGATHER, "The number of times MPI_Neighbor_allgather was called."),
 113     SET_COUNTER_ARRAY(OMPI_SPC_NEIGHBOR_ALLGATHERV, "The number of times MPI_Neighbor_allgatherv was called."),
 114     SET_COUNTER_ARRAY(OMPI_SPC_INEIGHBOR_ALLGATHER, "The number of times MPI_Ineighbor_allgather was called."),
 115     SET_COUNTER_ARRAY(OMPI_SPC_INEIGHBOR_ALLGATHERV, "The number of times MPI_Ineighbor_allgatherv was called."),
 116     SET_COUNTER_ARRAY(OMPI_SPC_NEIGHBOR_ALLGATHER_INIT, "The number of times MPIX_Neighbor_allgather_init was called."),
 117     SET_COUNTER_ARRAY(OMPI_SPC_NEIGHBOR_ALLGATHERV_INIT, "The number of times MPIX_Neighbor_allgatherv_init was called."),
 118     SET_COUNTER_ARRAY(OMPI_SPC_TEST, "The number of times MPI_Test was called."),
 119     SET_COUNTER_ARRAY(OMPI_SPC_TESTALL, "The number of times MPI_Testall was called."),
 120     SET_COUNTER_ARRAY(OMPI_SPC_TESTANY, "The number of times MPI_Testany was called."),
 121     SET_COUNTER_ARRAY(OMPI_SPC_TESTSOME, "The number of times MPI_Testsome was called."),
 122     SET_COUNTER_ARRAY(OMPI_SPC_WAIT, "The number of times MPI_Wait was called."),
 123     SET_COUNTER_ARRAY(OMPI_SPC_WAITALL, "The number of times MPI_Waitall was called."),
 124     SET_COUNTER_ARRAY(OMPI_SPC_WAITANY, "The number of times MPI_Waitany was called."),
 125     SET_COUNTER_ARRAY(OMPI_SPC_WAITSOME, "The number of times MPI_Waitsome was called."),
 126     SET_COUNTER_ARRAY(OMPI_SPC_BARRIER, "The number of times MPI_Barrier was called."),
 127     SET_COUNTER_ARRAY(OMPI_SPC_IBARRIER, "The number of times MPI_Ibarrier was called."),
 128     SET_COUNTER_ARRAY(OMPI_SPC_BARRIER_INIT, "The number of times MPIX_Barrier_init was called."),
 129     SET_COUNTER_ARRAY(OMPI_SPC_WTIME, "The number of times MPI_Wtime was called."),
 130     SET_COUNTER_ARRAY(OMPI_SPC_CANCEL, "The number of times MPI_Cancel was called."),
 131     SET_COUNTER_ARRAY(OMPI_SPC_BYTES_RECEIVED_USER, "The number of bytes received by the user through point-to-point communications. Note: Includes bytes transferred using internal RMA operations."),
 132     SET_COUNTER_ARRAY(OMPI_SPC_BYTES_RECEIVED_MPI, "The number of bytes received by MPI through collective, control, or other internal communications."),
 133     SET_COUNTER_ARRAY(OMPI_SPC_BYTES_SENT_USER, "The number of bytes sent by the user through point-to-point communications.  Note: Includes bytes transferred using internal RMA operations."),
 134     SET_COUNTER_ARRAY(OMPI_SPC_BYTES_SENT_MPI, "The number of bytes sent by MPI through collective, control, or other internal communications."),
 135     SET_COUNTER_ARRAY(OMPI_SPC_BYTES_PUT, "The number of bytes sent/received using RMA Put operations both through user-level Put functions and internal Put functions."),
 136     SET_COUNTER_ARRAY(OMPI_SPC_BYTES_GET, "The number of bytes sent/received using RMA Get operations both through user-level Get functions and internal Get functions."),
 137     SET_COUNTER_ARRAY(OMPI_SPC_UNEXPECTED, "The number of messages that arrived as unexpected messages."),
 138     SET_COUNTER_ARRAY(OMPI_SPC_OUT_OF_SEQUENCE, "The number of messages that arrived out of the proper sequence."),
 139     SET_COUNTER_ARRAY(OMPI_SPC_MATCH_TIME, "The number of microseconds spent matching unexpected messages.  Note: The timer used on the back end is in cycles, which could potentially be problematic on a system where the clock frequency can change.  On such a system, this counter could be inaccurate since we assume a fixed clock rate."),
 140     SET_COUNTER_ARRAY(OMPI_SPC_UNEXPECTED_IN_QUEUE, "The number of messages that are currently in the unexpected message queue(s) of an MPI process."),
 141     SET_COUNTER_ARRAY(OMPI_SPC_OOS_IN_QUEUE, "The number of messages that are currently in the out of sequence message queue(s) of an MPI process."),
 142     SET_COUNTER_ARRAY(OMPI_SPC_MAX_UNEXPECTED_IN_QUEUE, "The maximum number of messages that the unexpected message queue(s) within an MPI process "
 143                                                     "contained at once since the last reset of this counter. Note: This counter is reset each time it is read."),
 144     SET_COUNTER_ARRAY(OMPI_SPC_MAX_OOS_IN_QUEUE, "The maximum number of messages that the out of sequence message queue(s) within an MPI process "
 145                                              "contained at once since the last reset of this counter. Note: This counter is reset each time it is read.")
 146 };
 147 
 148 /* An array of integer values to denote whether an event is activated (1) or not (0) */
 149 static uint32_t ompi_spc_attached_event[OMPI_SPC_NUM_COUNTERS / sizeof(uint32_t)] = { 0 };
 150 /* An array of integer values to denote whether an event is timer-based (1) or not (0) */
 151 static uint32_t ompi_spc_timer_event[OMPI_SPC_NUM_COUNTERS / sizeof(uint32_t)] = { 0 };
 152 /* An array of event structures to store the event data (name and value) */
 153 static ompi_spc_t *ompi_spc_events = NULL;
 154 
 155 static inline void SET_SPC_BIT(uint32_t* array, int32_t pos)
 156 {
 157     assert(pos < OMPI_SPC_NUM_COUNTERS);
 158     array[pos / (8 * sizeof(uint32_t))] |= (1U << (pos % (8 * sizeof(uint32_t))));
 159 }
 160 
 161 static inline bool IS_SPC_BIT_SET(uint32_t* array, int32_t pos)
 162 {
 163     assert(pos < OMPI_SPC_NUM_COUNTERS);
 164     return !!(array[pos / (8 * sizeof(uint32_t))] & (1U << (pos % (8 * sizeof(uint32_t)))));
 165 }
 166 
 167 static inline void CLEAR_SPC_BIT(uint32_t* array, int32_t pos)
 168 {
 169     assert(pos < OMPI_SPC_NUM_COUNTERS);
 170     array[pos / (8 * sizeof(uint32_t))] &= ~(1U << (pos % (8 * sizeof(uint32_t))));
 171 }
 172 
 173 /* ##############################################################
 174  * ################# Begin MPI_T Functions ######################
 175  * ##############################################################
 176  */
 177 static int ompi_spc_notify(mca_base_pvar_t *pvar, mca_base_pvar_event_t event, void *obj_handle, int *count)
 178     __opal_attribute_unused__;
 179 
 180 static int ompi_spc_notify(mca_base_pvar_t *pvar, mca_base_pvar_event_t event, void *obj_handle, int *count)
 181 {
 182     int index;
 183 
 184     if(OPAL_LIKELY(!mpi_t_enabled)) {
 185         return MPI_SUCCESS;
 186     }
 187 
 188     /* For this event, we need to set count to the number of long long type
 189      * values for this counter.  All SPC counters are one long long, so we
 190      * always set count to 1.
 191      */
 192     if(MCA_BASE_PVAR_HANDLE_BIND == event) {
 193         *count = 1;
 194     }
 195     /* For this event, we need to turn on the counter */
 196     else if(MCA_BASE_PVAR_HANDLE_START == event) {
 197         /* Convert from MPI_T pvar index to SPC index */
 198         index = pvar->pvar_index - mpi_t_offset;
 199         SET_SPC_BIT(ompi_spc_attached_event, index);
 200     }
 201     /* For this event, we need to turn off the counter */
 202     else if(MCA_BASE_PVAR_HANDLE_STOP == event) {
 203         /* Convert from MPI_T pvar index to SPC index */
 204         index = pvar->pvar_index - mpi_t_offset;
 205         CLEAR_SPC_BIT(ompi_spc_attached_event, index);
 206     }
 207 
 208     return MPI_SUCCESS;
 209 }
 210 
 211 /* ##############################################################
 212  * ################# Begin SPC Functions ########################
 213  * ##############################################################
 214  */
 215 
 216 /* This function returns the current count of an SPC counter that has been retistered
 217  * as an MPI_T pvar.  The MPI_T index is not necessarily the same as the SPC index,
 218  * so we need to convert from MPI_T index to SPC index and then set the 'value' argument
 219  * to the correct value for this pvar.
 220  */
 221 static int ompi_spc_get_count(const struct mca_base_pvar_t *pvar, void *value, void *obj_handle)
 222     __opal_attribute_unused__;
 223 
 224 static int ompi_spc_get_count(const struct mca_base_pvar_t *pvar, void *value, void *obj_handle)
 225 {
 226     long long *counter_value = (long long*)value;
 227 
 228     if(OPAL_LIKELY(!mpi_t_enabled)) {
 229         *counter_value = 0;
 230         return MPI_SUCCESS;
 231     }
 232 
 233     /* Convert from MPI_T pvar index to SPC index */
 234     int index = pvar->pvar_index - mpi_t_offset;
 235     /* Set the counter value to the current SPC value */
 236     *counter_value = (long long)ompi_spc_events[index].value;
 237     /* If this is a timer-based counter, convert from cycles to microseconds */
 238     if( IS_SPC_BIT_SET(ompi_spc_timer_event, index) ) {
 239         *counter_value /= sys_clock_freq_mhz;
 240     }
 241     /* If this is a high watermark counter, reset it after it has been read */
 242     if(index == OMPI_SPC_MAX_UNEXPECTED_IN_QUEUE || index == OMPI_SPC_MAX_OOS_IN_QUEUE) {
 243         ompi_spc_events[index].value = 0;
 244     }
 245 
 246     return MPI_SUCCESS;
 247 }
 248 
 249 /* Initializes the events data structure and allocates memory for it if needed. */
 250 void ompi_spc_events_init(void)
 251 {
 252     int i;
 253 
 254     /* If the events data structure hasn't been allocated yet, allocate memory for it */
 255     if(NULL == ompi_spc_events) {
 256         ompi_spc_events = (ompi_spc_t*)malloc(OMPI_SPC_NUM_COUNTERS * sizeof(ompi_spc_t));
 257         if(ompi_spc_events == NULL) {
 258             opal_show_help("help-mpi-runtime.txt", "lib-call-fail", true,
 259                            "malloc", __FILE__, __LINE__);
 260             return;
 261         }
 262     }
 263     /* The data structure has been allocated, so we simply initialize all of the counters
 264      * with their names and an initial count of 0.
 265      */
 266     for(i = 0; i < OMPI_SPC_NUM_COUNTERS; i++) {
 267         ompi_spc_events[i].name = (char*)ompi_spc_events_names[i].counter_name;
 268         ompi_spc_events[i].value = 0;
 269     }
 270 
 271     ompi_comm_dup(&ompi_mpi_comm_world.comm, &ompi_spc_comm);
 272 }
 273 
 274 /* Initializes the SPC data structures and registers all counters as MPI_T pvars.
 275  * Turns on only the counters that were specified in the mpi_spc_attach MCA parameter.  
 276  */
 277 void ompi_spc_init(void)
 278 {
 279     int i, j, ret, found = 0, all_on = 0;
 280 
 281     /* Initialize the clock frequency variable as the CPU's frequency in MHz */
 282     sys_clock_freq_mhz = opal_timer_base_get_freq() / 1000000;
 283 
 284     ompi_spc_events_init();
 285 
 286     /* Get the MCA params string of counters to turn on */
 287     char **arg_strings = opal_argv_split(ompi_mpi_spc_attach_string, ',');
 288     int num_args       = opal_argv_count(arg_strings);
 289 
 290     /* If there is only one argument and it is 'all', then all counters
 291      * should be turned on.  If the size is 0, then no counters will be enabled.
 292      */
 293     if(1 == num_args) {
 294         if(strcmp(arg_strings[0], "all") == 0) {
 295             all_on = 1;
 296         }
 297     }
 298 
 299     /* Turn on only the counters that were specified in the MCA parameter */
 300     for(i = 0; i < OMPI_SPC_NUM_COUNTERS; i++) {
 301         if(all_on) {
 302             SET_SPC_BIT(ompi_spc_attached_event, i);
 303             mpi_t_enabled = true;
 304             found++;
 305         } else {
 306             /* Note: If no arguments were given, this will be skipped */
 307             for(j = 0; j < num_args; j++) {
 308                 if( 0 == strcmp(ompi_spc_events_names[i].counter_name, arg_strings[j]) ) {
 309                     SET_SPC_BIT(ompi_spc_attached_event, i);
 310                     mpi_t_enabled = true;
 311                     found++;
 312                     break;
 313                 }
 314             }
 315         }
 316 
 317         /* ########################################################################
 318          * ################## Add Timer-Based Counter Enums Here ##################
 319          * ########################################################################
 320          */
 321         CLEAR_SPC_BIT(ompi_spc_timer_event, i);
 322 
 323         /* Registers the current counter as an MPI_T pvar regardless of whether it's been turned on or not */
 324         ret = mca_base_pvar_register("ompi", "runtime", "spc", ompi_spc_events_names[i].counter_name, ompi_spc_events_names[i].counter_description,
 325                                      OPAL_INFO_LVL_4, MPI_T_PVAR_CLASS_SIZE,
 326                                      MCA_BASE_VAR_TYPE_UNSIGNED_LONG_LONG, NULL, MPI_T_BIND_NO_OBJECT,
 327                                      MCA_BASE_PVAR_FLAG_READONLY | MCA_BASE_PVAR_FLAG_CONTINUOUS,
 328                                      ompi_spc_get_count, NULL, ompi_spc_notify, NULL);
 329 
 330         /* Check to make sure that ret is a valid index and not an error code.
 331          */
 332         if( ret >= 0 ) {
 333             if( mpi_t_offset == -1 ) {
 334                 mpi_t_offset = ret;
 335             }
 336         }
 337         if( (ret < 0) || (ret != (mpi_t_offset + found - 1)) ) {
 338             mpi_t_enabled = false;
 339             opal_show_help("help-mpi-runtime.txt", "spc: MPI_T disabled", true);
 340             break;
 341         }
 342     }
 343     /* If this is a timer event, sent the corresponding timer_event entry to 1 */
 344     SET_SPC_BIT(ompi_spc_timer_event, OMPI_SPC_MATCH_TIME);
 345     opal_argv_free(arg_strings);
 346 }
 347 
 348 /* Gathers all of the SPC data onto rank 0 of MPI_COMM_WORLD and prints out all
 349  * of the counter values to stdout.
 350  */
 351 static void ompi_spc_dump(void)
 352 {
 353     int i, j, world_size, offset;
 354     long long *recv_buffer = NULL, *send_buffer;
 355 
 356     int rank = ompi_comm_rank(ompi_spc_comm);
 357     world_size = ompi_comm_size(ompi_spc_comm);
 358 
 359     /* Convert from cycles to usecs before sending */
 360     for(i = 0; i < OMPI_SPC_NUM_COUNTERS; i++) {
 361         if( IS_SPC_BIT_SET(ompi_spc_timer_event, i) ) {
 362             SPC_CYCLES_TO_USECS(&ompi_spc_events[i].value);
 363         }
 364     }
 365 
 366     /* Aggregate all of the information on rank 0 using MPI_Gather on MPI_COMM_WORLD */
 367     send_buffer = (long long*)malloc(OMPI_SPC_NUM_COUNTERS * sizeof(long long));
 368     if (NULL == send_buffer) {
 369         opal_show_help("help-mpi-runtime.txt", "lib-call-fail", true,
 370                        "malloc", __FILE__, __LINE__);
 371         return;
 372     }
 373     for(i = 0; i < OMPI_SPC_NUM_COUNTERS; i++) {
 374         send_buffer[i] = (long long)ompi_spc_events[i].value;
 375     }
 376     if( 0 == rank ) {
 377         recv_buffer = (long long*)malloc(world_size * OMPI_SPC_NUM_COUNTERS * sizeof(long long));
 378         if (NULL == recv_buffer) {
 379             opal_show_help("help-mpi-runtime.txt", "lib-call-fail", true,
 380                            "malloc", __FILE__, __LINE__);
 381             return;
 382         }
 383     }
 384     (void)ompi_spc_comm->c_coll->coll_gather(send_buffer, OMPI_SPC_NUM_COUNTERS, MPI_LONG_LONG,
 385                                              recv_buffer, OMPI_SPC_NUM_COUNTERS, MPI_LONG_LONG,
 386                                              0, ompi_spc_comm,
 387                                              ompi_spc_comm->c_coll->coll_gather_module);
 388 
 389     /* Once rank 0 has all of the information, print the aggregated counter values for each rank in order */
 390     if(rank == 0) {
 391         opal_output(0, "Open MPI Software-based Performance Counters:\n");
 392         offset = 0; /* Offset into the recv_buffer for each rank */
 393         for(j = 0; j < world_size; j++) {
 394             opal_output(0, "MPI_COMM_WORLD Rank %d:\n", j);
 395             for(i = 0; i < OMPI_SPC_NUM_COUNTERS; i++) {
 396                 /* If this is a timer-based counter, we need to covert from cycles to usecs */
 397                 if( 0 == recv_buffer[offset+i] ) {
 398                     continue;
 399                 }
 400                 opal_output(0, "%s -> %lld\n", ompi_spc_events[i].name, recv_buffer[offset+i]);
 401             }
 402             opal_output(0, "\n");
 403             offset += OMPI_SPC_NUM_COUNTERS;
 404         }
 405         printf("###########################################################################\n");
 406         printf("NOTE: Any counters not shown here were either disabled or had a value of 0.\n");
 407         printf("###########################################################################\n");
 408 
 409         free(recv_buffer);
 410     }
 411     free(send_buffer);
 412 
 413     ompi_spc_comm->c_coll->coll_barrier(ompi_spc_comm, ompi_spc_comm->c_coll->coll_barrier_module);
 414 }
 415 
 416 /* Frees any dynamically alocated OMPI SPC data structures */
 417 void ompi_spc_fini(void)
 418 {
 419     if (SPC_ENABLE == 1 && ompi_mpi_spc_dump_enabled) {
 420         ompi_spc_dump();
 421     }
 422 
 423     free(ompi_spc_events); ompi_spc_events = NULL;
 424     ompi_comm_free(&ompi_spc_comm);
 425 }
 426 
 427 /* Records an update to a counter using an atomic add operation. */
 428 void ompi_spc_record(unsigned int event_id, ompi_spc_value_t value)
 429 {
 430     /* Denoted unlikely because counters will often be turned off. */
 431     if( OPAL_UNLIKELY(IS_SPC_BIT_SET(ompi_spc_attached_event, event_id)) ) {
 432         OPAL_THREAD_ADD_FETCH_SIZE_T(&(ompi_spc_events[event_id].value), value);
 433     }
 434 }
 435 
 436 /* Starts cycle-precision timer and stores the start value in the 'cycles' argument.
 437  * Note: This assumes that the 'cycles' argument is initialized to 0 if the timer
 438  *       hasn't been started yet.
 439  */
 440 void ompi_spc_timer_start(unsigned int event_id, opal_timer_t *cycles)
 441 {
 442     /* Check whether cycles == 0.0 to make sure the timer hasn't started yet.
 443      * This is denoted unlikely because the counters will often be turned off.
 444      */
 445     if( OPAL_UNLIKELY(IS_SPC_BIT_SET(ompi_spc_attached_event, event_id) && *cycles == 0) ) {
 446         *cycles = opal_timer_base_get_cycles();
 447     }
 448 }
 449 
 450 /* Stops a cycle-precision timer and calculates the total elapsed time
 451  * based on the starting time in 'cycles' and stores the result in the
 452  * 'cycles' argument.
 453  */
 454 void ompi_spc_timer_stop(unsigned int event_id, opal_timer_t *cycles)
 455 {
 456     /* This is denoted unlikely because the counters will often be turned off. */
 457     if( OPAL_UNLIKELY(IS_SPC_BIT_SET(ompi_spc_attached_event, event_id)) ) {
 458         *cycles = opal_timer_base_get_cycles() - *cycles;
 459         OPAL_THREAD_ADD_FETCH_SIZE_T(&ompi_spc_events[event_id].value, (size_t) *cycles);
 460     }
 461 }
 462 
 463 /* Checks a tag, and records the user version of the counter if it's greater
 464  * than or equal to 0 and records the mpi version of the counter otherwise.
 465  */
 466 void ompi_spc_user_or_mpi(int tag, ompi_spc_value_t value, unsigned int user_enum, unsigned int mpi_enum)
 467 {
 468     SPC_RECORD( (tag >= 0 ? user_enum : mpi_enum), value);
 469 }
 470 
 471 /* Checks whether the counter denoted by value_enum exceeds the current value of the
 472  * counter denoted by watermark_enum, and if so sets the watermark_enum counter to the
 473  * value of the value_enum counter.
 474  */
 475 void ompi_spc_update_watermark(unsigned int watermark_enum, unsigned int value_enum)
 476 {
 477     /* Denoted unlikely because counters will often be turned off. */
 478     if( OPAL_UNLIKELY(IS_SPC_BIT_SET(ompi_spc_attached_event, watermark_enum) &&
 479                       IS_SPC_BIT_SET(ompi_spc_attached_event, value_enum)) ) {
 480         /* WARNING: This assumes that this function was called while a lock has already been taken.
 481          *          This function is NOT thread safe otherwise!
 482          */
 483         if(ompi_spc_events[value_enum].value > ompi_spc_events[watermark_enum].value) {
 484             ompi_spc_events[watermark_enum].value = ompi_spc_events[value_enum].value;
 485         }
 486     }
 487 }
 488 
 489 /* Converts a counter value that is in cycles to microseconds.
 490  */
 491 void ompi_spc_cycles_to_usecs(ompi_spc_value_t *cycles)
 492 {
 493     *cycles = *cycles / sys_clock_freq_mhz;
 494 }

/* [<][>][^][v][top][bottom][index][help] */