X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/de5e36cc7e45014c43cf9290b5ac8380072d69ad..ad11907f9221fee26cbe223d667a33744278f46b:/src/smpi/smpi_global.cpp diff --git a/src/smpi/smpi_global.cpp b/src/smpi/smpi_global.cpp index 1a008f954b..db6e796b2d 100644 --- a/src/smpi/smpi_global.cpp +++ b/src/smpi/smpi_global.cpp @@ -28,6 +28,16 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(smpi_kernel, smpi, "Logging specific to SMPI (ke #include #include /* trim_right / trim_left */ +#if HAVE_PAPI +#include "papi.h" +const char* papi_default_config_name = "default"; + +struct papi_process_data { + papi_counter_t counter_data; + int event_set; +}; + +#endif std::unordered_map location2speedup; typedef struct s_smpi_process_data { @@ -50,18 +60,23 @@ typedef struct s_smpi_process_data { xbt_bar_t finalization_barrier; int return_value; smpi_trace_call_location_t* trace_call_loc; +#if HAVE_PAPI + /** Contains hardware data as read by PAPI **/ + int papi_event_set; + papi_counter_t papi_counter_data; +#endif } s_smpi_process_data_t; -static smpi_process_data_t *process_data = NULL; +static smpi_process_data_t *process_data = nullptr; int process_count = 0; int smpi_universe_size = 0; -int* index_to_process_data = NULL; +int* index_to_process_data = nullptr; extern double smpi_total_benched_time; xbt_os_timer_t global_timer; MPI_Comm MPI_COMM_WORLD = MPI_COMM_UNINITIALIZED; -MPI_Errhandler *MPI_ERRORS_RETURN = NULL; -MPI_Errhandler *MPI_ERRORS_ARE_FATAL = NULL; -MPI_Errhandler *MPI_ERRHANDLER_NULL = NULL; +MPI_Errhandler *MPI_ERRORS_RETURN = nullptr; +MPI_Errhandler *MPI_ERRORS_ARE_FATAL = nullptr; +MPI_Errhandler *MPI_ERRHANDLER_NULL = nullptr; #define MAILBOX_NAME_MAXLEN (5 + sizeof(int) * 2 + 1) @@ -83,14 +98,14 @@ void smpi_process_init(int *argc, char ***argv) smpi_process_data_t data; smx_process_t proc; - if (argc != NULL && argv != NULL) { + if (argc != nullptr && argv != nullptr) { proc = SIMIX_process_self(); SIMIX_process_set_cleanup_function(proc, MSG_process_cleanup_from_SIMIX); char* instance_id = (*argv)[1]; int rank = xbt_str_parse_int((*argv)[2], "Invalid rank: %s"); index = smpi_process_index_of_smx_process(proc); - if(index_to_process_data == NULL){ + if(index_to_process_data == nullptr){ index_to_process_data=static_cast(xbt_malloc(SIMIX_process_count()*sizeof(int))); } @@ -106,7 +121,7 @@ void smpi_process_init(int *argc, char ***argv) smpi_deployment_register_process(instance_id, rank, index, &temp_comm_world, &temp_bar); data = smpi_process_remote_data(index); data->comm_world = temp_comm_world; - if(temp_bar != NULL) + if(temp_bar != nullptr) data->finalization_barrier = temp_bar; data->index = index; data->instance_id = instance_id; @@ -116,10 +131,9 @@ void smpi_process_init(int *argc, char ***argv) simdata->data = data; if (*argc > 3) { - free((*argv)[1]); memmove(&(*argv)[0], &(*argv)[2], sizeof(char *) * (*argc - 2)); - (*argv)[(*argc) - 1] = NULL; - (*argv)[(*argc) - 2] = NULL; + (*argv)[(*argc) - 1] = nullptr; + (*argv)[(*argc) - 2] = nullptr; } (*argc)-=2; data->argc = argc; @@ -129,7 +143,7 @@ void smpi_process_init(int *argc, char ***argv) XBT_DEBUG("<%d> New process in the game: %p", index, proc); } xbt_assert(smpi_process_data(), - "smpi_process_data() returned NULL. You probably gave a NULL parameter to MPI_Init. Although it's required by " + "smpi_process_data() returned nullptr. You probably gave a nullptr parameter to MPI_Init. Although it's required by " "MPI-2, this is currently not supported by SMPI."); } @@ -168,7 +182,7 @@ int smpi_process_finalized() /** @brief Check if a process is initialized */ int smpi_process_initialized() { - if (index_to_process_data == NULL){ + if (index_to_process_data == nullptr){ return false; } else{ int index = smpi_process_index(); @@ -249,14 +263,14 @@ int smpi_process_index() { smpi_process_data_t data = smpi_process_data(); //return -1 if not initialized - return data != NULL ? data->index : MPI_UNDEFINED; + return data != nullptr ? data->index : MPI_UNDEFINED; } MPI_Comm smpi_process_comm_world() { smpi_process_data_t data = smpi_process_data(); //return MPI_COMM_NULL if not initialized - return data != NULL ? *data->comm_world : MPI_COMM_NULL; + return data != nullptr ? *data->comm_world : MPI_COMM_NULL; } smx_mailbox_t smpi_process_mailbox() @@ -295,6 +309,20 @@ xbt_mutex_t smpi_process_remote_mailboxes_mutex(int index) return data->mailboxes_mutex; } +#if HAVE_PAPI +int smpi_process_papi_event_set(void) +{ + smpi_process_data_t data = smpi_process_data(); + return data->papi_event_set; +} + +papi_counter_t& smpi_process_papi_counters(void) +{ + smpi_process_data_t data = smpi_process_data(); + return data->papi_counter_data; +} +#endif + xbt_os_timer_t smpi_process_timer() { smpi_process_data_t data = smpi_process_data(); @@ -318,7 +346,7 @@ MPI_Comm smpi_process_comm_self() smpi_process_data_t data = smpi_process_data(); if(data->comm_self==MPI_COMM_NULL){ MPI_Group group = smpi_group_new(1); - data->comm_self = smpi_comm_new(group, NULL); + data->comm_self = smpi_comm_new(group, nullptr); smpi_group_set_mapping(group, smpi_process_index(), 0); } @@ -385,7 +413,7 @@ void smpi_comm_copy_buffer_callback(smx_synchro_t synchro, void *buff, size_t bu xbt_free(buff); //It seems that the request is used after the call there this should be free somewhere else but where??? //xbt_free(comm->comm.src_data);// inside SMPI the request is kept inside the user data and should be free - comm->src_buff = NULL; + comm->src_buff = nullptr; } if(tmpbuff!=buff)xbt_free(tmpbuff); @@ -410,7 +438,7 @@ static void smpi_check_options(){ } int smpi_enabled() { - return process_data != NULL; + return process_data != nullptr; } void smpi_global_init() @@ -446,16 +474,85 @@ void smpi_global_init() } } +#if HAVE_PAPI + // This map holds for each computation unit (such as "default" or "process1" etc.) + // the configuration as given by the user (counter data as a pair of (counter_name, counter_counter)) + // and the (computed) event_set. + std::map units2papi_setup; + + if (xbt_cfg_get_string("smpi/papi-events")[0] != '\0') { + if (PAPI_library_init(PAPI_VER_CURRENT) != PAPI_VER_CURRENT) + XBT_ERROR("Could not initialize PAPI library; is it correctly installed and linked?" + " Expected version is %i", + PAPI_VER_CURRENT); + + typedef boost::tokenizer> Tokenizer; + boost::char_separator separator_units(";"); + std::string str = std::string(xbt_cfg_get_string("smpi/papi-events")); + Tokenizer tokens(str, separator_units); + + // Iterate over all the computational units. This could be + // processes, hosts, threads, ranks... You name it. I'm not exactly + // sure what we will support eventually, so I'll leave it at the + // general term "units". + for (auto& unit_it : tokens) { + boost::char_separator separator_events(":"); + Tokenizer event_tokens(unit_it, separator_events); + + int event_set = PAPI_NULL; + if (PAPI_create_eventset(&event_set) != PAPI_OK) { + // TODO: Should this let the whole simulation die? + XBT_CRITICAL("Could not create PAPI event set during init."); + } + + // NOTE: We cannot use a map here, as we must obey the order of the counters + // This is important for PAPI: We need to map the values of counters back + // to the event_names (so, when PAPI_read() has finished)! + papi_counter_t counters2values; + + // Iterate over all counters that were specified for this specific + // unit. + // Note that we need to remove the name of the unit + // (that could also be the "default" value), which always comes first. + // Hence, we start at ++(events.begin())! + for (Tokenizer::iterator events_it = ++(event_tokens.begin()); events_it != event_tokens.end(); events_it++) { + + int event_code = PAPI_NULL; + char* event_name = const_cast((*events_it).c_str()); + if (PAPI_event_name_to_code(event_name, &event_code) == PAPI_OK) { + if (PAPI_add_event(event_set, event_code) != PAPI_OK) { + XBT_ERROR("Could not add PAPI event '%s'. Skipping.", event_name); + continue; + } else { + XBT_DEBUG("Successfully added PAPI event '%s' to the event set.", event_name); + } + } else { + XBT_CRITICAL("Could not find PAPI event '%s'. Skipping.", event_name); + continue; + } + + counters2values.push_back( + // We cannot just pass *events_it, as this is of type const basic_string + std::make_pair(std::string(*events_it), 0)); + } + + std::string unit_name = *(event_tokens.begin()); + papi_process_data config = {.counter_data = std::move(counters2values), .event_set = event_set}; + + units2papi_setup.insert(std::make_pair(unit_name, std::move(config))); + } + } +#endif if (process_count == 0){ process_count = SIMIX_process_count(); smpirun=1; } smpi_universe_size = process_count; - process_data = xbt_new0(smpi_process_data_t, process_count); + process_data = new smpi_process_data_t[process_count]; for (i = 0; i < process_count; i++) { - process_data[i] = xbt_new(s_smpi_process_data_t, 1); - process_data[i]->argc = NULL; - process_data[i]->argv = NULL; + process_data[i] = new s_smpi_process_data_t; + process_data[i]->argc = nullptr; + process_data[i]->argv = nullptr; process_data[i]->mailbox = simcall_mbox_create(get_mailbox_name(name, i)); process_data[i]->mailbox_small = simcall_mbox_create(get_mailbox_name_small(name, i)); process_data[i]->mailboxes_mutex = xbt_mutex_init(); @@ -464,21 +561,38 @@ void smpi_global_init() MC_ignore_heap(process_data[i]->timer, xbt_os_timer_size()); process_data[i]->comm_self = MPI_COMM_NULL; process_data[i]->comm_intra = MPI_COMM_NULL; - process_data[i]->comm_world = NULL; + process_data[i]->comm_world = nullptr; process_data[i]->state = SMPI_UNINITIALIZED; process_data[i]->sampling = 0; - process_data[i]->finalization_barrier = NULL; + process_data[i]->finalization_barrier = nullptr; process_data[i]->return_value = 0; if (xbt_cfg_get_boolean("smpi/trace-call-location")) { process_data[i]->trace_call_loc = xbt_new(smpi_trace_call_location_t, 1); } + +#if HAVE_PAPI + if (xbt_cfg_get_string("smpi/papi-events")[0] != '\0') { + // TODO: Implement host/process/thread based counters. This implementation + // just always takes the values passed via "default", like this: + // "default:COUNTER1:COUNTER2:COUNTER3;". + auto it = units2papi_setup.find(papi_default_config_name); + if (it != units2papi_setup.end()) { + process_data[i]->papi_event_set = it->second.event_set; + process_data[i]->papi_counter_data = it->second.counter_data; + XBT_DEBUG("Setting PAPI set for process %i", i); + } else { + process_data[i]->papi_event_set = PAPI_NULL; + XBT_DEBUG("No PAPI set for process %i", i); + } + } +#endif } //if the process was launched through smpirun script we generate a global mpi_comm_world //if not, we let MPI_COMM_NULL, and the comm world will be private to each mpi instance if(smpirun){ group = smpi_group_new(process_count); - MPI_COMM_WORLD = smpi_comm_new(group, NULL); + MPI_COMM_WORLD = smpi_comm_new(group, nullptr); MPI_Attr_put(MPI_COMM_WORLD, MPI_UNIVERSE_SIZE, reinterpret_cast(process_count)); xbt_bar_t bar=xbt_barrier_init(process_count); @@ -513,15 +627,15 @@ void smpi_global_destroy() if (xbt_cfg_get_boolean("smpi/trace-call-location")) { xbt_free(process_data[i]->trace_call_loc); } - xbt_free(process_data[i]); + delete process_data[i]; } - xbt_free(process_data); - process_data = NULL; + delete process_data; + process_data = nullptr; if (MPI_COMM_WORLD != MPI_COMM_UNINITIALIZED){ smpi_comm_cleanup_smp(MPI_COMM_WORLD); smpi_comm_cleanup_attributes(MPI_COMM_WORLD); - if(smpi_coll_cleanup_callback!=NULL) + if(smpi_coll_cleanup_callback!=nullptr) smpi_coll_cleanup_callback(); xbt_free(MPI_COMM_WORLD); } @@ -645,7 +759,7 @@ static void smpi_init_options(){ mpi_coll_barrier_fun = reinterpret_cast (mpi_coll_barrier_description[barrier_id].coll); - smpi_coll_cleanup_callback=NULL; + smpi_coll_cleanup_callback=nullptr; smpi_cpu_threshold = xbt_cfg_get_double("smpi/cpu-threshold"); smpi_running_power = xbt_cfg_get_double("smpi/running-power"); smpi_privatize_global_variables = xbt_cfg_get_boolean("smpi/privatize-global-variables"); @@ -657,7 +771,7 @@ int smpi_main(int (*realmain) (int argc, char *argv[]), int argc, char *argv[]) { srand(SMPI_RAND_SEED); - if (getenv("SMPI_PRETEND_CC") != NULL) { + if (getenv("SMPI_PRETEND_CC") != nullptr) { /* Hack to ensure that smpicc can pretend to be a simple compiler. Particularly handy to pass it to the * configuration tools */ return 0;