int ompi_comm_activate_nb (ompi_communicator_t **newcomm, ompi_communicator_t *comm, ompi_communicator_t *bridgecomm, const void *arg0, const void *arg1, bool send_first, int mode, ompi_request_t **req) { ompi_comm_cid_context_t *context; ompi_comm_request_t *request; ompi_request_t *subreq; int ret = 0; context = mca_comm_cid_context_alloc (*newcomm, comm, bridgecomm, arg0, arg1, "activate", send_first, mode); if (NULL == context) { return OMPI_ERR_OUT_OF_RESOURCE; } /* keep track of the pointer so it can be set to MPI_COMM_NULL on failure */ context->newcommp = newcomm; request = ompi_comm_request_get (); if (NULL == request) { OBJ_RELEASE(context); return OMPI_ERR_OUT_OF_RESOURCE; } request->context = &context->super; if (MPI_UNDEFINED != (*newcomm)->c_local_group->grp_my_rank) { /* Initialize the PML stuff in the newcomm */ if ( OMPI_SUCCESS != (ret = MCA_PML_CALL(add_comm(*newcomm))) ) { OBJ_RELEASE(newcomm); OBJ_RELEASE(context); *newcomm = MPI_COMM_NULL; return ret; } OMPI_COMM_SET_PML_ADDED(*newcomm); } /* Step 1: the barrier, after which it is allowed to * send messages over the new communicator */ ret = context->allreduce_fn (&context->ok, &context->ok, 1, MPI_MIN, context, &subreq); if (OMPI_SUCCESS != ret) { ompi_comm_request_return (request); return ret; } ompi_comm_request_schedule_append (request, ompi_comm_activate_nb_complete, &subreq, 1); ompi_comm_request_start (request); *req = &request->super; return OMPI_SUCCESS; }
int mca_pml_cm_add_comm(ompi_communicator_t* comm) { /* should never happen, but it was, so check */ if (comm->c_contextid > ompi_pml_cm.super.pml_max_contextid) { return OMPI_ERR_OUT_OF_RESOURCE; } /* initialize per-communicator data. MTLs may override this. */ comm->c_pml_comm = NULL; /* notify the MTL about the added communicator */ return OMPI_MTL_CALL(add_comm(ompi_mtl, comm)); }
/* * Parse the benv (bootenv.rc) file and break it into a benv * list. List entries may be comment blocks or commands. */ static void parse_benv(benv_des_t *bd) { int line; char *pbase, *pend; char *tok, *tnext; line = 1; pbase = (char *)bd->adr; pend = pbase + bd->len; for (tok = tnext = pbase; tnext < pend && '\0' != *tnext; tok = tnext) if (*tok == COMM) add_comm(bd, tok, pend, &tnext, &line); else add_cmd(bd, pend, &tnext, &line); }
int ompi_mpi_init(int argc, char **argv, int requested, int *provided) { int ret; ompi_proc_t** procs; size_t nprocs; char *error = NULL; struct timeval ompistart, ompistop; bool rte_setup = false; ompi_rte_collective_t *coll; char *cmd=NULL, *av=NULL; /* bitflag of the thread level support provided. To be used * for the modex in order to work in heterogeneous environments. */ uint8_t threadlevel_bf; /* Indicate that we have *started* MPI_INIT*. MPI_FINALIZE has something sorta similar in a static local variable in ompi_mpi_finalize(). */ ompi_mpi_init_started = true; /* Setup enough to check get/set MCA params */ if (OPAL_SUCCESS != (ret = opal_init_util(&argc, &argv))) { error = "ompi_mpi_init: opal_init_util failed"; goto error; } /* Register MCA variables */ if (OPAL_SUCCESS != (ret = ompi_register_mca_variables())) { error = "ompi_mpi_init: ompi_register_mca_variables failed"; goto error; } if (OPAL_SUCCESS != (ret = opal_arch_set_fortran_logical_size(sizeof(ompi_fortran_logical_t)))) { error = "ompi_mpi_init: opal_arch_set_fortran_logical_size failed"; goto error; } /* _After_ opal_init_util() but _before_ orte_init(), we need to set an MCA param that tells libevent that it's ok to use any mechanism in libevent that is available on this platform (e.g., epoll and friends). Per opal/event/event.s, we default to select/poll -- but we know that MPI processes won't be using pty's with the event engine, so it's ok to relax this constraint and let any fd-monitoring mechanism be used. */ ret = mca_base_var_find("opal", "event", "*", "event_include"); if (ret >= 0) { char *allvalue = "all"; /* We have to explicitly "set" the MCA param value here because libevent initialization will re-register the MCA param and therefore override the default. Setting the value here puts the desired value ("all") in different storage that is not overwritten if/when the MCA param is re-registered. This is unless the user has specified a different value for this MCA parameter. Make sure we check to see if the default is specified before forcing "all" in case that is not what the user desires. Note that we do *NOT* set this value as an environment variable, just so that it won't be inherited by any spawned processes and potentially cause unintented side-effects with launching RTE tools... */ mca_base_var_set_value(ret, allvalue, 4, MCA_BASE_VAR_SOURCE_DEFAULT, NULL); } if (ompi_enable_timing && 0 == OMPI_PROC_MY_NAME->vpid) { gettimeofday(&ompistart, NULL); } /* if we were not externally started, then we need to setup * some envars so the MPI_INFO_ENV can get the cmd name * and argv (but only if the user supplied a non-NULL argv!), and * the requested thread level */ if (NULL == getenv("OMPI_COMMAND") && NULL != argv && NULL != argv[0]) { asprintf(&cmd, "OMPI_COMMAND=%s", argv[0]); putenv(cmd); } if (NULL == getenv("OMPI_ARGV") && 1 < argc) { char *tmp; tmp = opal_argv_join(&argv[1], ' '); asprintf(&av, "OMPI_ARGV=%s", tmp); free(tmp); putenv(av); } /* open the rte framework */ if (OMPI_SUCCESS != (ret = mca_base_framework_open(&ompi_rte_base_framework, 0))) { error = "ompi_rte_base_open() failed"; goto error; } /* no select is required as this is a static framework */ /* Setup RTE - note that we are an MPI process */ if (OMPI_SUCCESS != (ret = ompi_rte_init(NULL, NULL))) { error = "ompi_mpi_init: ompi_rte_init failed"; goto error; } rte_setup = true; /* check for timing request - get stop time and report elapsed time if so */ if (ompi_enable_timing && 0 == OMPI_PROC_MY_NAME->vpid) { gettimeofday(&ompistop, NULL); opal_output(0, "ompi_mpi_init [%ld]: time from start to completion of rte_init %ld usec", (long)OMPI_PROC_MY_NAME->vpid, (long int)((ompistop.tv_sec - ompistart.tv_sec)*1000000 + (ompistop.tv_usec - ompistart.tv_usec))); gettimeofday(&ompistart, NULL); } #if OPAL_HAVE_HWLOC /* if hwloc is available but didn't get setup for some * reason, do so now */ if (NULL == opal_hwloc_topology) { if (OPAL_SUCCESS != (ret = opal_hwloc_base_get_topology())) { error = "Topology init"; goto error; } } #endif /* Register the default errhandler callback - RTE will ignore if it * doesn't support this capability */ ompi_rte_register_errhandler(ompi_errhandler_runtime_callback, OMPI_RTE_ERRHANDLER_LAST); /* Figure out the final MPI thread levels. If we were not compiled for support for MPI threads, then don't allow MPI_THREAD_MULTIPLE. Set this stuff up here early in the process so that other components can make decisions based on this value. */ ompi_mpi_thread_level(requested, provided); /* determine the bitflag belonging to the threadlevel_support provided */ memset ( &threadlevel_bf, 0, sizeof(uint8_t)); OMPI_THREADLEVEL_SET_BITFLAG ( ompi_mpi_thread_provided, threadlevel_bf ); /* add this bitflag to the modex */ if ( OMPI_SUCCESS != (ret = ompi_modex_send_string("MPI_THREAD_LEVEL", &threadlevel_bf, sizeof(uint8_t)))) { error = "ompi_mpi_init: modex send thread level"; goto error; } /* initialize datatypes. This step should be done early as it will * create the local convertor and local arch used in the proc * init. */ if (OMPI_SUCCESS != (ret = ompi_datatype_init())) { error = "ompi_datatype_init() failed"; goto error; } /* Initialize OMPI procs */ if (OMPI_SUCCESS != (ret = ompi_proc_init())) { error = "mca_proc_init() failed"; goto error; } /* Initialize the op framework. This has to be done *after* ddt_init, but befor mca_coll_base_open, since some collective modules (e.g., the hierarchical coll component) may need ops in their query function. */ if (OMPI_SUCCESS != (ret = mca_base_framework_open(&ompi_op_base_framework, 0))) { error = "ompi_op_base_open() failed"; goto error; } if (OMPI_SUCCESS != (ret = ompi_op_base_find_available(OMPI_ENABLE_PROGRESS_THREADS, OMPI_ENABLE_THREAD_MULTIPLE))) { error = "ompi_op_base_find_available() failed"; goto error; } if (OMPI_SUCCESS != (ret = ompi_op_init())) { error = "ompi_op_init() failed"; goto error; } /* Open up MPI-related MCA components */ if (OMPI_SUCCESS != (ret = mca_base_framework_open(&ompi_allocator_base_framework, 0))) { error = "mca_allocator_base_open() failed"; goto error; } if (OMPI_SUCCESS != (ret = mca_base_framework_open(&ompi_rcache_base_framework, 0))) { error = "mca_rcache_base_open() failed"; goto error; } if (OMPI_SUCCESS != (ret = mca_base_framework_open(&ompi_mpool_base_framework, 0))) { error = "mca_mpool_base_open() failed"; goto error; } if (OMPI_SUCCESS != (ret = mca_base_framework_open(&ompi_bml_base_framework, 0))) { error = "mca_bml_base_open() failed"; goto error; } if (OMPI_SUCCESS != (ret = mca_base_framework_open(&ompi_pml_base_framework, 0))) { error = "mca_pml_base_open() failed"; goto error; } if (OMPI_SUCCESS != (ret = mca_base_framework_open(&ompi_coll_base_framework, 0))) { error = "mca_coll_base_open() failed"; goto error; } if (OMPI_SUCCESS != (ret = mca_base_framework_open(&ompi_osc_base_framework, 0))) { error = "ompi_osc_base_open() failed"; goto error; } #if OPAL_ENABLE_FT_CR == 1 if (OMPI_SUCCESS != (ret = mca_base_framework_open(&ompi_crcp_base_framework, 0))) { error = "ompi_crcp_base_open() failed"; goto error; } #endif /* In order to reduce the common case for MPI apps (where they don't use MPI-2 IO or MPI-1 topology functions), the io and topo frameworks are initialized lazily, at the first use of relevant functions (e.g., MPI_FILE_*, MPI_CART_*, MPI_GRAPH_*), so they are not opened here. */ /* Select which MPI components to use */ if (OMPI_SUCCESS != (ret = mca_mpool_base_init(OMPI_ENABLE_PROGRESS_THREADS, OMPI_ENABLE_THREAD_MULTIPLE))) { error = "mca_mpool_base_init() failed"; goto error; } if (OMPI_SUCCESS != (ret = mca_pml_base_select(OMPI_ENABLE_PROGRESS_THREADS, OMPI_ENABLE_THREAD_MULTIPLE))) { error = "mca_pml_base_select() failed"; goto error; } /* check for timing request - get stop time and report elapsed time if so */ if (ompi_enable_timing && 0 == OMPI_PROC_MY_NAME->vpid) { gettimeofday(&ompistop, NULL); opal_output(0, "ompi_mpi_init[%ld]: time from completion of rte_init to modex %ld usec", (long)OMPI_PROC_MY_NAME->vpid, (long int)((ompistop.tv_sec - ompistart.tv_sec)*1000000 + (ompistop.tv_usec - ompistart.tv_usec))); gettimeofday(&ompistart, NULL); } /* exchange connection info - this function also acts as a barrier * as it will not return until the exchange is complete */ coll = OBJ_NEW(ompi_rte_collective_t); coll->id = ompi_process_info.peer_modex; coll->active = true; if (OMPI_SUCCESS != (ret = ompi_rte_modex(coll))) { error = "rte_modex failed"; goto error; } /* wait for modex to complete - this may be moved anywhere in mpi_init * so long as it occurs prior to calling a function that needs * the modex info! */ OMPI_WAIT_FOR_COMPLETION(coll->active); OBJ_RELEASE(coll); if (ompi_enable_timing && 0 == OMPI_PROC_MY_NAME->vpid) { gettimeofday(&ompistop, NULL); opal_output(0, "ompi_mpi_init[%ld]: time to execute modex %ld usec", (long)OMPI_PROC_MY_NAME->vpid, (long int)((ompistop.tv_sec - ompistart.tv_sec)*1000000 + (ompistop.tv_usec - ompistart.tv_usec))); gettimeofday(&ompistart, NULL); } /* select buffered send allocator component to be used */ if( OMPI_SUCCESS != (ret = mca_pml_base_bsend_init(OMPI_ENABLE_THREAD_MULTIPLE))) { error = "mca_pml_base_bsend_init() failed"; goto error; } if (OMPI_SUCCESS != (ret = mca_coll_base_find_available(OMPI_ENABLE_PROGRESS_THREADS, OMPI_ENABLE_THREAD_MULTIPLE))) { error = "mca_coll_base_find_available() failed"; goto error; } if (OMPI_SUCCESS != (ret = ompi_osc_base_find_available(OMPI_ENABLE_PROGRESS_THREADS, OMPI_ENABLE_THREAD_MULTIPLE))) { error = "ompi_osc_base_find_available() failed"; goto error; } #if OPAL_ENABLE_FT_CR == 1 if (OMPI_SUCCESS != (ret = ompi_crcp_base_select() ) ) { error = "ompi_crcp_base_select() failed"; goto error; } #endif /* io and topo components are not selected here -- see comment above about the io and topo frameworks being loaded lazily */ /* Initialize each MPI handle subsystem */ /* initialize requests */ if (OMPI_SUCCESS != (ret = ompi_request_init())) { error = "ompi_request_init() failed"; goto error; } if (OMPI_SUCCESS != (ret = ompi_message_init())) { error = "ompi_message_init() failed"; goto error; } /* initialize info */ if (OMPI_SUCCESS != (ret = ompi_info_init())) { error = "ompi_info_init() failed"; goto error; } /* initialize error handlers */ if (OMPI_SUCCESS != (ret = ompi_errhandler_init())) { error = "ompi_errhandler_init() failed"; goto error; } /* initialize error codes */ if (OMPI_SUCCESS != (ret = ompi_mpi_errcode_init())) { error = "ompi_mpi_errcode_init() failed"; goto error; } /* initialize internal error codes */ if (OMPI_SUCCESS != (ret = ompi_errcode_intern_init())) { error = "ompi_errcode_intern_init() failed"; goto error; } /* initialize groups */ if (OMPI_SUCCESS != (ret = ompi_group_init())) { error = "ompi_group_init() failed"; goto error; } /* initialize communicators */ if (OMPI_SUCCESS != (ret = ompi_comm_init())) { error = "ompi_comm_init() failed"; goto error; } /* initialize file handles */ if (OMPI_SUCCESS != (ret = ompi_file_init())) { error = "ompi_file_init() failed"; goto error; } /* initialize windows */ if (OMPI_SUCCESS != (ret = ompi_win_init())) { error = "ompi_win_init() failed"; goto error; } /* initialize attribute meta-data structure for comm/win/dtype */ if (OMPI_SUCCESS != (ret = ompi_attr_init())) { error = "ompi_attr_init() failed"; goto error; } /* identify the architectures of remote procs and setup * their datatype convertors, if required */ if (OMPI_SUCCESS != (ret = ompi_proc_complete_init())) { error = "ompi_proc_complete_init failed"; goto error; } /* If thread support was enabled, then setup OPAL to allow for them. */ if ((OMPI_ENABLE_PROGRESS_THREADS == 1) || (*provided != MPI_THREAD_SINGLE)) { opal_set_using_threads(true); } /* start PML/BTL's */ ret = MCA_PML_CALL(enable(true)); if( OMPI_SUCCESS != ret ) { error = "PML control failed"; goto error; } /* add all ompi_proc_t's to PML */ if (NULL == (procs = ompi_proc_world(&nprocs))) { error = "ompi_proc_world() failed"; goto error; } ret = MCA_PML_CALL(add_procs(procs, nprocs)); free(procs); /* If we got "unreachable", then print a specific error message. Otherwise, if we got some other failure, fall through to print a generic message. */ if (OMPI_ERR_UNREACH == ret) { opal_show_help("help-mpi-runtime", "mpi_init:startup:pml-add-procs-fail", true); error = NULL; goto error; } else if (OMPI_SUCCESS != ret) { error = "PML add procs failed"; goto error; } MCA_PML_CALL(add_comm(&ompi_mpi_comm_world.comm)); MCA_PML_CALL(add_comm(&ompi_mpi_comm_self.comm)); /* * Dump all MCA parameters if requested */ if (ompi_mpi_show_mca_params) { ompi_show_all_mca_params(ompi_mpi_comm_world.comm.c_my_rank, nprocs, ompi_process_info.nodename); } /* Do we need to wait for a debugger? */ ompi_rte_wait_for_debugger(); /* check for timing request - get stop time and report elapsed time if so, then start the clock again */ if (ompi_enable_timing && 0 == OMPI_PROC_MY_NAME->vpid) { gettimeofday(&ompistop, NULL); opal_output(0, "ompi_mpi_init[%ld]: time from modex to first barrier %ld usec", (long)OMPI_PROC_MY_NAME->vpid, (long int)((ompistop.tv_sec - ompistart.tv_sec)*1000000 + (ompistop.tv_usec - ompistart.tv_usec))); gettimeofday(&ompistart, NULL); } /* wait for everyone to reach this point */ coll = OBJ_NEW(ompi_rte_collective_t); coll->id = ompi_process_info.peer_init_barrier; coll->active = true; if (OMPI_SUCCESS != (ret = ompi_rte_barrier(coll))) { error = "rte_barrier failed"; goto error; } /* wait for barrier to complete */ OMPI_WAIT_FOR_COMPLETION(coll->active); OBJ_RELEASE(coll); /* check for timing request - get stop time and report elapsed time if so, then start the clock again */ if (ompi_enable_timing && 0 == OMPI_PROC_MY_NAME->vpid) { gettimeofday(&ompistop, NULL); opal_output(0, "ompi_mpi_init[%ld]: time to execute barrier %ld usec", (long)OMPI_PROC_MY_NAME->vpid, (long int)((ompistop.tv_sec - ompistart.tv_sec)*1000000 + (ompistop.tv_usec - ompistart.tv_usec))); gettimeofday(&ompistart, NULL); } #if OMPI_ENABLE_PROGRESS_THREADS == 0 /* Start setting up the event engine for MPI operations. Don't block in the event library, so that communications don't take forever between procs in the dynamic code. This will increase CPU utilization for the remainder of MPI_INIT when we are blocking on RTE-level events, but may greatly reduce non-TCP latency. */ opal_progress_set_event_flag(OPAL_EVLOOP_NONBLOCK); #endif /* wire up the mpi interface, if requested. Do this after the non-block switch for non-TCP performance. Do before the polling change as anyone with a complex wire-up is going to be using the oob. */ if (OMPI_SUCCESS != (ret = ompi_init_preconnect_mpi())) { error = "ompi_mpi_do_preconnect_all() failed"; goto error; } /* Setup the publish/subscribe (PUBSUB) framework */ if (OMPI_SUCCESS != (ret = mca_base_framework_open(&ompi_pubsub_base_framework, 0))) { error = "mca_pubsub_base_open() failed"; goto error; } if (OMPI_SUCCESS != (ret = ompi_pubsub_base_select())) { error = "ompi_pubsub_base_select() failed"; goto error; } /* Setup the dynamic process management (DPM) framework */ if (OMPI_SUCCESS != (ret = mca_base_framework_open(&ompi_dpm_base_framework, 0))) { error = "ompi_dpm_base_open() failed"; goto error; } if (OMPI_SUCCESS != (ret = ompi_dpm_base_select())) { error = "ompi_dpm_base_select() failed"; goto error; } /* Determine the overall threadlevel support of all processes in MPI_COMM_WORLD. This has to be done before calling coll_base_comm_select, since some of the collective components e.g. hierarch, might create subcommunicators. The threadlevel requested by all processes is required in order to know which cid allocation algorithm can be used. */ if ( OMPI_SUCCESS != ( ret = ompi_comm_cid_init ())) { error = "ompi_mpi_init: ompi_comm_cid_init failed"; goto error; } /* Init coll for the comms. This has to be after dpm_base_select, (since dpm.mark_dyncomm is not set in the communicator creation function else), but before dpm.dyncom_init, since this function might require collective for the CID allocation. */ if (OMPI_SUCCESS != (ret = mca_coll_base_comm_select(MPI_COMM_WORLD))) { error = "mca_coll_base_comm_select(MPI_COMM_WORLD) failed"; goto error; } if (OMPI_SUCCESS != (ret = mca_coll_base_comm_select(MPI_COMM_SELF))) { error = "mca_coll_base_comm_select(MPI_COMM_SELF) failed"; goto error; } /* Check whether we have been spawned or not. We introduce that at the very end, since we need collectives, datatypes, ptls etc. up and running here.... */ if (OMPI_SUCCESS != (ret = ompi_dpm.dyn_init())) { error = "ompi_comm_dyn_init() failed"; goto error; } /* * Startup the Checkpoint/Restart Mech. * Note: Always do this so tools don't hang when * in a non-checkpointable build */ if (OMPI_SUCCESS != (ret = ompi_cr_init())) { error = "ompi_cr_init"; goto error; } /* Undo OPAL calling opal_progress_event_users_increment() during opal_init, to get better latency when not using TCP. Do this *after* dyn_init, as dyn init uses lots of RTE communication and we don't want to hinder the performance of that code. */ opal_progress_event_users_decrement(); /* see if yield_when_idle was specified - if so, use it */ opal_progress_set_yield_when_idle(ompi_mpi_yield_when_idle); /* negative value means use default - just don't do anything */ if (ompi_mpi_event_tick_rate >= 0) { opal_progress_set_event_poll_rate(ompi_mpi_event_tick_rate); } /* At this point, we are fully configured and in MPI mode. Any communication calls here will work exactly like they would in the user's code. Setup the connections between procs and warm them up with simple sends, if requested */ if (OMPI_SUCCESS != (ret = ompi_mpiext_init())) { error = "ompi_mpiext_init"; goto error; } /* Fall through */ error: if (ret != OMPI_SUCCESS) { /* Only print a message if one was not already printed */ if (NULL != error) { const char *err_msg = opal_strerror(ret); /* If RTE was not setup yet, don't use opal_show_help */ if (rte_setup) { opal_show_help("help-mpi-runtime", "mpi_init:startup:internal-failure", true, "MPI_INIT", "MPI_INIT", error, err_msg, ret); } else { opal_show_help("help-mpi-runtime", "mpi_init:startup:internal-failure", true, "MPI_INIT", "MPI_INIT", error, err_msg, ret); } } return ret; } /* Initialize the registered datarep list to be empty */ OBJ_CONSTRUCT(&ompi_registered_datareps, opal_list_t); /* Initialize the arrays used to store the F90 types returned by the * MPI_Type_create_f90_XXX functions. */ OBJ_CONSTRUCT( &ompi_mpi_f90_integer_hashtable, opal_hash_table_t); opal_hash_table_init(&ompi_mpi_f90_integer_hashtable, 16 /* why not? */); OBJ_CONSTRUCT( &ompi_mpi_f90_real_hashtable, opal_hash_table_t); opal_hash_table_init(&ompi_mpi_f90_real_hashtable, FLT_MAX_10_EXP); OBJ_CONSTRUCT( &ompi_mpi_f90_complex_hashtable, opal_hash_table_t); opal_hash_table_init(&ompi_mpi_f90_complex_hashtable, FLT_MAX_10_EXP); /* All done. Wasn't that simple? */ ompi_mpi_initialized = true; /* check for timing request - get stop time and report elapsed time if so */ if (ompi_enable_timing && 0 == OMPI_PROC_MY_NAME->vpid) { gettimeofday(&ompistop, NULL); opal_output(0, "ompi_mpi_init[%ld]: time from barrier to complete mpi_init %ld usec", (long)OMPI_PROC_MY_NAME->vpid, (long int)((ompistop.tv_sec - ompistart.tv_sec)*1000000 + (ompistop.tv_usec - ompistart.tv_usec))); } return MPI_SUCCESS; }
/* This routine serves two purposes: * - the allreduce acts as a kind of Barrier, * which avoids, that we have incoming fragments * on the new communicator before everybody has set * up the comm structure. * - some components (e.g. the collective MagPIe component * might want to generate new communicators and communicate * using the new comm. Thus, it can just be called after * the 'barrier'. * * The reason that this routine is in comm_cid and not in * comm.c is, that this file contains the allreduce implementations * which are required, and thus we avoid having duplicate code... */ int ompi_comm_activate ( ompi_communicator_t** newcomm, ompi_communicator_t* comm, ompi_communicator_t* bridgecomm, void* local_leader, void* remote_leader, int mode, int send_first ) { int ret = 0; int ok=0, gok=0; ompi_comm_cid_allredfct* allredfnct; /* Step 1: the barrier, after which it is allowed to * send messages over the new communicator */ switch (mode) { case OMPI_COMM_CID_INTRA: allredfnct=(ompi_comm_cid_allredfct*)ompi_comm_allreduce_intra; break; case OMPI_COMM_CID_INTER: allredfnct=(ompi_comm_cid_allredfct*)ompi_comm_allreduce_inter; break; case OMPI_COMM_CID_INTRA_BRIDGE: allredfnct=(ompi_comm_cid_allredfct*)ompi_comm_allreduce_intra_bridge; break; case OMPI_COMM_CID_INTRA_OOB: allredfnct=(ompi_comm_cid_allredfct*)ompi_comm_allreduce_intra_oob; break; default: return MPI_UNDEFINED; break; } if (MPI_UNDEFINED != (*newcomm)->c_local_group->grp_my_rank) { /* Initialize the PML stuff in the newcomm */ if ( OMPI_SUCCESS != (ret = MCA_PML_CALL(add_comm(*newcomm))) ) { goto bail_on_error; } OMPI_COMM_SET_PML_ADDED(*newcomm); } (allredfnct)(&ok, &gok, 1, MPI_MIN, comm, bridgecomm, local_leader, remote_leader, send_first ); /** * Check to see if this process is in the new communicator. * * Specifically, this function is invoked by all proceses in the * old communicator, regardless of whether they are in the new * communicator or not. This is because it is far simpler to use * MPI collective functions on the old communicator to determine * some data for the new communicator (e.g., remote_leader) than * to kludge up our own pseudo-collective routines over just the * processes in the new communicator. Hence, *all* processes in * the old communicator need to invoke this function. * * That being said, only processes in the new communicator need to * select a coll module for the new communicator. More * specifically, proceses who are not in the new communicator * should *not* select a coll module -- for example, * ompi_comm_rank(newcomm) returns MPI_UNDEFINED for processes who * are not in the new communicator. This can cause errors in the * selection / initialization of a coll module. Plus, it's * wasteful -- processes in the new communicator will end up * freeing the new communicator anyway, so we might as well leave * the coll selection as NULL (the coll base comm unselect code * handles that case properly). */ if (MPI_UNDEFINED == (*newcomm)->c_local_group->grp_my_rank) { return OMPI_SUCCESS; } /* Let the collectives components fight over who will do collective on this new comm. */ if (OMPI_SUCCESS != (ret = mca_coll_base_comm_select(*newcomm))) { goto bail_on_error; } /* For an inter communicator, we have to deal with the potential * problem of what is happening if the local_comm that we created * has a lower CID than the parent comm. This is not a problem * as long as the user calls MPI_Comm_free on the inter communicator. * However, if the communicators are not freed by the user but released * by Open MPI in MPI_Finalize, we walk through the list of still available * communicators and free them one by one. Thus, local_comm is freed before * the actual inter-communicator. However, the local_comm pointer in the * inter communicator will still contain the 'previous' address of the local_comm * and thus this will lead to a segmentation violation. In order to prevent * that from happening, we increase the reference counter local_comm * by one if its CID is lower than the parent. We cannot increase however * its reference counter if the CID of local_comm is larger than * the CID of the inter communicators, since a regular MPI_Comm_free would * leave in that the case the local_comm hanging around and thus we would not * recycle CID's properly, which was the reason and the cause for this trouble. */ if ( OMPI_COMM_IS_INTER(*newcomm)) { if ( OMPI_COMM_CID_IS_LOWER(*newcomm, comm)) { OMPI_COMM_SET_EXTRA_RETAIN (*newcomm); OBJ_RETAIN (*newcomm); } } return OMPI_SUCCESS; bail_on_error: OBJ_RELEASE(*newcomm); *newcomm = MPI_COMM_NULL; return ret; }
int ompi_mpi_init(int argc, char **argv, int requested, int *provided) { int ret; ompi_proc_t** procs; size_t nprocs; char *error = NULL; bool timing = false; int param, value; struct timeval ompistart, ompistop; char *event_val = NULL; opal_paffinity_base_cpu_set_t mask; bool proc_bound; #if 0 /* see comment below about sched_yield */ int num_processors; #endif bool orte_setup = false; bool paffinity_enabled = false; /* Setup enough to check get/set MCA params */ if (ORTE_SUCCESS != (ret = opal_init_util())) { error = "ompi_mpi_init: opal_init_util failed"; goto error; } /* _After_ opal_init_util() but _before_ orte_init(), we need to set an MCA param that tells libevent that it's ok to use any mechanism in libevent that is available on this platform (e.g., epoll and friends). Per opal/event/event.s, we default to select/poll -- but we know that MPI processes won't be using pty's with the event engine, so it's ok to relax this constraint and let any fd-monitoring mechanism be used. */ ret = mca_base_param_reg_string_name("opal", "event_include", "Internal orted MCA param: tell opal_init() to use a specific mechanism in libevent", false, false, "all", &event_val); if (ret >= 0) { /* We have to explicitly "set" the MCA param value here because libevent initialization will re-register the MCA param and therefore override the default. Setting the value here puts the desired value ("all") in different storage that is not overwritten if/when the MCA param is re-registered. This is unless the user has specified a different value for this MCA parameter. Make sure we check to see if the default is specified before forcing "all" in case that is not what the user desires. Note that we do *NOT* set this value as an environment variable, just so that it won't be inherited by any spawned processes and potentially cause unintented side-effects with launching ORTE tools... */ if (0 == strcmp("all", event_val)) { mca_base_param_set_string(ret, "all"); } } if( NULL != event_val ) { free(event_val); event_val = NULL; } /* check to see if we want timing information */ param = mca_base_param_reg_int_name("ompi", "timing", "Request that critical timing loops be measured", false, false, 0, &value); if (value != 0) { timing = true; gettimeofday(&ompistart, NULL); } /* Setup ORTE - note that we are not a tool */ if (ORTE_SUCCESS != (ret = orte_init(ORTE_NON_TOOL))) { error = "ompi_mpi_init: orte_init failed"; goto error; } orte_setup = true; /* check for timing request - get stop time and report elapsed time if so */ if (timing && 0 == ORTE_PROC_MY_NAME->vpid) { gettimeofday(&ompistop, NULL); opal_output(0, "ompi_mpi_init [%ld]: time from start to completion of orte_init %ld usec", (long)ORTE_PROC_MY_NAME->vpid, (long int)((ompistop.tv_sec - ompistart.tv_sec)*1000000 + (ompistop.tv_usec - ompistart.tv_usec))); gettimeofday(&ompistart, NULL); } /* Figure out the final MPI thread levels. If we were not compiled for support for MPI threads, then don't allow MPI_THREAD_MULTIPLE. Set this stuff up here early in the process so that other components can make decisions based on this value. */ ompi_mpi_thread_requested = requested; if (OMPI_HAVE_THREAD_SUPPORT == 0) { ompi_mpi_thread_provided = *provided = MPI_THREAD_SINGLE; ompi_mpi_main_thread = NULL; } else if (OMPI_ENABLE_MPI_THREADS == 1) { ompi_mpi_thread_provided = *provided = requested; ompi_mpi_main_thread = opal_thread_get_self(); } else { if (MPI_THREAD_MULTIPLE == requested) { ompi_mpi_thread_provided = *provided = MPI_THREAD_SERIALIZED; } else { ompi_mpi_thread_provided = *provided = requested; } ompi_mpi_main_thread = opal_thread_get_self(); } ompi_mpi_thread_multiple = (ompi_mpi_thread_provided == MPI_THREAD_MULTIPLE); /* Once we've joined the RTE, see if any MCA parameters were passed to the MPI level */ if (OMPI_SUCCESS != (ret = ompi_mpi_register_params())) { error = "mca_mpi_register_params() failed"; goto error; } /* if it hasn't already been done, setup process affinity. * First check to see if a slot list was * specified. If so, use it. If no slot list was specified, * that's not an error -- just fall through and try the next * paffinity scheme. */ ret = opal_paffinity_base_get(&mask); if (OPAL_SUCCESS == ret) { /* paffinity is supported - check for binding */ OPAL_PAFFINITY_PROCESS_IS_BOUND(mask, &proc_bound); if (proc_bound) { /* someone external set it - indicate it is set * so that we know */ paffinity_enabled = true; } else { /* the system is capable of doing processor affinity, but it * has not yet been set - see if a slot_list was given */ if (NULL != opal_paffinity_base_slot_list) { /* It's an error if multiple paffinity schemes were specified */ if (opal_paffinity_alone) { ret = OMPI_ERR_BAD_PARAM; error = "Multiple processor affinity schemes specified (can only specify one)"; goto error; } ret = opal_paffinity_base_slot_list_set((long)ORTE_PROC_MY_NAME->vpid, opal_paffinity_base_slot_list); if (OPAL_ERR_NOT_FOUND != ret) { error = "opal_paffinity_base_slot_list_set() returned an error"; goto error; } paffinity_enabled = true; } else if (opal_paffinity_alone) { /* no slot_list, but they asked for paffinity */ int phys_cpu; orte_node_rank_t nrank; if (ORTE_NODE_RANK_INVALID == (nrank = orte_ess.get_node_rank(ORTE_PROC_MY_NAME))) { error = "Could not get node rank - cannot set processor affinity"; goto error; } OPAL_PAFFINITY_CPU_ZERO(mask); phys_cpu = opal_paffinity_base_get_physical_processor_id(nrank); if (0 > phys_cpu) { error = "Could not get physical processor id - cannot set processor affinity"; goto error; } OPAL_PAFFINITY_CPU_SET(phys_cpu, mask); ret = opal_paffinity_base_set(mask); if (OPAL_SUCCESS != ret) { error = "Setting processor affinity failed"; goto error; } paffinity_enabled = true; } } } /* If we were able to set processor affinity, try setting up memory affinity */ if (!opal_maffinity_setup && paffinity_enabled) { if (OPAL_SUCCESS == opal_maffinity_base_open() && OPAL_SUCCESS == opal_maffinity_base_select()) { opal_maffinity_setup = true; } } /* initialize datatypes. This step should be done early as it will * create the local convertor and local arch used in the proc * init. */ if (OMPI_SUCCESS != (ret = ompi_ddt_init())) { error = "ompi_ddt_init() failed"; goto error; } /* Initialize OMPI procs */ if (OMPI_SUCCESS != (ret = ompi_proc_init())) { error = "mca_proc_init() failed"; goto error; } /* initialize ops. This has to be done *after* ddt_init, but befor mca_coll_base_open, since come collective modules (e.g. the hierarchical) need them in the query function */ if (OMPI_SUCCESS != (ret = ompi_op_init())) { error = "ompi_op_init() failed"; goto error; } /* Open up MPI-related MCA components */ if (OMPI_SUCCESS != (ret = mca_allocator_base_open())) { error = "mca_allocator_base_open() failed"; goto error; } if (OMPI_SUCCESS != (ret = mca_rcache_base_open())) { error = "mca_rcache_base_open() failed"; goto error; } if (OMPI_SUCCESS != (ret = mca_mpool_base_open())) { error = "mca_mpool_base_open() failed"; goto error; } if (OMPI_SUCCESS != (ret = mca_pml_base_open())) { error = "mca_pml_base_open() failed"; goto error; } if (OMPI_SUCCESS != (ret = mca_coll_base_open())) { error = "mca_coll_base_open() failed"; goto error; } if (OMPI_SUCCESS != (ret = ompi_osc_base_open())) { error = "ompi_osc_base_open() failed"; goto error; } #if OPAL_ENABLE_FT == 1 if (OMPI_SUCCESS != (ret = ompi_crcp_base_open())) { error = "ompi_crcp_base_open() failed"; goto error; } #endif /* In order to reduce the common case for MPI apps (where they don't use MPI-2 IO or MPI-1 topology functions), the io and topo frameworks are initialized lazily, at the first use of relevant functions (e.g., MPI_FILE_*, MPI_CART_*, MPI_GRAPH_*), so they are not opened here. */ /* Select which MPI components to use */ if (OMPI_SUCCESS != (ret = mca_mpool_base_init(OMPI_ENABLE_PROGRESS_THREADS, OMPI_ENABLE_MPI_THREADS))) { error = "mca_mpool_base_init() failed"; goto error; } if (OMPI_SUCCESS != (ret = mca_pml_base_select(OMPI_ENABLE_PROGRESS_THREADS, OMPI_ENABLE_MPI_THREADS))) { error = "mca_pml_base_select() failed"; goto error; } /* select buffered send allocator component to be used */ ret=mca_pml_base_bsend_init(OMPI_ENABLE_MPI_THREADS); if( OMPI_SUCCESS != ret ) { error = "mca_pml_base_bsend_init() failed"; goto error; } if (OMPI_SUCCESS != (ret = mca_coll_base_find_available(OMPI_ENABLE_PROGRESS_THREADS, OMPI_ENABLE_MPI_THREADS))) { error = "mca_coll_base_find_available() failed"; goto error; } if (OMPI_SUCCESS != (ret = ompi_osc_base_find_available(OMPI_ENABLE_PROGRESS_THREADS, OMPI_ENABLE_MPI_THREADS))) { error = "ompi_osc_base_find_available() failed"; goto error; } #if OPAL_ENABLE_FT == 1 if (OMPI_SUCCESS != (ret = ompi_crcp_base_select() ) ) { error = "ompi_crcp_base_select() failed"; goto error; } #endif /* io and topo components are not selected here -- see comment above about the io and topo frameworks being loaded lazily */ /* Initialize each MPI handle subsystem */ /* initialize requests */ if (OMPI_SUCCESS != (ret = ompi_request_init())) { error = "ompi_request_init() failed"; goto error; } /* initialize info */ if (OMPI_SUCCESS != (ret = ompi_info_init())) { error = "ompi_info_init() failed"; goto error; } /* initialize error handlers */ if (OMPI_SUCCESS != (ret = ompi_errhandler_init())) { error = "ompi_errhandler_init() failed"; goto error; } /* initialize error codes */ if (OMPI_SUCCESS != (ret = ompi_mpi_errcode_init())) { error = "ompi_mpi_errcode_init() failed"; goto error; } /* initialize internal error codes */ if (OMPI_SUCCESS != (ret = ompi_errcode_intern_init())) { error = "ompi_errcode_intern_init() failed"; goto error; } /* initialize groups */ if (OMPI_SUCCESS != (ret = ompi_group_init())) { error = "ompi_group_init() failed"; goto error; } /* initialize communicators */ if (OMPI_SUCCESS != (ret = ompi_comm_init())) { error = "ompi_comm_init() failed"; goto error; } /* initialize file handles */ if (OMPI_SUCCESS != (ret = ompi_file_init())) { error = "ompi_file_init() failed"; goto error; } /* initialize windows */ if (OMPI_SUCCESS != (ret = ompi_win_init())) { error = "ompi_win_init() failed"; goto error; } /* initialize attribute meta-data structure for comm/win/dtype */ if (OMPI_SUCCESS != (ret = ompi_attr_init())) { error = "ompi_attr_init() failed"; goto error; } /* check for timing request - get stop time and report elapsed time if so */ if (timing && 0 == ORTE_PROC_MY_NAME->vpid) { gettimeofday(&ompistop, NULL); opal_output(0, "ompi_mpi_init[%ld]: time from completion of orte_init to modex %ld usec", (long)ORTE_PROC_MY_NAME->vpid, (long int)((ompistop.tv_sec - ompistart.tv_sec)*1000000 + (ompistop.tv_usec - ompistart.tv_usec))); gettimeofday(&ompistart, NULL); } /* exchange connection info - this function also acts as a barrier * as it will not return until the exchange is complete */ if (OMPI_SUCCESS != (ret = orte_grpcomm.modex(NULL))) { error = "orte_grpcomm_modex failed"; goto error; } if (timing && 0 == ORTE_PROC_MY_NAME->vpid) { gettimeofday(&ompistop, NULL); opal_output(0, "ompi_mpi_init[%ld]: time to execute modex %ld usec", (long)ORTE_PROC_MY_NAME->vpid, (long int)((ompistop.tv_sec - ompistart.tv_sec)*1000000 + (ompistop.tv_usec - ompistart.tv_usec))); gettimeofday(&ompistart, NULL); } /* identify the architectures of remote procs and setup * their datatype convertors, if required */ if (OMPI_SUCCESS != (ret = ompi_proc_set_arch())) { error = "ompi_proc_set_arch failed"; goto error; } /* If thread support was enabled, then setup OPAL to allow for them. */ if ((OMPI_ENABLE_PROGRESS_THREADS == 1) || (*provided != MPI_THREAD_SINGLE)) { opal_set_using_threads(true); } /* start PML/BTL's */ ret = MCA_PML_CALL(enable(true)); if( OMPI_SUCCESS != ret ) { error = "PML control failed"; goto error; } /* add all ompi_proc_t's to PML */ if (NULL == (procs = ompi_proc_world(&nprocs))) { error = "ompi_proc_world() failed"; goto error; } ret = MCA_PML_CALL(add_procs(procs, nprocs)); free(procs); if( OMPI_SUCCESS != ret ) { error = "PML add procs failed"; goto error; } MCA_PML_CALL(add_comm(&ompi_mpi_comm_world.comm)); MCA_PML_CALL(add_comm(&ompi_mpi_comm_self.comm)); /* * Dump all MCA parameters if requested */ if (ompi_mpi_show_mca_params) { ompi_show_all_mca_params(ompi_mpi_comm_world.comm.c_my_rank, nprocs, orte_process_info.nodename); } /* Do we need to wait for a debugger? */ ompi_wait_for_debugger(); /* check for timing request - get stop time and report elapsed time if so, then start the clock again */ if (timing && 0 == ORTE_PROC_MY_NAME->vpid) { gettimeofday(&ompistop, NULL); opal_output(0, "ompi_mpi_init[%ld]: time from modex thru complete oob wireup %ld usec", (long)ORTE_PROC_MY_NAME->vpid, (long int)((ompistop.tv_sec - ompistart.tv_sec)*1000000 + (ompistop.tv_usec - ompistart.tv_usec))); gettimeofday(&ompistart, NULL); } /* wait for everyone to reach this point */ if (OMPI_SUCCESS != (ret = orte_grpcomm.barrier())) { error = "orte_grpcomm_barrier failed"; goto error; } /* check for timing request - get stop time and report elapsed time if so, then start the clock again */ if (timing && 0 == ORTE_PROC_MY_NAME->vpid) { gettimeofday(&ompistop, NULL); opal_output(0, "ompi_mpi_init[%ld]: time to execute barrier %ld usec", (long)ORTE_PROC_MY_NAME->vpid, (long int)((ompistop.tv_sec - ompistart.tv_sec)*1000000 + (ompistop.tv_usec - ompistart.tv_usec))); gettimeofday(&ompistart, NULL); } #if OMPI_ENABLE_PROGRESS_THREADS == 0 /* Start setting up the event engine for MPI operations. Don't block in the event library, so that communications don't take forever between procs in the dynamic code. This will increase CPU utilization for the remainder of MPI_INIT when we are blocking on ORTE-level events, but may greatly reduce non-TCP latency. */ opal_progress_set_event_flag(OPAL_EVLOOP_NONBLOCK); #endif /* wire up the mpi interface, if requested. Do this after the non-block switch for non-TCP performance. Do before the polling change as anyone with a complex wire-up is going to be using the oob. */ if (OMPI_SUCCESS != (ret = ompi_init_preconnect_mpi())) { error = "ompi_mpi_do_preconnect_all() failed"; goto error; } /* Setup the publish/subscribe (PUBSUB) framework */ if (OMPI_SUCCESS != (ret = ompi_pubsub_base_open())) { error = "ompi_pubsub_base_open() failed"; goto error; } if (OMPI_SUCCESS != (ret = ompi_pubsub_base_select())) { error = "ompi_pubsub_base_select() failed"; goto error; } /* Setup the dynamic process management (DPM) framework */ if (OMPI_SUCCESS != (ret = ompi_dpm_base_open())) { error = "ompi_dpm_base_open() failed"; goto error; } if (OMPI_SUCCESS != (ret = ompi_dpm_base_select())) { error = "ompi_dpm_base_select() failed"; goto error; } /* Init coll for the comms. This has to be after dpm_base_select, (since dpm.mark_dyncomm is not set in the communicator creation function else), but before dpm.dyncom_init, since this function might require collective for the CID allocation. */ if (OMPI_SUCCESS != (ret = mca_coll_base_comm_select(MPI_COMM_WORLD))) { error = "mca_coll_base_comm_select(MPI_COMM_WORLD) failed"; goto error; } if (OMPI_SUCCESS != (ret = mca_coll_base_comm_select(MPI_COMM_SELF))) { error = "mca_coll_base_comm_select(MPI_COMM_SELF) failed"; goto error; } /* Check whether we have been spawned or not. We introduce that at the very end, since we need collectives, datatypes, ptls etc. up and running here.... */ if (OMPI_SUCCESS != (ret = ompi_dpm.dyn_init())) { error = "ompi_comm_dyn_init() failed"; goto error; } /* * Startup the Checkpoint/Restart Mech. * Note: Always do this so tools don't hang when * in a non-checkpointable build */ if (OMPI_SUCCESS != (ret = ompi_cr_init())) { error = "ompi_cr_init"; goto error; } /* Undo OPAL calling opal_progress_event_users_increment() during opal_init, to get better latency when not using TCP. Do this *after* dyn_init, as dyn init uses lots of ORTE communication and we don't want to hinder the performance of that code. */ opal_progress_event_users_decrement(); /* see if yield_when_idle was specified - if so, use it */ param = mca_base_param_find("mpi", NULL, "yield_when_idle"); mca_base_param_lookup_int(param, &value); if (value < 0) { /* if no info is provided, just default to conservative */ opal_progress_set_yield_when_idle(true); } else { /* info was provided, so set idle accordingly */ opal_progress_set_yield_when_idle(value == 0 ? false : true); } param = mca_base_param_find("mpi", NULL, "event_tick_rate"); mca_base_param_lookup_int(param, &value); /* negative value means use default - just don't do anything */ if (value >= 0) { opal_progress_set_event_poll_rate(value); } /* At this point, we are fully configured and in MPI mode. Any communication calls here will work exactly like they would in the user's code. Setup the connections between procs and warm them up with simple sends, if requested */ error: if (ret != OMPI_SUCCESS) { const char *err_msg = opal_strerror(ret); /* If ORTE was not setup yet, don't use orte_show_help */ if (orte_setup) { orte_show_help("help-mpi-runtime", "mpi_init:startup:internal-failure", true, "MPI_INIT", "MPI_INIT", error, err_msg, ret); } else { opal_show_help("help-mpi-runtime", "mpi_init:startup:internal-failure", true, "MPI_INIT", "MPI_INIT", error, err_msg, ret); } return ret; } /* Initialize the registered datarep list to be empty */ OBJ_CONSTRUCT(&ompi_registered_datareps, opal_list_t); /* Initialize the arrays used to store the F90 types returned by the * MPI_Type_create_f90_XXX functions. */ OBJ_CONSTRUCT( &ompi_mpi_f90_integer_hashtable, opal_hash_table_t); opal_hash_table_init(&ompi_mpi_f90_integer_hashtable, 16 /* why not? */); OBJ_CONSTRUCT( &ompi_mpi_f90_real_hashtable, opal_hash_table_t); opal_hash_table_init(&ompi_mpi_f90_real_hashtable, FLT_MAX_10_EXP); OBJ_CONSTRUCT( &ompi_mpi_f90_complex_hashtable, opal_hash_table_t); opal_hash_table_init(&ompi_mpi_f90_complex_hashtable, FLT_MAX_10_EXP); /* All done. Wasn't that simple? */ ompi_mpi_initialized = true; /* check for timing request - get stop time and report elapsed time if so */ if (timing && 0 == ORTE_PROC_MY_NAME->vpid) { gettimeofday(&ompistop, NULL); opal_output(0, "ompi_mpi_init[%ld]: time from barrier p to complete mpi_init %ld usec", (long)ORTE_PROC_MY_NAME->vpid, (long int)((ompistop.tv_sec - ompistart.tv_sec)*1000000 + (ompistop.tv_usec - ompistart.tv_usec))); } return MPI_SUCCESS; }