2016-05-07 14:12:01 +03:00
|
|
|
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
|
2007-04-23 22:28:20 +04:00
|
|
|
/*
|
2010-03-13 02:57:50 +03:00
|
|
|
* Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana
|
2007-04-23 22:28:20 +04:00
|
|
|
* University Research and Technology
|
|
|
|
* Corporation. All rights reserved.
|
2011-06-24 00:38:02 +04:00
|
|
|
* Copyright (c) 2004-2011 The University of Tennessee and The University
|
2007-04-23 22:28:20 +04:00
|
|
|
* of Tennessee Research Foundation. All rights
|
|
|
|
* reserved.
|
|
|
|
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
|
|
|
* University of Stuttgart. All rights reserved.
|
|
|
|
* Copyright (c) 2004-2005 The Regents of the University of California.
|
|
|
|
* All rights reserved.
|
2013-05-18 01:45:49 +04:00
|
|
|
* Copyright (c) 2007-2013 Cisco Systems, Inc. All rights reserved.
|
2016-05-07 14:12:01 +03:00
|
|
|
* Copyright (c) 2007-2016 Los Alamos National Security, LLC. All rights
|
2015-06-24 06:59:57 +03:00
|
|
|
* reserved.
|
Repair the tree spawn. The problem seems to come from the fact
that now the HNP send the messages using the routed component. In the case
of tree spawn, when a intermediary node spawn a child it doesn't know how
to forward a message to it, so when the node-map message is coming from
the HNP (as there is nothing yet in the contact/routing table) the message
is sent back the way it came. As a result the node-map message keeps jumping
between the HNP and the first level orteds.
The solution is to add a new option to the children orte_parent_uri, which
is only set when the orted is _not_ directly spawned by the HNP. When this
option is present on the argument list, the orted will add the parent to
its routing, and force the parent to update his routes (by sending the URI).
With this approach, the routing tree is build in same time as the processes
are spawned, and all messages from the HNP can be routed to the leaves.
However, this is far from an optimal solution. Right now, this so called tree
spawn, only spawn the children in a tree without doing anything about the
"connect back to the HNP" step. The HNP is flooded with reports from all the
orted. The total number of messages is higher than in the non tree startup
scheme, so we do not expect this approach to be scalable in the current
incarnation. A complete overhaul of the tree startup is required in order
improve the scalability. Stay tuned!
This commit was SVN r21504.
2009-06-24 02:10:25 +04:00
|
|
|
* Copyright (c) 2009 Institut National de Recherche en Informatique
|
|
|
|
* et Automatique. All rights reserved.
|
2015-06-24 06:59:57 +03:00
|
|
|
* Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved.
|
2016-02-17 19:32:17 +03:00
|
|
|
* Copyright (c) 2013-2016 Intel, Inc. All rights reserved.
|
2016-09-19 07:37:08 +03:00
|
|
|
* Copyright (c) 2015-2016 Research Organization for Information Science
|
2015-06-03 07:58:07 +03:00
|
|
|
* and Technology (RIST). All rights reserved.
|
2007-04-23 22:28:20 +04:00
|
|
|
* $COPYRIGHT$
|
|
|
|
*
|
|
|
|
* Additional copyrights may follow
|
|
|
|
*
|
|
|
|
* $HEADER$
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "orte_config.h"
|
2010-07-18 01:03:27 +04:00
|
|
|
#include "orte/constants.h"
|
2009-03-13 05:10:32 +03:00
|
|
|
|
|
|
|
#include <string.h>
|
2007-04-23 22:28:20 +04:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_NETDB_H
|
|
|
|
#include <netdb.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_PARAM_H
|
|
|
|
#include <sys/param.h>
|
|
|
|
#endif
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <signal.h>
|
2009-01-08 17:27:52 +03:00
|
|
|
#ifdef HAVE_SYS_TIME_H
|
|
|
|
#include <sys/time.h>
|
|
|
|
#endif /* HAVE_SYS_TIME_H */
|
2007-04-23 22:28:20 +04:00
|
|
|
|
|
|
|
|
Update libevent to the 2.0 series, currently at 2.0.7rc. We will update to their final release when it becomes available. Currently known errors exist in unused portions of the libevent code. This revision passes the IBM test suite on a Linux machine and on a standalone Mac.
This is a fairly intrusive change, but outside of the moving of opal/event to opal/mca/event, the only changes involved (a) changing all calls to opal_event functions to reflect the new framework instead, and (b) ensuring that all opal_event_t objects are properly constructed since they are now true opal_objects.
Note: Shiqing has just returned from vacation and has not yet had a chance to complete the Windows integration. Thus, this commit almost certainly breaks Windows support on the trunk. However, I want this to have a chance to soak for as long as possible before I become less available a week from today (going to be at a class for 5 days, and thus will only be sparingly available) so we can find and fix any problems.
Biggest change is moving the libevent code from opal/event to a new opal/mca/event framework. This was done to make it much easier to update libevent in the future. New versions can be inserted as a new component and tested in parallel with the current version until validated, then we can remove the earlier version if we so choose. This is a statically built framework ala installdirs, so only one component will build at a time. There is no selection logic - the sole compiled component simply loads its function pointers into the opal_event struct.
I have gone thru the code base and converted all the libevent calls I could find. However, I cannot compile nor test every environment. It is therefore quite likely that errors remain in the system. Please keep an eye open for two things:
1. compile-time errors: these will be obvious as calls to the old functions (e.g., opal_evtimer_new) must be replaced by the new framework APIs (e.g., opal_event.evtimer_new)
2. run-time errors: these will likely show up as segfaults due to missing constructors on opal_event_t objects. It appears that it became a typical practice for people to "init" an opal_event_t by simply using memset to zero it out. This will no longer work - you must either OBJ_NEW or OBJ_CONSTRUCT an opal_event_t. I tried to catch these cases, but may have missed some. Believe me, you'll know when you hit it.
There is also the issue of the new libevent "no recursion" behavior. As I described on a recent email, we will have to discuss this and figure out what, if anything, we need to do.
This commit was SVN r23925.
2010-10-24 22:35:54 +04:00
|
|
|
#include "opal/mca/event/event.h"
|
2007-04-23 22:28:20 +04:00
|
|
|
#include "opal/mca/base/base.h"
|
2009-02-14 05:26:12 +03:00
|
|
|
#include "opal/util/output.h"
|
2007-07-12 23:53:18 +04:00
|
|
|
#include "opal/util/cmd_line.h"
|
2012-11-16 08:04:29 +04:00
|
|
|
#include "opal/util/if.h"
|
2013-01-18 09:00:05 +04:00
|
|
|
#include "opal/util/net.h"
|
2007-07-12 23:53:18 +04:00
|
|
|
#include "opal/util/opal_environ.h"
|
|
|
|
#include "opal/util/os_path.h"
|
|
|
|
#include "opal/util/printf.h"
|
|
|
|
#include "opal/util/argv.h"
|
2016-09-20 08:56:58 +03:00
|
|
|
#include "opal/util/fd.h"
|
2007-07-12 23:53:18 +04:00
|
|
|
#include "opal/runtime/opal.h"
|
2013-03-28 01:09:41 +04:00
|
|
|
#include "opal/mca/base/mca_base_var.h"
|
2008-02-28 04:57:57 +03:00
|
|
|
#include "opal/util/daemon_init.h"
|
|
|
|
#include "opal/dss/dss.h"
|
2011-09-11 23:02:24 +04:00
|
|
|
#include "opal/mca/hwloc/hwloc.h"
|
2015-06-18 19:53:20 +03:00
|
|
|
#include "opal/mca/pmix/pmix.h"
|
2007-07-12 23:53:18 +04:00
|
|
|
|
2008-06-09 18:53:58 +04:00
|
|
|
#include "orte/util/show_help.h"
|
2007-04-23 22:28:20 +04:00
|
|
|
#include "orte/util/proc_info.h"
|
2007-07-12 23:53:18 +04:00
|
|
|
#include "orte/util/session_dir.h"
|
2008-02-28 04:57:57 +03:00
|
|
|
#include "orte/util/name_fns.h"
|
2010-03-23 23:47:41 +03:00
|
|
|
#include "orte/util/nidmap.h"
|
2014-01-31 03:50:14 +04:00
|
|
|
#include "orte/util/parse_options.h"
|
Repair the tree spawn. The problem seems to come from the fact
that now the HNP send the messages using the routed component. In the case
of tree spawn, when a intermediary node spawn a child it doesn't know how
to forward a message to it, so when the node-map message is coming from
the HNP (as there is nothing yet in the contact/routing table) the message
is sent back the way it came. As a result the node-map message keeps jumping
between the HNP and the first level orteds.
The solution is to add a new option to the children orte_parent_uri, which
is only set when the orted is _not_ directly spawned by the HNP. When this
option is present on the argument list, the orted will add the parent to
its routing, and force the parent to update his routes (by sending the URI).
With this approach, the routing tree is build in same time as the processes
are spawned, and all messages from the HNP can be routed to the leaves.
However, this is far from an optimal solution. Right now, this so called tree
spawn, only spawn the children in a tree without doing anything about the
"connect back to the HNP" step. The HNP is flooded with reports from all the
orted. The total number of messages is higher than in the non tree startup
scheme, so we do not expect this approach to be scalable in the current
incarnation. A complete overhaul of the tree startup is required in order
improve the scalability. Stay tuned!
This commit was SVN r21504.
2009-06-24 02:10:25 +04:00
|
|
|
#include "orte/mca/rml/base/rml_contact.h"
|
2016-09-19 07:37:08 +03:00
|
|
|
#include "orte/util/pre_condition_transports.h"
|
2007-04-23 22:28:20 +04:00
|
|
|
|
|
|
|
#include "orte/mca/errmgr/errmgr.h"
|
2012-04-06 18:23:13 +04:00
|
|
|
#include "orte/mca/ess/ess.h"
|
2009-05-11 18:11:44 +04:00
|
|
|
#include "orte/mca/grpcomm/grpcomm.h"
|
2012-04-10 23:08:54 +04:00
|
|
|
#include "orte/mca/grpcomm/base/base.h"
|
2007-04-23 22:28:20 +04:00
|
|
|
#include "orte/mca/rml/rml.h"
|
2009-02-14 05:26:12 +03:00
|
|
|
#include "orte/mca/rml/rml_types.h"
|
2007-07-12 23:53:18 +04:00
|
|
|
#include "orte/mca/odls/odls.h"
|
2010-03-23 23:47:41 +03:00
|
|
|
#include "orte/mca/odls/base/odls_private.h"
|
2008-02-28 04:57:57 +03:00
|
|
|
#include "orte/mca/plm/plm.h"
|
|
|
|
#include "orte/mca/ras/ras.h"
|
2008-04-14 22:26:08 +04:00
|
|
|
#include "orte/mca/routed/routed.h"
|
2010-07-18 06:48:17 +04:00
|
|
|
#include "orte/mca/rmaps/rmaps_types.h"
|
2012-04-06 18:23:13 +04:00
|
|
|
#include "orte/mca/state/state.h"
|
2007-07-12 23:53:18 +04:00
|
|
|
|
2008-02-28 04:57:57 +03:00
|
|
|
/* need access to the create_jobid fn used by plm components
|
|
|
|
* so we can set singleton name, if necessary
|
|
|
|
*/
|
|
|
|
#include "orte/mca/plm/base/plm_private.h"
|
2007-07-12 23:53:18 +04:00
|
|
|
|
|
|
|
#include "orte/runtime/runtime.h"
|
2008-02-28 04:57:57 +03:00
|
|
|
#include "orte/runtime/orte_globals.h"
|
2010-07-18 01:03:27 +04:00
|
|
|
#include "orte/runtime/orte_locks.h"
|
|
|
|
#include "orte/runtime/orte_quit.h"
|
2014-06-17 21:57:51 +04:00
|
|
|
#include "orte/runtime/orte_wait.h"
|
2007-04-23 22:28:20 +04:00
|
|
|
|
2007-07-12 23:53:18 +04:00
|
|
|
#include "orte/orted/orted.h"
|
Per the PMIx RFC:
WHAT: Merge the PMIx branch into the devel repo, creating a new
OPAL “lmix” framework to abstract PMI support for all RTEs.
Replace the ORTE daemon-level collectives with a new PMIx
server and update the ORTE grpcomm framework to support
server-to-server collectives
WHY: We’ve had problems dealing with variations in PMI implementations,
and need to extend the existing PMI definitions to meet exascale
requirements.
WHEN: Mon, Aug 25
WHERE: https://github.com/rhc54/ompi-svn-mirror.git
Several community members have been working on a refactoring of the current PMI support within OMPI. Although the APIs are common, Slurm and Cray implement a different range of capabilities, and package them differently. For example, Cray provides an integrated PMI-1/2 library, while Slurm separates the two and requires the user to specify the one to be used at runtime. In addition, several bugs in the Slurm implementations have caused problems requiring extra coding.
All this has led to a slew of #if’s in the PMI code and bugs when the corner-case logic for one implementation accidentally traps the other. Extending this support to other implementations would have increased this complexity to an unacceptable level.
Accordingly, we have:
* created a new OPAL “pmix” framework to abstract the PMI support, with separate components for Cray, Slurm PMI-1, and Slurm PMI-2 implementations.
* Replaced the current ORTE grpcomm daemon-based collective operation with an integrated PMIx server, and updated the grpcomm APIs to provide more flexible, multi-algorithm support for collective operations. At this time, only the xcast and allgather operations are supported.
* Replaced the current global collective id with a signature based on the names of the participating procs. The allows an unlimited number of collectives to be executed by any group of processes, subject to the requirement that only one collective can be active at a time for a unique combination of procs. Note that a proc can be involved in any number of simultaneous collectives - it is the specific combination of procs that is subject to the constraint
* removed the prior OMPI/OPAL modex code
* added new macros for executing modex send/recv to simplify use of the new APIs. The send macros allow the caller to specify whether or not the BTL supports async modex operations - if so, then the non-blocking “fence” operation is used, if the active PMIx component supports it. Otherwise, the default is a full blocking modex exchange as we currently perform.
* retained the current flag that directs us to use a blocking fence operation, but only to retrieve data upon demand
This commit was SVN r32570.
2014-08-21 22:56:47 +04:00
|
|
|
#include "orte/orted/pmix/pmix_server.h"
|
2007-04-23 22:28:20 +04:00
|
|
|
|
2007-07-12 23:53:18 +04:00
|
|
|
/*
|
|
|
|
* Globals
|
|
|
|
*/
|
2012-04-06 18:23:13 +04:00
|
|
|
static opal_event_t *pipe_handler;
|
2007-07-12 23:53:18 +04:00
|
|
|
static void shutdown_callback(int fd, short flags, void *arg);
|
2012-04-06 18:23:13 +04:00
|
|
|
static void pipe_closed(int fd, short flags, void *arg);
|
2007-07-12 23:53:18 +04:00
|
|
|
|
2013-03-28 01:09:41 +04:00
|
|
|
static char *orte_parent_uri;
|
|
|
|
|
2007-07-12 23:53:18 +04:00
|
|
|
static struct {
|
This commit represents a bunch of work on a Mercurial side branch. As
such, the commit message back to the master SVN repository is fairly
long.
= ORTE Job-Level Output Messages =
Add two new interfaces that should be used for all new code throughout
the ORTE and OMPI layers (we already make the search-and-replace on
the existing ORTE / OMPI layers):
* orte_output(): (and corresponding friends ORTE_OUTPUT,
orte_output_verbose, etc.) This function sends the output directly
to the HNP for processing as part of a job-specific output
channel. It supports all the same outputs as opal_output()
(syslog, file, stdout, stderr), but for stdout/stderr, the output
is sent to the HNP for processing and output. More on this below.
* orte_show_help(): This function is a drop-in-replacement for
opal_show_help(), with two differences in functionality:
1. the rendered text help message output is sent to the HNP for
display (rather than outputting directly into the process' stderr
stream)
1. the HNP detects duplicate help messages and does not display them
(so that you don't see the same error message N times, once from
each of your N MPI processes); instead, it counts "new" instances
of the help message and displays a message every ~5 seconds when
there are new ones ("I got X new copies of the help message...")
opal_show_help and opal_output still exist, but they only output in
the current process. The intent for the new orte_* functions is that
they can apply job-level intelligence to the output. As such, we
recommend that all new ORTE and OMPI code use the new orte_*
functions, not thei opal_* functions.
=== New code ===
For ORTE and OMPI programmers, here's what you need to do differently
in new code:
* Do not include opal/util/show_help.h or opal/util/output.h.
Instead, include orte/util/output.h (this one header file has
declarations for both the orte_output() series of functions and
orte_show_help()).
* Effectively s/opal_output/orte_output/gi throughout your code.
Note that orte_output_open() takes a slightly different argument
list (as a way to pass data to the filtering stream -- see below),
so you if explicitly call opal_output_open(), you'll need to
slightly adapt to the new signature of orte_output_open().
* Literally s/opal_show_help/orte_show_help/. The function signature
is identical.
=== Notes ===
* orte_output'ing to stream 0 will do similar to what
opal_output'ing did, so leaving a hard-coded "0" as the first
argument is safe.
* For systems that do not use ORTE's RML or the HNP, the effect of
orte_output_* and orte_show_help will be identical to their opal
counterparts (the additional information passed to
orte_output_open() will be lost!). Indeed, the orte_* functions
simply become trivial wrappers to their opal_* counterparts. Note
that we have not tested this; the code is simple but it is quite
possible that we mucked something up.
= Filter Framework =
Messages sent view the new orte_* functions described above and
messages output via the IOF on the HNP will now optionally be passed
through a new "filter" framework before being output to
stdout/stderr. The "filter" OPAL MCA framework is intended to allow
preprocessing to messages before they are sent to their final
destinations. The first component that was written in the filter
framework was to create an XML stream, segregating all the messages
into different XML tags, etc. This will allow 3rd party tools to read
the stdout/stderr from the HNP and be able to know exactly what each
text message is (e.g., a help message, another OMPI infrastructure
message, stdout from the user process, stderr from the user process,
etc.).
Filtering is not active by default. Filter components must be
specifically requested, such as:
{{{
$ mpirun --mca filter xml ...
}}}
There can only be one filter component active.
= New MCA Parameters =
The new functionality described above introduces two new MCA
parameters:
* '''orte_base_help_aggregate''': Defaults to 1 (true), meaning that
help messages will be aggregated, as described above. If set to 0,
all help messages will be displayed, even if they are duplicates
(i.e., the original behavior).
* '''orte_base_show_output_recursions''': An MCA parameter to help
debug one of the known issues, described below. It is likely that
this MCA parameter will disappear before v1.3 final.
= Known Issues =
* The XML filter component is not complete. The current output from
this component is preliminary and not real XML. A bit more work
needs to be done to configure.m4 search for an appropriate XML
library/link it in/use it at run time.
* There are possible recursion loops in the orte_output() and
orte_show_help() functions -- e.g., if RML send calls orte_output()
or orte_show_help(). We have some ideas how to fix these, but
figured that it was ok to commit before feature freeze with known
issues. The code currently contains sub-optimal workarounds so
that this will not be a problem, but it would be good to actually
solve the problem rather than have hackish workarounds before v1.3 final.
This commit was SVN r18434.
2008-05-14 00:00:55 +04:00
|
|
|
bool debug;
|
2007-07-12 23:53:18 +04:00
|
|
|
bool help;
|
|
|
|
bool set_sid;
|
2008-02-28 04:57:57 +03:00
|
|
|
bool hnp;
|
|
|
|
bool daemonize;
|
2007-07-12 23:53:18 +04:00
|
|
|
char* name;
|
|
|
|
char* vpid_start;
|
|
|
|
char* num_procs;
|
|
|
|
int uri_pipe;
|
|
|
|
int singleton_died_pipe;
|
2008-06-03 01:46:34 +04:00
|
|
|
bool abort;
|
2012-05-03 01:00:22 +04:00
|
|
|
bool mapreduce;
|
2012-06-22 01:29:28 +04:00
|
|
|
bool tree_spawn;
|
2014-12-09 02:33:45 +03:00
|
|
|
char *hnp_topo_sig;
|
2016-03-03 01:30:57 +03:00
|
|
|
bool test_suicide;
|
2007-07-12 23:53:18 +04:00
|
|
|
} orted_globals;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* define the orted context table for obtaining parameters
|
|
|
|
*/
|
|
|
|
opal_cmd_line_init_t orte_cmd_line_opts[] = {
|
|
|
|
/* Various "obvious" options */
|
2012-10-30 23:45:18 +04:00
|
|
|
{ NULL, 'h', NULL, "help", 0,
|
2007-07-12 23:53:18 +04:00
|
|
|
&orted_globals.help, OPAL_CMD_LINE_TYPE_BOOL,
|
|
|
|
"This help message" },
|
|
|
|
|
2012-10-30 23:45:18 +04:00
|
|
|
{ "orte_daemon_spin", 's', NULL, "spin", 0,
|
2008-07-02 05:46:58 +04:00
|
|
|
&orted_spin_flag, OPAL_CMD_LINE_TYPE_BOOL,
|
2007-07-12 23:53:18 +04:00
|
|
|
"Have the orted spin until we can connect a debugger to it" },
|
|
|
|
|
2016-03-03 01:30:57 +03:00
|
|
|
{ NULL, '\0', NULL, "test-suicide", 1,
|
|
|
|
&orted_globals.test_suicide, OPAL_CMD_LINE_TYPE_BOOL,
|
|
|
|
"Suicide instead of clean abort after delay" },
|
2015-06-24 06:59:57 +03:00
|
|
|
|
2012-10-30 23:45:18 +04:00
|
|
|
{ "orte_debug", 'd', NULL, "debug", 0,
|
2008-06-03 01:46:34 +04:00
|
|
|
NULL, OPAL_CMD_LINE_TYPE_BOOL,
|
|
|
|
"Debug the OpenRTE" },
|
2015-06-24 06:59:57 +03:00
|
|
|
|
2012-10-30 23:45:18 +04:00
|
|
|
{ "orte_daemonize", '\0', NULL, "daemonize", 0,
|
2008-02-28 04:57:57 +03:00
|
|
|
&orted_globals.daemonize, OPAL_CMD_LINE_TYPE_BOOL,
|
|
|
|
"Daemonize the orted into the background" },
|
2007-07-12 23:53:18 +04:00
|
|
|
|
2012-10-30 23:45:18 +04:00
|
|
|
{ "orte_debug_daemons", '\0', NULL, "debug-daemons", 0,
|
This commit represents a bunch of work on a Mercurial side branch. As
such, the commit message back to the master SVN repository is fairly
long.
= ORTE Job-Level Output Messages =
Add two new interfaces that should be used for all new code throughout
the ORTE and OMPI layers (we already make the search-and-replace on
the existing ORTE / OMPI layers):
* orte_output(): (and corresponding friends ORTE_OUTPUT,
orte_output_verbose, etc.) This function sends the output directly
to the HNP for processing as part of a job-specific output
channel. It supports all the same outputs as opal_output()
(syslog, file, stdout, stderr), but for stdout/stderr, the output
is sent to the HNP for processing and output. More on this below.
* orte_show_help(): This function is a drop-in-replacement for
opal_show_help(), with two differences in functionality:
1. the rendered text help message output is sent to the HNP for
display (rather than outputting directly into the process' stderr
stream)
1. the HNP detects duplicate help messages and does not display them
(so that you don't see the same error message N times, once from
each of your N MPI processes); instead, it counts "new" instances
of the help message and displays a message every ~5 seconds when
there are new ones ("I got X new copies of the help message...")
opal_show_help and opal_output still exist, but they only output in
the current process. The intent for the new orte_* functions is that
they can apply job-level intelligence to the output. As such, we
recommend that all new ORTE and OMPI code use the new orte_*
functions, not thei opal_* functions.
=== New code ===
For ORTE and OMPI programmers, here's what you need to do differently
in new code:
* Do not include opal/util/show_help.h or opal/util/output.h.
Instead, include orte/util/output.h (this one header file has
declarations for both the orte_output() series of functions and
orte_show_help()).
* Effectively s/opal_output/orte_output/gi throughout your code.
Note that orte_output_open() takes a slightly different argument
list (as a way to pass data to the filtering stream -- see below),
so you if explicitly call opal_output_open(), you'll need to
slightly adapt to the new signature of orte_output_open().
* Literally s/opal_show_help/orte_show_help/. The function signature
is identical.
=== Notes ===
* orte_output'ing to stream 0 will do similar to what
opal_output'ing did, so leaving a hard-coded "0" as the first
argument is safe.
* For systems that do not use ORTE's RML or the HNP, the effect of
orte_output_* and orte_show_help will be identical to their opal
counterparts (the additional information passed to
orte_output_open() will be lost!). Indeed, the orte_* functions
simply become trivial wrappers to their opal_* counterparts. Note
that we have not tested this; the code is simple but it is quite
possible that we mucked something up.
= Filter Framework =
Messages sent view the new orte_* functions described above and
messages output via the IOF on the HNP will now optionally be passed
through a new "filter" framework before being output to
stdout/stderr. The "filter" OPAL MCA framework is intended to allow
preprocessing to messages before they are sent to their final
destinations. The first component that was written in the filter
framework was to create an XML stream, segregating all the messages
into different XML tags, etc. This will allow 3rd party tools to read
the stdout/stderr from the HNP and be able to know exactly what each
text message is (e.g., a help message, another OMPI infrastructure
message, stdout from the user process, stderr from the user process,
etc.).
Filtering is not active by default. Filter components must be
specifically requested, such as:
{{{
$ mpirun --mca filter xml ...
}}}
There can only be one filter component active.
= New MCA Parameters =
The new functionality described above introduces two new MCA
parameters:
* '''orte_base_help_aggregate''': Defaults to 1 (true), meaning that
help messages will be aggregated, as described above. If set to 0,
all help messages will be displayed, even if they are duplicates
(i.e., the original behavior).
* '''orte_base_show_output_recursions''': An MCA parameter to help
debug one of the known issues, described below. It is likely that
this MCA parameter will disappear before v1.3 final.
= Known Issues =
* The XML filter component is not complete. The current output from
this component is preliminary and not real XML. A bit more work
needs to be done to configure.m4 search for an appropriate XML
library/link it in/use it at run time.
* There are possible recursion loops in the orte_output() and
orte_show_help() functions -- e.g., if RML send calls orte_output()
or orte_show_help(). We have some ideas how to fix these, but
figured that it was ok to commit before feature freeze with known
issues. The code currently contains sub-optimal workarounds so
that this will not be a problem, but it would be good to actually
solve the problem rather than have hackish workarounds before v1.3 final.
This commit was SVN r18434.
2008-05-14 00:00:55 +04:00
|
|
|
&orted_globals.debug, OPAL_CMD_LINE_TYPE_BOOL,
|
2007-07-12 23:53:18 +04:00
|
|
|
"Enable debugging of OpenRTE daemons" },
|
|
|
|
|
2012-10-30 23:45:18 +04:00
|
|
|
{ "orte_debug_daemons_file", '\0', NULL, "debug-daemons-file", 0,
|
2007-07-12 23:53:18 +04:00
|
|
|
NULL, OPAL_CMD_LINE_TYPE_BOOL,
|
|
|
|
"Enable debugging of OpenRTE daemons, storing output in files" },
|
|
|
|
|
2012-10-30 23:45:18 +04:00
|
|
|
{ NULL, '\0', NULL, "hnp", 0,
|
2008-02-28 04:57:57 +03:00
|
|
|
&orted_globals.hnp, OPAL_CMD_LINE_TYPE_BOOL,
|
|
|
|
"Direct the orted to act as the HNP"},
|
|
|
|
|
2012-10-30 23:45:18 +04:00
|
|
|
{ "orte_hnp_uri", '\0', NULL, "hnp-uri", 1,
|
2008-02-28 04:57:57 +03:00
|
|
|
NULL, OPAL_CMD_LINE_TYPE_STRING,
|
|
|
|
"URI for the HNP"},
|
2015-06-24 06:59:57 +03:00
|
|
|
|
2012-10-30 23:45:18 +04:00
|
|
|
{ "orte_parent_uri", '\0', NULL, "parent-uri", 1,
|
Repair the tree spawn. The problem seems to come from the fact
that now the HNP send the messages using the routed component. In the case
of tree spawn, when a intermediary node spawn a child it doesn't know how
to forward a message to it, so when the node-map message is coming from
the HNP (as there is nothing yet in the contact/routing table) the message
is sent back the way it came. As a result the node-map message keeps jumping
between the HNP and the first level orteds.
The solution is to add a new option to the children orte_parent_uri, which
is only set when the orted is _not_ directly spawned by the HNP. When this
option is present on the argument list, the orted will add the parent to
its routing, and force the parent to update his routes (by sending the URI).
With this approach, the routing tree is build in same time as the processes
are spawned, and all messages from the HNP can be routed to the leaves.
However, this is far from an optimal solution. Right now, this so called tree
spawn, only spawn the children in a tree without doing anything about the
"connect back to the HNP" step. The HNP is flooded with reports from all the
orted. The total number of messages is higher than in the non tree startup
scheme, so we do not expect this approach to be scalable in the current
incarnation. A complete overhaul of the tree startup is required in order
improve the scalability. Stay tuned!
This commit was SVN r21504.
2009-06-24 02:10:25 +04:00
|
|
|
NULL, OPAL_CMD_LINE_TYPE_STRING,
|
|
|
|
"URI for the parent if tree launch is enabled."},
|
2015-06-24 06:59:57 +03:00
|
|
|
|
2012-10-30 23:45:18 +04:00
|
|
|
{ NULL, '\0', NULL, "set-sid", 0,
|
2007-07-12 23:53:18 +04:00
|
|
|
&orted_globals.set_sid, OPAL_CMD_LINE_TYPE_BOOL,
|
|
|
|
"Direct the orted to separate from the current session"},
|
2015-06-24 06:59:57 +03:00
|
|
|
|
2012-10-30 23:45:18 +04:00
|
|
|
{ "tmpdir_base", '\0', NULL, "tmpdir", 1,
|
2007-07-12 23:53:18 +04:00
|
|
|
NULL, OPAL_CMD_LINE_TYPE_STRING,
|
|
|
|
"Set the root for the session directory tree" },
|
|
|
|
|
2012-10-30 23:45:18 +04:00
|
|
|
{ NULL, '\0', NULL, "report-uri", 1,
|
2007-07-12 23:53:18 +04:00
|
|
|
&orted_globals.uri_pipe, OPAL_CMD_LINE_TYPE_INT,
|
|
|
|
"Report this process' uri on indicated pipe"},
|
|
|
|
|
2012-10-30 23:45:18 +04:00
|
|
|
{ NULL, '\0', NULL, "singleton-died-pipe", 1,
|
2007-07-12 23:53:18 +04:00
|
|
|
&orted_globals.singleton_died_pipe, OPAL_CMD_LINE_TYPE_INT,
|
|
|
|
"Watch on indicated pipe for singleton termination"},
|
2015-06-24 06:59:57 +03:00
|
|
|
|
2012-10-30 23:45:18 +04:00
|
|
|
{ "orte_output_filename", '\0', "output-filename", "output-filename", 1,
|
2009-02-03 23:06:05 +03:00
|
|
|
NULL, OPAL_CMD_LINE_TYPE_STRING,
|
|
|
|
"Redirect output from application processes into filename.rank" },
|
2015-06-24 06:59:57 +03:00
|
|
|
|
2012-10-30 23:45:18 +04:00
|
|
|
{ "orte_xterm", '\0', "xterm", "xterm", 1,
|
2009-02-03 23:06:05 +03:00
|
|
|
NULL, OPAL_CMD_LINE_TYPE_STRING,
|
|
|
|
"Create a new xterm window and display output from the specified ranks there" },
|
|
|
|
|
2012-10-30 23:45:18 +04:00
|
|
|
{ "orte_report_bindings", '\0', "report-bindings", "report-bindings", 0,
|
2009-09-28 07:17:15 +04:00
|
|
|
NULL, OPAL_CMD_LINE_TYPE_BOOL,
|
|
|
|
"Whether to report process bindings to stderr" },
|
|
|
|
|
2012-10-30 23:45:18 +04:00
|
|
|
{ "orte_node_regex", '\0', "nodes", "nodes", 1,
|
2011-07-07 22:54:30 +04:00
|
|
|
NULL, OPAL_CMD_LINE_TYPE_STRING,
|
|
|
|
"Regular expression defining nodes in system" },
|
|
|
|
|
2012-10-30 23:45:18 +04:00
|
|
|
{ "orte_hetero_nodes", '\0', NULL, "hetero-nodes", 0,
|
2011-11-01 22:43:10 +04:00
|
|
|
NULL, OPAL_CMD_LINE_TYPE_BOOL,
|
|
|
|
"Nodes in cluster may differ in topology, so send the topology back from each node [Default = false]" },
|
2015-06-24 06:59:57 +03:00
|
|
|
|
2014-12-09 02:33:45 +03:00
|
|
|
{ NULL, '\0', NULL, "hnp-topo-sig", 1,
|
|
|
|
&orted_globals.hnp_topo_sig, OPAL_CMD_LINE_TYPE_STRING,
|
|
|
|
"Topology signature of HNP" },
|
2011-11-01 22:43:10 +04:00
|
|
|
|
2012-10-30 23:45:18 +04:00
|
|
|
{ NULL, '\0', "mapreduce", "mapreduce", 0,
|
2012-05-03 01:00:22 +04:00
|
|
|
&orted_globals.mapreduce, OPAL_CMD_LINE_TYPE_BOOL,
|
|
|
|
"Whether to report process bindings to stderr" },
|
|
|
|
|
2007-07-12 23:53:18 +04:00
|
|
|
/* End of list */
|
2012-10-30 23:45:18 +04:00
|
|
|
{ NULL, '\0', NULL, NULL, 0,
|
2007-07-12 23:53:18 +04:00
|
|
|
NULL, OPAL_CMD_LINE_TYPE_NULL, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
int orte_daemon(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
opal_cmd_line_t *cmd_line = NULL;
|
2008-02-28 04:57:57 +03:00
|
|
|
char *rml_uri;
|
2007-07-12 23:53:18 +04:00
|
|
|
int i;
|
2008-02-28 04:57:57 +03:00
|
|
|
opal_buffer_t *buffer;
|
2016-04-16 03:47:42 +03:00
|
|
|
char hostname[OPAL_MAXHOSTNAMELEN];
|
2013-05-18 01:45:49 +04:00
|
|
|
#if OPAL_ENABLE_FT_CR == 1
|
2008-04-23 04:17:12 +04:00
|
|
|
char *tmp_env_var = NULL;
|
2013-05-18 01:45:49 +04:00
|
|
|
#endif
|
2015-09-05 02:54:40 +03:00
|
|
|
char *coprocessors;
|
|
|
|
uint8_t tflag;
|
2015-06-24 06:59:57 +03:00
|
|
|
|
2007-07-12 23:53:18 +04:00
|
|
|
/* initialize the globals */
|
|
|
|
memset(&orted_globals, 0, sizeof(orted_globals));
|
|
|
|
/* initialize the singleton died pipe to an illegal value so we can detect it was set */
|
|
|
|
orted_globals.singleton_died_pipe = -1;
|
2015-06-24 06:59:57 +03:00
|
|
|
|
2007-07-12 23:53:18 +04:00
|
|
|
/* setup to check common command line options that just report and die */
|
|
|
|
cmd_line = OBJ_NEW(opal_cmd_line_t);
|
2011-07-07 22:54:30 +04:00
|
|
|
if (OPAL_SUCCESS != opal_cmd_line_create(cmd_line, orte_cmd_line_opts)) {
|
|
|
|
OBJ_RELEASE(cmd_line);
|
|
|
|
exit(1);
|
|
|
|
}
|
2007-07-12 23:53:18 +04:00
|
|
|
mca_base_cmd_line_setup(cmd_line);
|
2016-05-07 14:12:01 +03:00
|
|
|
if (ORTE_SUCCESS != (ret = opal_cmd_line_parse(cmd_line, false, false,
|
2007-07-12 23:53:18 +04:00
|
|
|
argc, argv))) {
|
|
|
|
char *args = NULL;
|
|
|
|
args = opal_cmd_line_get_usage_msg(cmd_line);
|
2011-07-07 22:54:30 +04:00
|
|
|
fprintf(stderr, "Usage: %s [OPTION]...\n%s\n", argv[0], args);
|
2007-07-12 23:53:18 +04:00
|
|
|
free(args);
|
2011-07-07 22:54:30 +04:00
|
|
|
OBJ_RELEASE(cmd_line);
|
2007-07-12 23:53:18 +04:00
|
|
|
return ret;
|
|
|
|
}
|
2015-06-24 06:59:57 +03:00
|
|
|
|
2007-07-12 23:53:18 +04:00
|
|
|
/*
|
|
|
|
* Since this process can now handle MCA/GMCA parameters, make sure to
|
|
|
|
* process them.
|
|
|
|
*/
|
2016-05-06 20:55:21 +03:00
|
|
|
mca_base_cmd_line_process_args(cmd_line, &environ, &environ);
|
2015-06-24 06:59:57 +03:00
|
|
|
|
2007-07-13 22:15:36 +04:00
|
|
|
/* Ensure that enough of OPAL is setup for us to be able to run */
|
2007-07-13 23:08:05 +04:00
|
|
|
/*
|
|
|
|
* NOTE: (JJH)
|
|
|
|
* We need to allow 'mca_base_cmd_line_process_args()' to process command
|
|
|
|
* line arguments *before* calling opal_init_util() since the command
|
|
|
|
* line could contain MCA parameters that affect the way opal_init_util()
|
|
|
|
* functions. AMCA parameters are one such option normally received on the
|
|
|
|
* command line that affect the way opal_init_util() behaves.
|
2015-06-24 06:59:57 +03:00
|
|
|
* It is "safe" to call mca_base_cmd_line_process_args() before
|
2007-07-13 23:08:05 +04:00
|
|
|
* opal_init_util() since mca_base_cmd_line_process_args() does *not*
|
|
|
|
* depend upon opal_init_util() functionality.
|
|
|
|
*/
|
2009-12-04 03:51:15 +03:00
|
|
|
if (OPAL_SUCCESS != opal_init_util(&argc, &argv)) {
|
2007-07-13 22:15:36 +04:00
|
|
|
fprintf(stderr, "OPAL failed to initialize -- orted aborting\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2008-07-09 02:36:39 +04:00
|
|
|
/* save the environment for launch purposes. This MUST be
|
|
|
|
* done so that we can pass it to any local procs we
|
|
|
|
* spawn - otherwise, those local procs won't see any
|
|
|
|
* non-MCA envars that were set in the enviro when the
|
|
|
|
* orted was executed - e.g., by .csh
|
|
|
|
*/
|
2008-02-28 04:57:57 +03:00
|
|
|
orte_launch_environ = opal_argv_copy(environ);
|
2015-06-24 06:59:57 +03:00
|
|
|
|
2010-04-15 22:10:50 +04:00
|
|
|
/* purge any ess flag set in the environ when we were launched */
|
2014-10-23 00:56:37 +04:00
|
|
|
opal_unsetenv(OPAL_MCA_PREFIX"ess", &orte_launch_environ);
|
2015-06-24 06:59:57 +03:00
|
|
|
|
2007-07-23 19:00:39 +04:00
|
|
|
/* if orte_daemon_debug is set, let someone know we are alive right
|
|
|
|
* away just in case we have a problem along the way
|
|
|
|
*/
|
This commit represents a bunch of work on a Mercurial side branch. As
such, the commit message back to the master SVN repository is fairly
long.
= ORTE Job-Level Output Messages =
Add two new interfaces that should be used for all new code throughout
the ORTE and OMPI layers (we already make the search-and-replace on
the existing ORTE / OMPI layers):
* orte_output(): (and corresponding friends ORTE_OUTPUT,
orte_output_verbose, etc.) This function sends the output directly
to the HNP for processing as part of a job-specific output
channel. It supports all the same outputs as opal_output()
(syslog, file, stdout, stderr), but for stdout/stderr, the output
is sent to the HNP for processing and output. More on this below.
* orte_show_help(): This function is a drop-in-replacement for
opal_show_help(), with two differences in functionality:
1. the rendered text help message output is sent to the HNP for
display (rather than outputting directly into the process' stderr
stream)
1. the HNP detects duplicate help messages and does not display them
(so that you don't see the same error message N times, once from
each of your N MPI processes); instead, it counts "new" instances
of the help message and displays a message every ~5 seconds when
there are new ones ("I got X new copies of the help message...")
opal_show_help and opal_output still exist, but they only output in
the current process. The intent for the new orte_* functions is that
they can apply job-level intelligence to the output. As such, we
recommend that all new ORTE and OMPI code use the new orte_*
functions, not thei opal_* functions.
=== New code ===
For ORTE and OMPI programmers, here's what you need to do differently
in new code:
* Do not include opal/util/show_help.h or opal/util/output.h.
Instead, include orte/util/output.h (this one header file has
declarations for both the orte_output() series of functions and
orte_show_help()).
* Effectively s/opal_output/orte_output/gi throughout your code.
Note that orte_output_open() takes a slightly different argument
list (as a way to pass data to the filtering stream -- see below),
so you if explicitly call opal_output_open(), you'll need to
slightly adapt to the new signature of orte_output_open().
* Literally s/opal_show_help/orte_show_help/. The function signature
is identical.
=== Notes ===
* orte_output'ing to stream 0 will do similar to what
opal_output'ing did, so leaving a hard-coded "0" as the first
argument is safe.
* For systems that do not use ORTE's RML or the HNP, the effect of
orte_output_* and orte_show_help will be identical to their opal
counterparts (the additional information passed to
orte_output_open() will be lost!). Indeed, the orte_* functions
simply become trivial wrappers to their opal_* counterparts. Note
that we have not tested this; the code is simple but it is quite
possible that we mucked something up.
= Filter Framework =
Messages sent view the new orte_* functions described above and
messages output via the IOF on the HNP will now optionally be passed
through a new "filter" framework before being output to
stdout/stderr. The "filter" OPAL MCA framework is intended to allow
preprocessing to messages before they are sent to their final
destinations. The first component that was written in the filter
framework was to create an XML stream, segregating all the messages
into different XML tags, etc. This will allow 3rd party tools to read
the stdout/stderr from the HNP and be able to know exactly what each
text message is (e.g., a help message, another OMPI infrastructure
message, stdout from the user process, stderr from the user process,
etc.).
Filtering is not active by default. Filter components must be
specifically requested, such as:
{{{
$ mpirun --mca filter xml ...
}}}
There can only be one filter component active.
= New MCA Parameters =
The new functionality described above introduces two new MCA
parameters:
* '''orte_base_help_aggregate''': Defaults to 1 (true), meaning that
help messages will be aggregated, as described above. If set to 0,
all help messages will be displayed, even if they are duplicates
(i.e., the original behavior).
* '''orte_base_show_output_recursions''': An MCA parameter to help
debug one of the known issues, described below. It is likely that
this MCA parameter will disappear before v1.3 final.
= Known Issues =
* The XML filter component is not complete. The current output from
this component is preliminary and not real XML. A bit more work
needs to be done to configure.m4 search for an appropriate XML
library/link it in/use it at run time.
* There are possible recursion loops in the orte_output() and
orte_show_help() functions -- e.g., if RML send calls orte_output()
or orte_show_help(). We have some ideas how to fix these, but
figured that it was ok to commit before feature freeze with known
issues. The code currently contains sub-optimal workarounds so
that this will not be a problem, but it would be good to actually
solve the problem rather than have hackish workarounds before v1.3 final.
This commit was SVN r18434.
2008-05-14 00:00:55 +04:00
|
|
|
if (orted_globals.debug) {
|
2016-04-16 03:47:42 +03:00
|
|
|
gethostname(hostname, sizeof(hostname));
|
2007-07-23 19:00:39 +04:00
|
|
|
fprintf(stderr, "Daemon was launched on %s - beginning to initialize\n", hostname);
|
|
|
|
}
|
2015-06-24 06:59:57 +03:00
|
|
|
|
2007-07-12 23:53:18 +04:00
|
|
|
/* check for help request */
|
|
|
|
if (orted_globals.help) {
|
|
|
|
char *args = NULL;
|
|
|
|
args = opal_cmd_line_get_usage_msg(cmd_line);
|
This commit represents a bunch of work on a Mercurial side branch. As
such, the commit message back to the master SVN repository is fairly
long.
= ORTE Job-Level Output Messages =
Add two new interfaces that should be used for all new code throughout
the ORTE and OMPI layers (we already make the search-and-replace on
the existing ORTE / OMPI layers):
* orte_output(): (and corresponding friends ORTE_OUTPUT,
orte_output_verbose, etc.) This function sends the output directly
to the HNP for processing as part of a job-specific output
channel. It supports all the same outputs as opal_output()
(syslog, file, stdout, stderr), but for stdout/stderr, the output
is sent to the HNP for processing and output. More on this below.
* orte_show_help(): This function is a drop-in-replacement for
opal_show_help(), with two differences in functionality:
1. the rendered text help message output is sent to the HNP for
display (rather than outputting directly into the process' stderr
stream)
1. the HNP detects duplicate help messages and does not display them
(so that you don't see the same error message N times, once from
each of your N MPI processes); instead, it counts "new" instances
of the help message and displays a message every ~5 seconds when
there are new ones ("I got X new copies of the help message...")
opal_show_help and opal_output still exist, but they only output in
the current process. The intent for the new orte_* functions is that
they can apply job-level intelligence to the output. As such, we
recommend that all new ORTE and OMPI code use the new orte_*
functions, not thei opal_* functions.
=== New code ===
For ORTE and OMPI programmers, here's what you need to do differently
in new code:
* Do not include opal/util/show_help.h or opal/util/output.h.
Instead, include orte/util/output.h (this one header file has
declarations for both the orte_output() series of functions and
orte_show_help()).
* Effectively s/opal_output/orte_output/gi throughout your code.
Note that orte_output_open() takes a slightly different argument
list (as a way to pass data to the filtering stream -- see below),
so you if explicitly call opal_output_open(), you'll need to
slightly adapt to the new signature of orte_output_open().
* Literally s/opal_show_help/orte_show_help/. The function signature
is identical.
=== Notes ===
* orte_output'ing to stream 0 will do similar to what
opal_output'ing did, so leaving a hard-coded "0" as the first
argument is safe.
* For systems that do not use ORTE's RML or the HNP, the effect of
orte_output_* and orte_show_help will be identical to their opal
counterparts (the additional information passed to
orte_output_open() will be lost!). Indeed, the orte_* functions
simply become trivial wrappers to their opal_* counterparts. Note
that we have not tested this; the code is simple but it is quite
possible that we mucked something up.
= Filter Framework =
Messages sent view the new orte_* functions described above and
messages output via the IOF on the HNP will now optionally be passed
through a new "filter" framework before being output to
stdout/stderr. The "filter" OPAL MCA framework is intended to allow
preprocessing to messages before they are sent to their final
destinations. The first component that was written in the filter
framework was to create an XML stream, segregating all the messages
into different XML tags, etc. This will allow 3rd party tools to read
the stdout/stderr from the HNP and be able to know exactly what each
text message is (e.g., a help message, another OMPI infrastructure
message, stdout from the user process, stderr from the user process,
etc.).
Filtering is not active by default. Filter components must be
specifically requested, such as:
{{{
$ mpirun --mca filter xml ...
}}}
There can only be one filter component active.
= New MCA Parameters =
The new functionality described above introduces two new MCA
parameters:
* '''orte_base_help_aggregate''': Defaults to 1 (true), meaning that
help messages will be aggregated, as described above. If set to 0,
all help messages will be displayed, even if they are duplicates
(i.e., the original behavior).
* '''orte_base_show_output_recursions''': An MCA parameter to help
debug one of the known issues, described below. It is likely that
this MCA parameter will disappear before v1.3 final.
= Known Issues =
* The XML filter component is not complete. The current output from
this component is preliminary and not real XML. A bit more work
needs to be done to configure.m4 search for an appropriate XML
library/link it in/use it at run time.
* There are possible recursion loops in the orte_output() and
orte_show_help() functions -- e.g., if RML send calls orte_output()
or orte_show_help(). We have some ideas how to fix these, but
figured that it was ok to commit before feature freeze with known
issues. The code currently contains sub-optimal workarounds so
that this will not be a problem, but it would be good to actually
solve the problem rather than have hackish workarounds before v1.3 final.
This commit was SVN r18434.
2008-05-14 00:00:55 +04:00
|
|
|
orte_show_help("help-orted.txt", "orted:usage", false,
|
2007-07-12 23:53:18 +04:00
|
|
|
argv[0], args);
|
|
|
|
free(args);
|
|
|
|
return 1;
|
|
|
|
}
|
2013-02-28 21:31:47 +04:00
|
|
|
#if defined(HAVE_SETSID)
|
2007-07-12 23:53:18 +04:00
|
|
|
/* see if we were directed to separate from current session */
|
|
|
|
if (orted_globals.set_sid) {
|
|
|
|
setsid();
|
|
|
|
}
|
2013-02-28 21:31:47 +04:00
|
|
|
#endif
|
2007-07-12 23:53:18 +04:00
|
|
|
/* see if they want us to spin until they can connect a debugger to us */
|
|
|
|
i=0;
|
|
|
|
while (orted_spin_flag) {
|
|
|
|
i++;
|
2015-06-24 06:59:57 +03:00
|
|
|
if (1000 < i) i=0;
|
2007-07-12 23:53:18 +04:00
|
|
|
}
|
2008-03-23 15:33:04 +03:00
|
|
|
|
2010-03-13 02:57:50 +03:00
|
|
|
#if OPAL_ENABLE_FT_CR == 1
|
2007-10-17 17:47:36 +04:00
|
|
|
/* Mark as a tool program */
|
2013-03-28 01:09:41 +04:00
|
|
|
(void) mca_base_var_env_name ("opal_cr_is_tool", &tmp_env_var);
|
2008-04-23 04:17:12 +04:00
|
|
|
opal_setenv(tmp_env_var,
|
2007-10-17 17:47:36 +04:00
|
|
|
"1",
|
|
|
|
true, &environ);
|
2008-04-23 04:17:12 +04:00
|
|
|
free(tmp_env_var);
|
2007-10-17 17:47:36 +04:00
|
|
|
#endif
|
|
|
|
|
2012-05-03 01:00:22 +04:00
|
|
|
/* if mapreduce set, flag it */
|
|
|
|
if (orted_globals.mapreduce) {
|
|
|
|
orte_map_reduce = true;
|
|
|
|
}
|
|
|
|
|
2013-04-08 04:42:57 +04:00
|
|
|
/* detach from controlling terminal
|
|
|
|
* otherwise, remain attached so output can get to us
|
|
|
|
*/
|
|
|
|
if(!orte_debug_flag &&
|
|
|
|
!orte_debug_daemons_flag &&
|
|
|
|
orted_globals.daemonize) {
|
|
|
|
opal_daemon_init(NULL);
|
|
|
|
}
|
2015-06-24 06:59:57 +03:00
|
|
|
|
2007-07-12 23:53:18 +04:00
|
|
|
/* Set the flag telling OpenRTE that I am NOT a
|
|
|
|
* singleton, but am "infrastructure" - prevents setting
|
|
|
|
* up incorrect infrastructure that only a singleton would
|
|
|
|
* require.
|
|
|
|
*/
|
2009-05-04 15:07:40 +04:00
|
|
|
if (orted_globals.hnp) {
|
2009-12-04 03:51:15 +03:00
|
|
|
if (ORTE_SUCCESS != (ret = orte_init(&argc, &argv, ORTE_PROC_HNP))) {
|
2009-05-04 15:07:40 +04:00
|
|
|
ORTE_ERROR_LOG(ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
} else {
|
2009-12-04 03:51:15 +03:00
|
|
|
if (ORTE_SUCCESS != (ret = orte_init(&argc, &argv, ORTE_PROC_DAEMON))) {
|
2009-05-04 15:07:40 +04:00
|
|
|
ORTE_ERROR_LOG(ret);
|
|
|
|
return ret;
|
|
|
|
}
|
2007-07-12 23:53:18 +04:00
|
|
|
}
|
2011-07-12 21:07:41 +04:00
|
|
|
/* finalize the OPAL utils. As they are opened again from orte_init->opal_init
|
|
|
|
* we continue to have a reference count on them. So we have to finalize them twice...
|
|
|
|
*/
|
|
|
|
opal_finalize_util();
|
|
|
|
|
2014-01-31 03:50:14 +04:00
|
|
|
/* bind ourselves if so directed */
|
|
|
|
if (NULL != orte_daemon_cores) {
|
|
|
|
char **cores=NULL, tmp[128];
|
|
|
|
hwloc_obj_t pu;
|
|
|
|
hwloc_cpuset_t ours, pucpus, res;
|
|
|
|
int core;
|
|
|
|
|
|
|
|
/* could be a collection of comma-delimited ranges, so
|
|
|
|
* use our handy utility to parse it
|
|
|
|
*/
|
|
|
|
orte_util_parse_range_options(orte_daemon_cores, &cores);
|
|
|
|
if (NULL != cores) {
|
|
|
|
ours = hwloc_bitmap_alloc();
|
|
|
|
hwloc_bitmap_zero(ours);
|
|
|
|
pucpus = hwloc_bitmap_alloc();
|
|
|
|
res = hwloc_bitmap_alloc();
|
|
|
|
for (i=0; NULL != cores[i]; i++) {
|
|
|
|
core = strtoul(cores[i], NULL, 10);
|
2014-11-10 07:50:12 +03:00
|
|
|
if (NULL == (pu = opal_hwloc_base_get_pu(opal_hwloc_topology, core, OPAL_HWLOC_LOGICAL))) {
|
2014-01-31 03:50:14 +04:00
|
|
|
/* turn off the show help forwarding as we won't
|
|
|
|
* be able to cycle the event library to send
|
|
|
|
*/
|
|
|
|
orte_show_help_finalize();
|
|
|
|
/* the message will now come out locally */
|
|
|
|
orte_show_help("help-orted.txt", "orted:cannot-bind",
|
|
|
|
true, orte_process_info.nodename,
|
|
|
|
orte_daemon_cores);
|
|
|
|
ret = ORTE_ERR_NOT_SUPPORTED;
|
2015-06-03 08:55:24 +03:00
|
|
|
hwloc_bitmap_free(ours);
|
|
|
|
hwloc_bitmap_free(pucpus);
|
|
|
|
hwloc_bitmap_free(res);
|
2014-01-31 03:50:14 +04:00
|
|
|
goto DONE;
|
|
|
|
}
|
|
|
|
hwloc_bitmap_and(pucpus, pu->online_cpuset, pu->allowed_cpuset);
|
|
|
|
hwloc_bitmap_or(res, ours, pucpus);
|
|
|
|
hwloc_bitmap_copy(ours, res);
|
|
|
|
}
|
|
|
|
/* if the result is all zeros, then don't bind */
|
|
|
|
if (!hwloc_bitmap_iszero(ours)) {
|
|
|
|
(void)hwloc_set_cpubind(opal_hwloc_topology, ours, 0);
|
|
|
|
if (opal_hwloc_report_bindings) {
|
2014-03-10 19:53:07 +04:00
|
|
|
opal_hwloc_base_cset2mapstr(tmp, sizeof(tmp), opal_hwloc_topology, ours);
|
2014-01-31 03:50:14 +04:00
|
|
|
opal_output(0, "Daemon %s is bound to cores %s",
|
|
|
|
ORTE_NAME_PRINT(ORTE_PROC_MY_NAME), tmp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* cleanup */
|
|
|
|
hwloc_bitmap_free(ours);
|
|
|
|
hwloc_bitmap_free(pucpus);
|
|
|
|
hwloc_bitmap_free(res);
|
|
|
|
opal_argv_free(cores);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-03 01:30:57 +03:00
|
|
|
if ((int)ORTE_VPID_INVALID != orted_debug_failure) {
|
2008-06-03 01:46:34 +04:00
|
|
|
orted_globals.abort=false;
|
|
|
|
/* some vpid was ordered to fail. The value can be positive
|
|
|
|
* or negative, depending upon the desired method for failure,
|
|
|
|
* so need to check both here
|
|
|
|
*/
|
2016-03-03 01:30:57 +03:00
|
|
|
if (0 > orted_debug_failure) {
|
|
|
|
orted_debug_failure = -1*orted_debug_failure;
|
2008-06-03 01:46:34 +04:00
|
|
|
orted_globals.abort = true;
|
|
|
|
}
|
|
|
|
/* are we the specified vpid? */
|
2016-03-03 01:30:57 +03:00
|
|
|
if ((int)ORTE_PROC_MY_NAME->vpid == orted_debug_failure) {
|
2008-06-03 01:46:34 +04:00
|
|
|
/* if the user specified we delay, then setup a timer
|
|
|
|
* and have it kill us
|
|
|
|
*/
|
2016-03-03 01:30:57 +03:00
|
|
|
if (0 < orted_debug_failure_delay) {
|
|
|
|
ORTE_TIMER_EVENT(orted_debug_failure_delay, 0, shutdown_callback, ORTE_SYS_PRI);
|
2015-06-24 06:59:57 +03:00
|
|
|
|
2008-06-03 01:46:34 +04:00
|
|
|
} else {
|
2009-03-06 00:50:47 +03:00
|
|
|
opal_output(0, "%s is executing clean %s", ORTE_NAME_PRINT(ORTE_PROC_MY_NAME),
|
2008-06-03 01:46:34 +04:00
|
|
|
orted_globals.abort ? "abort" : "abnormal termination");
|
|
|
|
|
|
|
|
/* do -not- call finalize as this will send a message to the HNP
|
|
|
|
* indicating clean termination! Instead, just forcibly cleanup
|
|
|
|
* the local session_dir tree and exit
|
|
|
|
*/
|
|
|
|
orte_session_dir_cleanup(ORTE_JOBID_WILDCARD);
|
2015-06-24 06:59:57 +03:00
|
|
|
|
2008-06-03 01:46:34 +04:00
|
|
|
/* if we were ordered to abort, do so */
|
|
|
|
if (orted_globals.abort) {
|
|
|
|
abort();
|
|
|
|
}
|
2015-06-24 06:59:57 +03:00
|
|
|
|
2008-06-03 01:46:34 +04:00
|
|
|
/* otherwise, return with non-zero status */
|
2009-02-25 06:10:21 +03:00
|
|
|
ret = ORTE_ERROR_DEFAULT_EXIT_CODE;
|
|
|
|
goto DONE;
|
2008-06-03 01:46:34 +04:00
|
|
|
}
|
2008-05-29 17:38:27 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-28 04:57:57 +03:00
|
|
|
/* insert our contact info into our process_info struct so we
|
|
|
|
* have it for later use and set the local daemon field to our name
|
2007-07-12 23:53:18 +04:00
|
|
|
*/
|
2009-03-06 00:56:03 +03:00
|
|
|
orte_process_info.my_daemon_uri = orte_rml.get_contact_info();
|
2008-02-28 04:57:57 +03:00
|
|
|
ORTE_PROC_MY_DAEMON->jobid = ORTE_PROC_MY_NAME->jobid;
|
|
|
|
ORTE_PROC_MY_DAEMON->vpid = ORTE_PROC_MY_NAME->vpid;
|
2015-06-24 06:59:57 +03:00
|
|
|
|
2008-02-28 04:57:57 +03:00
|
|
|
/* if I am also the hnp, then update that contact info field too */
|
2009-05-04 15:07:40 +04:00
|
|
|
if (ORTE_PROC_IS_HNP) {
|
2009-03-06 00:56:03 +03:00
|
|
|
orte_process_info.my_hnp_uri = orte_rml.get_contact_info();
|
2008-02-28 04:57:57 +03:00
|
|
|
ORTE_PROC_MY_HNP->jobid = ORTE_PROC_MY_NAME->jobid;
|
|
|
|
ORTE_PROC_MY_HNP->vpid = ORTE_PROC_MY_NAME->vpid;
|
|
|
|
}
|
2015-06-24 06:59:57 +03:00
|
|
|
|
Fix a potential, albeit perhaps esoteric, race condition that can occur for fast HNP's, slow orteds, and fast apps. Under those conditions, it is possible for the orted to be caught in its original send of contact info back to the HNP, and thus for the progress stack never to recover back to a high level. In those circumstances, the orted can "hang" when trying to exit.
Add a new function to opal_progress that tells us our recursion depth to support that solution.
Yes, I know this sounds picky, but good ol' Jeff managed to make it happen by driving his cluster near to death...
Also ensure that we declare "failed" for the daemon job when daemons fail instead of the application job. This is important so that orte knows that it cannot use xcast to tell daemons to "exit", nor should it expect all daemons to respond. Otherwise, it is possible to hang.
After lots of testing, decide to default (again) to slurm detecting failed orteds. This proved necessary to avoid rather annoying hangs that were difficult to recover from. There are conditions where slurm will fail to launch all daemons (slurm folks are working on it), and yet again, good ol' Jeff managed to find both of them.
Thanks you Jeff! :-/
This commit was SVN r18611.
2008-06-06 23:36:27 +04:00
|
|
|
/* setup the primary daemon command receive function */
|
As per the RFC, bring in the ORTE async progress code and the rewrite of OOB:
*** THIS RFC INCLUDES A MINOR CHANGE TO THE MPI-RTE INTERFACE ***
Note: during the course of this work, it was necessary to completely separate the MPI and RTE progress engines. There were multiple places in the MPI layer where ORTE_WAIT_FOR_COMPLETION was being used. A new OMPI_WAIT_FOR_COMPLETION macro was created (defined in ompi/mca/rte/rte.h) that simply cycles across opal_progress until the provided flag becomes false. Places where the MPI layer blocked waiting for RTE to complete an event have been modified to use this macro.
***************************************************************************************
I am reissuing this RFC because of the time that has passed since its original release. Since its initial release and review, I have debugged it further to ensure it fully supports tests like loop_spawn. It therefore seems ready for merge back to the trunk. Given its prior review, I have set the timeout for one week.
The code is in https://bitbucket.org/rhc/ompi-oob2
WHAT: Rewrite of ORTE OOB
WHY: Support asynchronous progress and a host of other features
WHEN: Wed, August 21
SYNOPSIS:
The current OOB has served us well, but a number of limitations have been identified over the years. Specifically:
* it is only progressed when called via opal_progress, which can lead to hangs or recursive calls into libevent (which is not supported by that code)
* we've had issues when multiple NICs are available as the code doesn't "shift" messages between transports - thus, all nodes had to be available via the same TCP interface.
* the OOB "unloads" incoming opal_buffer_t objects during the transmission, thus preventing use of OBJ_RETAIN in the code when repeatedly sending the same message to multiple recipients
* there is no failover mechanism across NICs - if the selected NIC (or its attached switch) fails, we are forced to abort
* only one transport (i.e., component) can be "active"
The revised OOB resolves these problems:
* async progress is used for all application processes, with the progress thread blocking in the event library
* each available TCP NIC is supported by its own TCP module. The ability to asynchronously progress each module independently is provided, but not enabled by default (a runtime MCA parameter turns it "on")
* multi-address TCP NICs (e.g., a NIC with both an IPv4 and IPv6 address, or with virtual interfaces) are supported - reachability is determined by comparing the contact info for a peer against all addresses within the range covered by the address/mask pairs for the NIC.
* a message that arrives on one TCP NIC is automatically shifted to whatever NIC that is connected to the next "hop" if that peer cannot be reached by the incoming NIC. If no TCP module will reach the peer, then the OOB attempts to send the message via all other available components - if none can reach the peer, then an "error" is reported back to the RML, which then calls the errmgr for instructions.
* opal_buffer_t now conforms to standard object rules re OBJ_RETAIN as we no longer "unload" the incoming object
* NIC failure is reported to the TCP component, which then tries to resend the message across any other available TCP NIC. If that doesn't work, then the message is given back to the OOB base to try using other components. If all that fails, then the error is reported to the RML, which reports to the errmgr for instructions
* obviously from the above, multiple OOB components (e.g., TCP and UD) can be active in parallel
* the matching code has been moved to the RML (and out of the OOB/TCP component) so it is independent of transport
* routing is done by the individual OOB modules (as opposed to the RML). Thus, both routed and non-routed transports can simultaneously be active
* all blocking send/recv APIs have been removed. Everything operates asynchronously.
KNOWN LIMITATIONS:
* although provision is made for component failover as described above, the code for doing so has not been fully implemented yet. At the moment, if all connections for a given peer fail, the errmgr is notified of a "lost connection", which by default results in termination of the job if it was a lifeline
* the IPv6 code is present and compiles, but is not complete. Since the current IPv6 support in the OOB doesn't work anyway, I don't consider this a blocker
* routing is performed at the individual module level, yet the active routed component is selected on a global basis. We probably should update that to reflect that different transports may need/choose to route in different ways
* obviously, not every error path has been tested nor necessarily covered
* determining abnormal termination is more challenging than in the old code as we now potentially have multiple ways of connecting to a process. Ideally, we would declare "connection failed" when *all* transports can no longer reach the process, but that requires some additional (possibly complex) code. For now, the code replicates the old behavior only somewhat modified - i.e., if a module sees its connection fail, it checks to see if it is a lifeline. If so, it notifies the errmgr that the lifeline is lost - otherwise, it notifies the errmgr that a non-lifeline connection was lost.
* reachability is determined solely on the basis of a shared subnet address/mask - more sophisticated algorithms (e.g., the one used in the tcp btl) are required to handle routing via gateways
* the RML needs to assign sequence numbers to each message on a per-peer basis. The receiving RML will then deliver messages in order, thus preventing out-of-order messaging in the case where messages travel across different transports or a message needs to be redirected/resent due to failure of a NIC
This commit was SVN r29058.
2013-08-22 20:37:40 +04:00
|
|
|
orte_rml.recv_buffer_nb(ORTE_NAME_WILDCARD, ORTE_RML_TAG_DAEMON,
|
|
|
|
ORTE_RML_PERSISTENT, orte_daemon_recv, NULL);
|
2015-06-24 06:59:57 +03:00
|
|
|
|
2007-07-12 23:53:18 +04:00
|
|
|
/* output a message indicating we are alive, our name, and our pid
|
|
|
|
* for debugging purposes
|
|
|
|
*/
|
|
|
|
if (orte_debug_daemons_flag) {
|
2007-07-20 06:34:29 +04:00
|
|
|
fprintf(stderr, "Daemon %s checking in as pid %ld on host %s\n",
|
2009-03-06 00:56:03 +03:00
|
|
|
ORTE_NAME_PRINT(ORTE_PROC_MY_NAME), (long)orte_process_info.pid,
|
|
|
|
orte_process_info.nodename);
|
2007-07-12 23:53:18 +04:00
|
|
|
}
|
|
|
|
|
2007-10-06 13:24:51 +04:00
|
|
|
/* We actually do *not* want the orted to voluntarily yield() the
|
|
|
|
processor more than necessary. The orted already blocks when
|
|
|
|
it is doing nothing, so it doesn't use any more CPU cycles than
|
|
|
|
it should; but when it *is* doing something, we do not want it
|
|
|
|
to be unnecessarily delayed because it voluntarily yielded the
|
|
|
|
processor in the middle of its work.
|
|
|
|
|
|
|
|
For example: when a message arrives at the orted, we want the
|
|
|
|
OS to wake up the orted in a timely fashion (which most OS's
|
|
|
|
seem good about doing) and then we want the orted to process
|
|
|
|
the message as fast as possible. If the orted yields and lets
|
|
|
|
aggressive MPI applications get the processor back, it may be a
|
|
|
|
long time before the OS schedules the orted to run again
|
|
|
|
(particularly if there is no IO event to wake it up). Hence,
|
|
|
|
routed OOB messages (for example) may be significantly delayed
|
|
|
|
before being delivered to MPI processes, which can be
|
|
|
|
problematic in some scenarios (e.g., COMM_SPAWN, BTL's that
|
|
|
|
require OOB messages for wireup, etc.). */
|
|
|
|
opal_progress_set_yield_when_idle(false);
|
2007-07-12 23:53:18 +04:00
|
|
|
|
2007-10-15 19:41:36 +04:00
|
|
|
/* Change the default behavior of libevent such that we want to
|
|
|
|
continually block rather than blocking for the default timeout
|
|
|
|
and then looping around the progress engine again. There
|
|
|
|
should be nothing in the orted that cannot block in libevent
|
|
|
|
until "something" happens (i.e., there's no need to keep
|
|
|
|
cycling through progress because the only things that should
|
|
|
|
happen will happen in libevent). This is a minor optimization,
|
|
|
|
but what the heck... :-) */
|
|
|
|
opal_progress_set_event_flag(OPAL_EVLOOP_ONCE);
|
|
|
|
|
2013-10-04 06:58:26 +04:00
|
|
|
/* if requested, report my uri to the indicated pipe */
|
2007-07-12 23:53:18 +04:00
|
|
|
if (orted_globals.uri_pipe > 0) {
|
2008-02-28 04:57:57 +03:00
|
|
|
orte_job_t *jdata;
|
|
|
|
orte_proc_t *proc;
|
2012-04-06 18:23:13 +04:00
|
|
|
orte_node_t *node;
|
These changes were mostly captured in a prior RFC (except for #2 below) and are aimed specifically at improving startup performance and setting up the remaining modifications described in that RFC.
The commit has been tested for C/R and Cray operations, and on Odin (SLURM, rsh) and RoadRunner (TM). I tried to update all environments, but obviously could not test them. I know that Windows needs some work, and have highlighted what is know to be needed in the odls process component.
This represents a lot of work by Brian, Tim P, Josh, and myself, with much advice from Jeff and others. For posterity, I have appended a copy of the email describing the work that was done:
As we have repeatedly noted, the modex operation in MPI_Init is the single greatest consumer of time during startup. To-date, we have executed that operation as an ORTE stage gate that held the process until a startup message containing all required modex (and OOB contact info - see #3 below) info could be sent to it. Each process would send its data to the HNP's registry, which assembled and sent the message when all processes had reported in.
In addition, ORTE had taken responsibility for monitoring process status as it progressed through a series of "stage gates". The process reported its status at each gate, and ORTE would then send a "release" message once all procs had reported in.
The incoming changes revamp these procedures in three ways:
1. eliminating the ORTE stage gate system and cleanly delineating responsibility between the OMPI and ORTE layers for MPI init/finalize. The modex stage gate (STG1) has been replaced by a collective operation in the modex itself that performs an allgather on the required modex info. The allgather is implemented using the orte_grpcomm framework since the BTL's are not active at that point. At the moment, the grpcomm framework only has a "basic" component analogous to OMPI's "basic" coll framework - I would recommend that the MPI team create additional, more advanced components to improve performance of this step.
The other stage gates have been replaced by orte_grpcomm barrier functions. We tried to use MPI barriers instead (since the BTL's are active at that point), but - as we discussed on the telecon - these are not currently true barriers so the job would hang when we fell through while messages were still in process. Note that the grpcomm barrier doesn't actually resolve that problem, but Brian has pointed out that we are unlikely to ever see it violated. Again, you might want to spend a little time on an advanced barrier algorithm as the one in "basic" is very simplistic.
Summarizing this change: ORTE no longer tracks process state nor has direct responsibility for synchronizing jobs. This is now done via collective operations within the MPI layer, albeit using ORTE collective communication services. I -strongly- urge the MPI team to implement advanced collective algorithms to improve the performance of this critical procedure.
2. reducing the volume of data exchanged during modex. Data in the modex consisted of the process name, the name of the node where that process is located (expressed as a string), plus a string representation of all contact info. The nodename was required in order for the modex to determine if the process was local or not - in addition, some people like to have it to print pretty error messages when a connection failed.
The size of this data has been reduced in three ways:
(a) reducing the size of the process name itself. The process name consisted of two 32-bit fields for the jobid and vpid. This is far larger than any current system, or system likely to exist in the near future, can support. Accordingly, the default size of these fields has been reduced to 16-bits, which means you can have 32k procs in each of 32k jobs. Since the daemons must have a vpid, and we require one daemon/node, this also restricts the default configuration to 32k nodes.
To support any future "mega-clusters", a configuration option --enable-jumbo-apps has been added. This option increases the jobid and vpid field sizes to 32-bits. Someday, if necessary, someone can add yet another option to increase them to 64-bits, I suppose.
(b) replacing the string nodename with an integer nodeid. Since we have one daemon/node, the nodeid corresponds to the local daemon's vpid. This replaces an often lengthy string with only 2 (or at most 4) bytes, a substantial reduction.
(c) when the mca param requesting that nodenames be sent to support pretty error messages, a second mca param is now used to request FQDN - otherwise, the domain name is stripped (by default) from the message to save space. If someone wants to combine those into a single param somehow (perhaps with an argument?), they are welcome to do so - I didn't want to alter what people are already using.
While these may seem like small savings, they actually amount to a significant impact when aggregated across the entire modex operation. Since every proc must receive the modex data regardless of the collective used to send it, just reducing the size of the process name removes nearly 400MBytes of communication from a 32k proc job (admittedly, much of this comm may occur in parallel). So it does add up pretty quickly.
3. routing RML messages to reduce connections. The default messaging system remains point-to-point - i.e., each proc opens a socket to every proc it communicates with and sends its messages directly. A new option uses the orteds as routers - i.e., each proc only opens a single socket to its local orted. All messages are sent from the proc to the orted, which forwards the message to the orted on the node where the intended recipient proc is located - that orted then forwards the message to its local proc (the recipient). This greatly reduces the connection storm we have encountered during startup.
It also has the benefit of removing the sharing of every proc's OOB contact with every other proc. The orted routing tables are populated during launch since every orted gets a map of where every proc is being placed. Each proc, therefore, only needs to know the contact info for its local daemon, which is passed in via the environment when the proc is fork/exec'd by the daemon. This alone removes ~50 bytes/process of communication that was in the current STG1 startup message - so for our 32k proc job, this saves us roughly 32k*50 = 1.6MBytes sent to 32k procs = 51GBytes of messaging.
Note that you can use the new routing method by specifying -mca routed tree - if you so desire. This mode will become the default at some point in the future.
There are a few minor additional changes in the commit that I'll just note in passing:
* propagation of command line mca params to the orteds - fixes ticket #1073. See note there for details.
* requiring of "finalize" prior to "exit" for MPI procs - fixes ticket #1144. See note there for details.
* cleanup of some stale header files
This commit was SVN r16364.
2007-10-05 23:48:23 +04:00
|
|
|
orte_app_context_t *app;
|
2010-08-09 23:28:56 +04:00
|
|
|
char *tmp, *nptr, *sysinfo;
|
2016-09-19 07:37:08 +03:00
|
|
|
char **singenv=NULL, *string_key, *env_str;
|
2008-02-28 04:57:57 +03:00
|
|
|
|
These changes were mostly captured in a prior RFC (except for #2 below) and are aimed specifically at improving startup performance and setting up the remaining modifications described in that RFC.
The commit has been tested for C/R and Cray operations, and on Odin (SLURM, rsh) and RoadRunner (TM). I tried to update all environments, but obviously could not test them. I know that Windows needs some work, and have highlighted what is know to be needed in the odls process component.
This represents a lot of work by Brian, Tim P, Josh, and myself, with much advice from Jeff and others. For posterity, I have appended a copy of the email describing the work that was done:
As we have repeatedly noted, the modex operation in MPI_Init is the single greatest consumer of time during startup. To-date, we have executed that operation as an ORTE stage gate that held the process until a startup message containing all required modex (and OOB contact info - see #3 below) info could be sent to it. Each process would send its data to the HNP's registry, which assembled and sent the message when all processes had reported in.
In addition, ORTE had taken responsibility for monitoring process status as it progressed through a series of "stage gates". The process reported its status at each gate, and ORTE would then send a "release" message once all procs had reported in.
The incoming changes revamp these procedures in three ways:
1. eliminating the ORTE stage gate system and cleanly delineating responsibility between the OMPI and ORTE layers for MPI init/finalize. The modex stage gate (STG1) has been replaced by a collective operation in the modex itself that performs an allgather on the required modex info. The allgather is implemented using the orte_grpcomm framework since the BTL's are not active at that point. At the moment, the grpcomm framework only has a "basic" component analogous to OMPI's "basic" coll framework - I would recommend that the MPI team create additional, more advanced components to improve performance of this step.
The other stage gates have been replaced by orte_grpcomm barrier functions. We tried to use MPI barriers instead (since the BTL's are active at that point), but - as we discussed on the telecon - these are not currently true barriers so the job would hang when we fell through while messages were still in process. Note that the grpcomm barrier doesn't actually resolve that problem, but Brian has pointed out that we are unlikely to ever see it violated. Again, you might want to spend a little time on an advanced barrier algorithm as the one in "basic" is very simplistic.
Summarizing this change: ORTE no longer tracks process state nor has direct responsibility for synchronizing jobs. This is now done via collective operations within the MPI layer, albeit using ORTE collective communication services. I -strongly- urge the MPI team to implement advanced collective algorithms to improve the performance of this critical procedure.
2. reducing the volume of data exchanged during modex. Data in the modex consisted of the process name, the name of the node where that process is located (expressed as a string), plus a string representation of all contact info. The nodename was required in order for the modex to determine if the process was local or not - in addition, some people like to have it to print pretty error messages when a connection failed.
The size of this data has been reduced in three ways:
(a) reducing the size of the process name itself. The process name consisted of two 32-bit fields for the jobid and vpid. This is far larger than any current system, or system likely to exist in the near future, can support. Accordingly, the default size of these fields has been reduced to 16-bits, which means you can have 32k procs in each of 32k jobs. Since the daemons must have a vpid, and we require one daemon/node, this also restricts the default configuration to 32k nodes.
To support any future "mega-clusters", a configuration option --enable-jumbo-apps has been added. This option increases the jobid and vpid field sizes to 32-bits. Someday, if necessary, someone can add yet another option to increase them to 64-bits, I suppose.
(b) replacing the string nodename with an integer nodeid. Since we have one daemon/node, the nodeid corresponds to the local daemon's vpid. This replaces an often lengthy string with only 2 (or at most 4) bytes, a substantial reduction.
(c) when the mca param requesting that nodenames be sent to support pretty error messages, a second mca param is now used to request FQDN - otherwise, the domain name is stripped (by default) from the message to save space. If someone wants to combine those into a single param somehow (perhaps with an argument?), they are welcome to do so - I didn't want to alter what people are already using.
While these may seem like small savings, they actually amount to a significant impact when aggregated across the entire modex operation. Since every proc must receive the modex data regardless of the collective used to send it, just reducing the size of the process name removes nearly 400MBytes of communication from a 32k proc job (admittedly, much of this comm may occur in parallel). So it does add up pretty quickly.
3. routing RML messages to reduce connections. The default messaging system remains point-to-point - i.e., each proc opens a socket to every proc it communicates with and sends its messages directly. A new option uses the orteds as routers - i.e., each proc only opens a single socket to its local orted. All messages are sent from the proc to the orted, which forwards the message to the orted on the node where the intended recipient proc is located - that orted then forwards the message to its local proc (the recipient). This greatly reduces the connection storm we have encountered during startup.
It also has the benefit of removing the sharing of every proc's OOB contact with every other proc. The orted routing tables are populated during launch since every orted gets a map of where every proc is being placed. Each proc, therefore, only needs to know the contact info for its local daemon, which is passed in via the environment when the proc is fork/exec'd by the daemon. This alone removes ~50 bytes/process of communication that was in the current STG1 startup message - so for our 32k proc job, this saves us roughly 32k*50 = 1.6MBytes sent to 32k procs = 51GBytes of messaging.
Note that you can use the new routing method by specifying -mca routed tree - if you so desire. This mode will become the default at some point in the future.
There are a few minor additional changes in the commit that I'll just note in passing:
* propagation of command line mca params to the orteds - fixes ticket #1073. See note there for details.
* requiring of "finalize" prior to "exit" for MPI procs - fixes ticket #1144. See note there for details.
* cleanup of some stale header files
This commit was SVN r16364.
2007-10-05 23:48:23 +04:00
|
|
|
/* setup the singleton's job */
|
2008-02-28 04:57:57 +03:00
|
|
|
jdata = OBJ_NEW(orte_job_t);
|
2015-01-27 16:14:36 +03:00
|
|
|
/* default to ompi for now */
|
2016-02-17 19:32:17 +03:00
|
|
|
opal_argv_append_nosize(&jdata->personality, "ompi");
|
2009-06-06 05:08:47 +04:00
|
|
|
orte_plm_base_create_jobid(jdata);
|
2016-02-16 17:51:20 +03:00
|
|
|
opal_hash_table_set_value_uint32(orte_job_data, jdata->jobid, jdata);
|
2012-06-27 18:53:55 +04:00
|
|
|
|
2010-07-18 06:48:17 +04:00
|
|
|
/* must create a map for it (even though it has no
|
|
|
|
* info in it) so that the job info will be picked
|
|
|
|
* up in subsequent pidmaps or other daemons won't
|
|
|
|
* know how to route
|
|
|
|
*/
|
|
|
|
jdata->map = OBJ_NEW(orte_job_map_t);
|
|
|
|
|
2008-02-28 04:57:57 +03:00
|
|
|
/* setup an app_context for the singleton */
|
These changes were mostly captured in a prior RFC (except for #2 below) and are aimed specifically at improving startup performance and setting up the remaining modifications described in that RFC.
The commit has been tested for C/R and Cray operations, and on Odin (SLURM, rsh) and RoadRunner (TM). I tried to update all environments, but obviously could not test them. I know that Windows needs some work, and have highlighted what is know to be needed in the odls process component.
This represents a lot of work by Brian, Tim P, Josh, and myself, with much advice from Jeff and others. For posterity, I have appended a copy of the email describing the work that was done:
As we have repeatedly noted, the modex operation in MPI_Init is the single greatest consumer of time during startup. To-date, we have executed that operation as an ORTE stage gate that held the process until a startup message containing all required modex (and OOB contact info - see #3 below) info could be sent to it. Each process would send its data to the HNP's registry, which assembled and sent the message when all processes had reported in.
In addition, ORTE had taken responsibility for monitoring process status as it progressed through a series of "stage gates". The process reported its status at each gate, and ORTE would then send a "release" message once all procs had reported in.
The incoming changes revamp these procedures in three ways:
1. eliminating the ORTE stage gate system and cleanly delineating responsibility between the OMPI and ORTE layers for MPI init/finalize. The modex stage gate (STG1) has been replaced by a collective operation in the modex itself that performs an allgather on the required modex info. The allgather is implemented using the orte_grpcomm framework since the BTL's are not active at that point. At the moment, the grpcomm framework only has a "basic" component analogous to OMPI's "basic" coll framework - I would recommend that the MPI team create additional, more advanced components to improve performance of this step.
The other stage gates have been replaced by orte_grpcomm barrier functions. We tried to use MPI barriers instead (since the BTL's are active at that point), but - as we discussed on the telecon - these are not currently true barriers so the job would hang when we fell through while messages were still in process. Note that the grpcomm barrier doesn't actually resolve that problem, but Brian has pointed out that we are unlikely to ever see it violated. Again, you might want to spend a little time on an advanced barrier algorithm as the one in "basic" is very simplistic.
Summarizing this change: ORTE no longer tracks process state nor has direct responsibility for synchronizing jobs. This is now done via collective operations within the MPI layer, albeit using ORTE collective communication services. I -strongly- urge the MPI team to implement advanced collective algorithms to improve the performance of this critical procedure.
2. reducing the volume of data exchanged during modex. Data in the modex consisted of the process name, the name of the node where that process is located (expressed as a string), plus a string representation of all contact info. The nodename was required in order for the modex to determine if the process was local or not - in addition, some people like to have it to print pretty error messages when a connection failed.
The size of this data has been reduced in three ways:
(a) reducing the size of the process name itself. The process name consisted of two 32-bit fields for the jobid and vpid. This is far larger than any current system, or system likely to exist in the near future, can support. Accordingly, the default size of these fields has been reduced to 16-bits, which means you can have 32k procs in each of 32k jobs. Since the daemons must have a vpid, and we require one daemon/node, this also restricts the default configuration to 32k nodes.
To support any future "mega-clusters", a configuration option --enable-jumbo-apps has been added. This option increases the jobid and vpid field sizes to 32-bits. Someday, if necessary, someone can add yet another option to increase them to 64-bits, I suppose.
(b) replacing the string nodename with an integer nodeid. Since we have one daemon/node, the nodeid corresponds to the local daemon's vpid. This replaces an often lengthy string with only 2 (or at most 4) bytes, a substantial reduction.
(c) when the mca param requesting that nodenames be sent to support pretty error messages, a second mca param is now used to request FQDN - otherwise, the domain name is stripped (by default) from the message to save space. If someone wants to combine those into a single param somehow (perhaps with an argument?), they are welcome to do so - I didn't want to alter what people are already using.
While these may seem like small savings, they actually amount to a significant impact when aggregated across the entire modex operation. Since every proc must receive the modex data regardless of the collective used to send it, just reducing the size of the process name removes nearly 400MBytes of communication from a 32k proc job (admittedly, much of this comm may occur in parallel). So it does add up pretty quickly.
3. routing RML messages to reduce connections. The default messaging system remains point-to-point - i.e., each proc opens a socket to every proc it communicates with and sends its messages directly. A new option uses the orteds as routers - i.e., each proc only opens a single socket to its local orted. All messages are sent from the proc to the orted, which forwards the message to the orted on the node where the intended recipient proc is located - that orted then forwards the message to its local proc (the recipient). This greatly reduces the connection storm we have encountered during startup.
It also has the benefit of removing the sharing of every proc's OOB contact with every other proc. The orted routing tables are populated during launch since every orted gets a map of where every proc is being placed. Each proc, therefore, only needs to know the contact info for its local daemon, which is passed in via the environment when the proc is fork/exec'd by the daemon. This alone removes ~50 bytes/process of communication that was in the current STG1 startup message - so for our 32k proc job, this saves us roughly 32k*50 = 1.6MBytes sent to 32k procs = 51GBytes of messaging.
Note that you can use the new routing method by specifying -mca routed tree - if you so desire. This mode will become the default at some point in the future.
There are a few minor additional changes in the commit that I'll just note in passing:
* propagation of command line mca params to the orteds - fixes ticket #1073. See note there for details.
* requiring of "finalize" prior to "exit" for MPI procs - fixes ticket #1144. See note there for details.
* cleanup of some stale header files
This commit was SVN r16364.
2007-10-05 23:48:23 +04:00
|
|
|
app = OBJ_NEW(orte_app_context_t);
|
|
|
|
app->app = strdup("singleton");
|
|
|
|
app->num_procs = 1;
|
2008-02-28 08:32:23 +03:00
|
|
|
opal_pointer_array_add(jdata->apps, app);
|
2016-02-25 20:05:38 +03:00
|
|
|
jdata->num_apps = 1;
|
2015-06-24 06:59:57 +03:00
|
|
|
|
2008-02-28 04:57:57 +03:00
|
|
|
/* setup a proc object for the singleton - since we
|
|
|
|
* -must- be the HNP, and therefore we stored our
|
|
|
|
* node on the global node pool, and since the singleton
|
|
|
|
* -must- be on the same node as us, indicate that
|
|
|
|
*/
|
|
|
|
proc = OBJ_NEW(orte_proc_t);
|
|
|
|
proc->name.jobid = jdata->jobid;
|
|
|
|
proc->name.vpid = 0;
|
2014-12-04 05:09:28 +03:00
|
|
|
proc->parent = 0;
|
2014-06-01 20:14:10 +04:00
|
|
|
ORTE_FLAG_SET(proc, ORTE_PROC_FLAG_ALIVE);
|
2008-02-28 04:57:57 +03:00
|
|
|
proc->state = ORTE_PROC_STATE_RUNNING;
|
|
|
|
proc->app_idx = 0;
|
2012-06-27 18:53:55 +04:00
|
|
|
/* obviously, it is on my node */
|
2012-04-06 18:23:13 +04:00
|
|
|
node = (orte_node_t*)opal_pointer_array_get_item(orte_node_pool, 0);
|
|
|
|
proc->node = node;
|
|
|
|
OBJ_RETAIN(node); /* keep accounting straight */
|
2008-02-28 08:32:23 +03:00
|
|
|
opal_pointer_array_add(jdata->procs, proc);
|
2008-02-28 04:57:57 +03:00
|
|
|
jdata->num_procs = 1;
|
2014-12-04 05:09:28 +03:00
|
|
|
/* add the node to the job map */
|
|
|
|
OBJ_RETAIN(node);
|
|
|
|
opal_pointer_array_add(jdata->map->nodes, node);
|
|
|
|
jdata->map->num_nodes++;
|
2012-09-04 05:10:26 +04:00
|
|
|
/* and it obviously is on the node */
|
|
|
|
OBJ_RETAIN(proc);
|
|
|
|
opal_pointer_array_add(node->procs, proc);
|
|
|
|
node->num_procs++;
|
2012-06-27 18:53:55 +04:00
|
|
|
/* and obviously it is one of my local procs */
|
2012-04-10 23:08:54 +04:00
|
|
|
OBJ_RETAIN(proc);
|
|
|
|
opal_pointer_array_add(orte_local_children, proc);
|
2012-04-06 18:23:13 +04:00
|
|
|
jdata->num_local_procs = 1;
|
2012-06-27 18:53:55 +04:00
|
|
|
/* set the trivial */
|
|
|
|
proc->local_rank = 0;
|
|
|
|
proc->node_rank = 0;
|
|
|
|
proc->app_rank = 0;
|
|
|
|
proc->state = ORTE_PROC_STATE_RUNNING;
|
|
|
|
proc->app_idx = 0;
|
2014-06-01 20:14:10 +04:00
|
|
|
ORTE_FLAG_SET(proc, ORTE_PROC_FLAG_LOCAL);
|
2012-06-27 18:53:55 +04:00
|
|
|
|
2016-09-19 07:37:08 +03:00
|
|
|
/* set the ORTE_JOB_TRANSPORT_KEY from the environment */
|
|
|
|
orte_pre_condition_transports(jdata);
|
|
|
|
|
2015-06-18 19:53:20 +03:00
|
|
|
/* register the singleton's nspace with our PMIx server */
|
|
|
|
if (ORTE_SUCCESS != (ret = orte_pmix_server_register_nspace(jdata))) {
|
|
|
|
ORTE_ERROR_LOG(ret);
|
|
|
|
goto DONE;
|
|
|
|
}
|
|
|
|
/* use setup fork to create the envars needed by the singleton */
|
|
|
|
if (OPAL_SUCCESS != (ret = opal_pmix.server_setup_fork(&proc->name, &singenv))) {
|
2016-09-20 08:56:58 +03:00
|
|
|
ORTE_ERROR_LOG(ret);
|
|
|
|
goto DONE;
|
2015-06-18 19:53:20 +03:00
|
|
|
}
|
2016-09-19 07:37:08 +03:00
|
|
|
|
|
|
|
/* append the transport key to the envars needed by the singleton */
|
|
|
|
if (!orte_get_attribute(&jdata->attributes, ORTE_JOB_TRANSPORT_KEY, (void**)&string_key, OPAL_STRING) || NULL == string_key) {
|
|
|
|
ORTE_ERROR_LOG(ORTE_ERR_NOT_FOUND);
|
|
|
|
goto DONE;
|
|
|
|
}
|
|
|
|
asprintf(&env_str, OPAL_MCA_PREFIX"orte_precondition_transports=%s", string_key);
|
|
|
|
opal_argv_append_nosize(&singenv, env_str);
|
|
|
|
free(env_str);
|
|
|
|
|
2015-06-18 19:53:20 +03:00
|
|
|
nptr = opal_argv_join(singenv, ',');
|
|
|
|
opal_argv_free(singenv);
|
|
|
|
/* create a string that contains our uri + sysinfo + PMIx server URI envars */
|
2010-08-09 23:28:56 +04:00
|
|
|
orte_util_convert_sysinfo_to_string(&sysinfo, orte_local_cpu_type, orte_local_cpu_model);
|
2015-06-18 19:53:20 +03:00
|
|
|
asprintf(&tmp, "%s[%s]%s", orte_process_info.my_daemon_uri, sysinfo, nptr);
|
|
|
|
free(sysinfo);
|
|
|
|
free(nptr);
|
These changes were mostly captured in a prior RFC (except for #2 below) and are aimed specifically at improving startup performance and setting up the remaining modifications described in that RFC.
The commit has been tested for C/R and Cray operations, and on Odin (SLURM, rsh) and RoadRunner (TM). I tried to update all environments, but obviously could not test them. I know that Windows needs some work, and have highlighted what is know to be needed in the odls process component.
This represents a lot of work by Brian, Tim P, Josh, and myself, with much advice from Jeff and others. For posterity, I have appended a copy of the email describing the work that was done:
As we have repeatedly noted, the modex operation in MPI_Init is the single greatest consumer of time during startup. To-date, we have executed that operation as an ORTE stage gate that held the process until a startup message containing all required modex (and OOB contact info - see #3 below) info could be sent to it. Each process would send its data to the HNP's registry, which assembled and sent the message when all processes had reported in.
In addition, ORTE had taken responsibility for monitoring process status as it progressed through a series of "stage gates". The process reported its status at each gate, and ORTE would then send a "release" message once all procs had reported in.
The incoming changes revamp these procedures in three ways:
1. eliminating the ORTE stage gate system and cleanly delineating responsibility between the OMPI and ORTE layers for MPI init/finalize. The modex stage gate (STG1) has been replaced by a collective operation in the modex itself that performs an allgather on the required modex info. The allgather is implemented using the orte_grpcomm framework since the BTL's are not active at that point. At the moment, the grpcomm framework only has a "basic" component analogous to OMPI's "basic" coll framework - I would recommend that the MPI team create additional, more advanced components to improve performance of this step.
The other stage gates have been replaced by orte_grpcomm barrier functions. We tried to use MPI barriers instead (since the BTL's are active at that point), but - as we discussed on the telecon - these are not currently true barriers so the job would hang when we fell through while messages were still in process. Note that the grpcomm barrier doesn't actually resolve that problem, but Brian has pointed out that we are unlikely to ever see it violated. Again, you might want to spend a little time on an advanced barrier algorithm as the one in "basic" is very simplistic.
Summarizing this change: ORTE no longer tracks process state nor has direct responsibility for synchronizing jobs. This is now done via collective operations within the MPI layer, albeit using ORTE collective communication services. I -strongly- urge the MPI team to implement advanced collective algorithms to improve the performance of this critical procedure.
2. reducing the volume of data exchanged during modex. Data in the modex consisted of the process name, the name of the node where that process is located (expressed as a string), plus a string representation of all contact info. The nodename was required in order for the modex to determine if the process was local or not - in addition, some people like to have it to print pretty error messages when a connection failed.
The size of this data has been reduced in three ways:
(a) reducing the size of the process name itself. The process name consisted of two 32-bit fields for the jobid and vpid. This is far larger than any current system, or system likely to exist in the near future, can support. Accordingly, the default size of these fields has been reduced to 16-bits, which means you can have 32k procs in each of 32k jobs. Since the daemons must have a vpid, and we require one daemon/node, this also restricts the default configuration to 32k nodes.
To support any future "mega-clusters", a configuration option --enable-jumbo-apps has been added. This option increases the jobid and vpid field sizes to 32-bits. Someday, if necessary, someone can add yet another option to increase them to 64-bits, I suppose.
(b) replacing the string nodename with an integer nodeid. Since we have one daemon/node, the nodeid corresponds to the local daemon's vpid. This replaces an often lengthy string with only 2 (or at most 4) bytes, a substantial reduction.
(c) when the mca param requesting that nodenames be sent to support pretty error messages, a second mca param is now used to request FQDN - otherwise, the domain name is stripped (by default) from the message to save space. If someone wants to combine those into a single param somehow (perhaps with an argument?), they are welcome to do so - I didn't want to alter what people are already using.
While these may seem like small savings, they actually amount to a significant impact when aggregated across the entire modex operation. Since every proc must receive the modex data regardless of the collective used to send it, just reducing the size of the process name removes nearly 400MBytes of communication from a 32k proc job (admittedly, much of this comm may occur in parallel). So it does add up pretty quickly.
3. routing RML messages to reduce connections. The default messaging system remains point-to-point - i.e., each proc opens a socket to every proc it communicates with and sends its messages directly. A new option uses the orteds as routers - i.e., each proc only opens a single socket to its local orted. All messages are sent from the proc to the orted, which forwards the message to the orted on the node where the intended recipient proc is located - that orted then forwards the message to its local proc (the recipient). This greatly reduces the connection storm we have encountered during startup.
It also has the benefit of removing the sharing of every proc's OOB contact with every other proc. The orted routing tables are populated during launch since every orted gets a map of where every proc is being placed. Each proc, therefore, only needs to know the contact info for its local daemon, which is passed in via the environment when the proc is fork/exec'd by the daemon. This alone removes ~50 bytes/process of communication that was in the current STG1 startup message - so for our 32k proc job, this saves us roughly 32k*50 = 1.6MBytes sent to 32k procs = 51GBytes of messaging.
Note that you can use the new routing method by specifying -mca routed tree - if you so desire. This mode will become the default at some point in the future.
There are a few minor additional changes in the commit that I'll just note in passing:
* propagation of command line mca params to the orteds - fixes ticket #1073. See note there for details.
* requiring of "finalize" prior to "exit" for MPI procs - fixes ticket #1144. See note there for details.
* cleanup of some stale header files
This commit was SVN r16364.
2007-10-05 23:48:23 +04:00
|
|
|
|
|
|
|
/* pass that info to the singleton */
|
2016-09-20 08:56:58 +03:00
|
|
|
if (OPAL_SUCCESS != (ret = opal_fd_write(orted_globals.uri_pipe, strlen(tmp)+1, tmp))) { ; /* need to add 1 to get the NULL */
|
|
|
|
ORTE_ERROR_LOG(ret);
|
|
|
|
goto DONE;
|
|
|
|
}
|
These changes were mostly captured in a prior RFC (except for #2 below) and are aimed specifically at improving startup performance and setting up the remaining modifications described in that RFC.
The commit has been tested for C/R and Cray operations, and on Odin (SLURM, rsh) and RoadRunner (TM). I tried to update all environments, but obviously could not test them. I know that Windows needs some work, and have highlighted what is know to be needed in the odls process component.
This represents a lot of work by Brian, Tim P, Josh, and myself, with much advice from Jeff and others. For posterity, I have appended a copy of the email describing the work that was done:
As we have repeatedly noted, the modex operation in MPI_Init is the single greatest consumer of time during startup. To-date, we have executed that operation as an ORTE stage gate that held the process until a startup message containing all required modex (and OOB contact info - see #3 below) info could be sent to it. Each process would send its data to the HNP's registry, which assembled and sent the message when all processes had reported in.
In addition, ORTE had taken responsibility for monitoring process status as it progressed through a series of "stage gates". The process reported its status at each gate, and ORTE would then send a "release" message once all procs had reported in.
The incoming changes revamp these procedures in three ways:
1. eliminating the ORTE stage gate system and cleanly delineating responsibility between the OMPI and ORTE layers for MPI init/finalize. The modex stage gate (STG1) has been replaced by a collective operation in the modex itself that performs an allgather on the required modex info. The allgather is implemented using the orte_grpcomm framework since the BTL's are not active at that point. At the moment, the grpcomm framework only has a "basic" component analogous to OMPI's "basic" coll framework - I would recommend that the MPI team create additional, more advanced components to improve performance of this step.
The other stage gates have been replaced by orte_grpcomm barrier functions. We tried to use MPI barriers instead (since the BTL's are active at that point), but - as we discussed on the telecon - these are not currently true barriers so the job would hang when we fell through while messages were still in process. Note that the grpcomm barrier doesn't actually resolve that problem, but Brian has pointed out that we are unlikely to ever see it violated. Again, you might want to spend a little time on an advanced barrier algorithm as the one in "basic" is very simplistic.
Summarizing this change: ORTE no longer tracks process state nor has direct responsibility for synchronizing jobs. This is now done via collective operations within the MPI layer, albeit using ORTE collective communication services. I -strongly- urge the MPI team to implement advanced collective algorithms to improve the performance of this critical procedure.
2. reducing the volume of data exchanged during modex. Data in the modex consisted of the process name, the name of the node where that process is located (expressed as a string), plus a string representation of all contact info. The nodename was required in order for the modex to determine if the process was local or not - in addition, some people like to have it to print pretty error messages when a connection failed.
The size of this data has been reduced in three ways:
(a) reducing the size of the process name itself. The process name consisted of two 32-bit fields for the jobid and vpid. This is far larger than any current system, or system likely to exist in the near future, can support. Accordingly, the default size of these fields has been reduced to 16-bits, which means you can have 32k procs in each of 32k jobs. Since the daemons must have a vpid, and we require one daemon/node, this also restricts the default configuration to 32k nodes.
To support any future "mega-clusters", a configuration option --enable-jumbo-apps has been added. This option increases the jobid and vpid field sizes to 32-bits. Someday, if necessary, someone can add yet another option to increase them to 64-bits, I suppose.
(b) replacing the string nodename with an integer nodeid. Since we have one daemon/node, the nodeid corresponds to the local daemon's vpid. This replaces an often lengthy string with only 2 (or at most 4) bytes, a substantial reduction.
(c) when the mca param requesting that nodenames be sent to support pretty error messages, a second mca param is now used to request FQDN - otherwise, the domain name is stripped (by default) from the message to save space. If someone wants to combine those into a single param somehow (perhaps with an argument?), they are welcome to do so - I didn't want to alter what people are already using.
While these may seem like small savings, they actually amount to a significant impact when aggregated across the entire modex operation. Since every proc must receive the modex data regardless of the collective used to send it, just reducing the size of the process name removes nearly 400MBytes of communication from a 32k proc job (admittedly, much of this comm may occur in parallel). So it does add up pretty quickly.
3. routing RML messages to reduce connections. The default messaging system remains point-to-point - i.e., each proc opens a socket to every proc it communicates with and sends its messages directly. A new option uses the orteds as routers - i.e., each proc only opens a single socket to its local orted. All messages are sent from the proc to the orted, which forwards the message to the orted on the node where the intended recipient proc is located - that orted then forwards the message to its local proc (the recipient). This greatly reduces the connection storm we have encountered during startup.
It also has the benefit of removing the sharing of every proc's OOB contact with every other proc. The orted routing tables are populated during launch since every orted gets a map of where every proc is being placed. Each proc, therefore, only needs to know the contact info for its local daemon, which is passed in via the environment when the proc is fork/exec'd by the daemon. This alone removes ~50 bytes/process of communication that was in the current STG1 startup message - so for our 32k proc job, this saves us roughly 32k*50 = 1.6MBytes sent to 32k procs = 51GBytes of messaging.
Note that you can use the new routing method by specifying -mca routed tree - if you so desire. This mode will become the default at some point in the future.
There are a few minor additional changes in the commit that I'll just note in passing:
* propagation of command line mca params to the orteds - fixes ticket #1073. See note there for details.
* requiring of "finalize" prior to "exit" for MPI procs - fixes ticket #1144. See note there for details.
* cleanup of some stale header files
This commit was SVN r16364.
2007-10-05 23:48:23 +04:00
|
|
|
|
|
|
|
/* cleanup */
|
|
|
|
free(tmp);
|
2016-09-22 07:18:54 +03:00
|
|
|
close(orted_globals.uri_pipe);
|
2012-09-04 05:10:26 +04:00
|
|
|
|
|
|
|
/* since a singleton spawned us, we need to harvest
|
|
|
|
* any MCA params from the local environment so
|
|
|
|
* we can pass them along to any subsequent daemons
|
|
|
|
* we may start as the result of a comm_spawn
|
|
|
|
*/
|
|
|
|
for (i=0; NULL != environ[i]; i++) {
|
2014-10-23 00:56:37 +04:00
|
|
|
if (0 == strncmp(environ[i], OPAL_MCA_PREFIX, 9)) {
|
2012-09-04 05:10:26 +04:00
|
|
|
/* make a copy to manipulate */
|
|
|
|
tmp = strdup(environ[i]);
|
|
|
|
/* find the equal sign */
|
|
|
|
nptr = strchr(tmp, '=');
|
|
|
|
*nptr = '\0';
|
|
|
|
nptr++;
|
|
|
|
/* add the mca param to the orted cmd line */
|
2014-10-23 00:56:37 +04:00
|
|
|
opal_argv_append_nosize(&orted_cmd_line, "-"OPAL_MCA_CMD_LINE_ID);
|
2012-09-04 05:10:26 +04:00
|
|
|
opal_argv_append_nosize(&orted_cmd_line, &tmp[9]);
|
|
|
|
opal_argv_append_nosize(&orted_cmd_line, nptr);
|
|
|
|
free(tmp);
|
|
|
|
}
|
|
|
|
}
|
2007-07-12 23:53:18 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* if we were given a pipe to monitor for singleton termination, set that up */
|
|
|
|
if (orted_globals.singleton_died_pipe > 0) {
|
|
|
|
/* register shutdown handler */
|
2012-04-06 18:23:13 +04:00
|
|
|
pipe_handler = (opal_event_t*)malloc(sizeof(opal_event_t));
|
|
|
|
opal_event_set(orte_event_base, pipe_handler,
|
2007-07-12 23:53:18 +04:00
|
|
|
orted_globals.singleton_died_pipe,
|
2012-04-06 18:23:13 +04:00
|
|
|
OPAL_EV_READ,
|
|
|
|
pipe_closed,
|
2012-04-10 23:08:54 +04:00
|
|
|
pipe_handler);
|
2012-04-06 18:23:13 +04:00
|
|
|
opal_event_add(pipe_handler, NULL);
|
2007-07-12 23:53:18 +04:00
|
|
|
}
|
|
|
|
|
2011-11-26 06:33:05 +04:00
|
|
|
/* If I have a parent, then save his contact info so
|
|
|
|
* any messages we send can flow thru him.
|
|
|
|
*/
|
2013-03-28 01:09:41 +04:00
|
|
|
|
|
|
|
orte_parent_uri = NULL;
|
|
|
|
(void) mca_base_var_register ("orte", "orte", NULL, "parent_uri",
|
|
|
|
"URI for the parent if tree launch is enabled.",
|
|
|
|
MCA_BASE_VAR_TYPE_STRING, NULL, 0,
|
|
|
|
MCA_BASE_VAR_FLAG_INTERNAL,
|
|
|
|
OPAL_INFO_LVL_9,
|
|
|
|
MCA_BASE_VAR_SCOPE_CONSTANT,
|
|
|
|
&orte_parent_uri);
|
|
|
|
if (NULL != orte_parent_uri) {
|
2011-11-26 06:33:05 +04:00
|
|
|
orte_process_name_t parent;
|
|
|
|
|
|
|
|
/* set the contact info into the hash table */
|
As per the RFC, bring in the ORTE async progress code and the rewrite of OOB:
*** THIS RFC INCLUDES A MINOR CHANGE TO THE MPI-RTE INTERFACE ***
Note: during the course of this work, it was necessary to completely separate the MPI and RTE progress engines. There were multiple places in the MPI layer where ORTE_WAIT_FOR_COMPLETION was being used. A new OMPI_WAIT_FOR_COMPLETION macro was created (defined in ompi/mca/rte/rte.h) that simply cycles across opal_progress until the provided flag becomes false. Places where the MPI layer blocked waiting for RTE to complete an event have been modified to use this macro.
***************************************************************************************
I am reissuing this RFC because of the time that has passed since its original release. Since its initial release and review, I have debugged it further to ensure it fully supports tests like loop_spawn. It therefore seems ready for merge back to the trunk. Given its prior review, I have set the timeout for one week.
The code is in https://bitbucket.org/rhc/ompi-oob2
WHAT: Rewrite of ORTE OOB
WHY: Support asynchronous progress and a host of other features
WHEN: Wed, August 21
SYNOPSIS:
The current OOB has served us well, but a number of limitations have been identified over the years. Specifically:
* it is only progressed when called via opal_progress, which can lead to hangs or recursive calls into libevent (which is not supported by that code)
* we've had issues when multiple NICs are available as the code doesn't "shift" messages between transports - thus, all nodes had to be available via the same TCP interface.
* the OOB "unloads" incoming opal_buffer_t objects during the transmission, thus preventing use of OBJ_RETAIN in the code when repeatedly sending the same message to multiple recipients
* there is no failover mechanism across NICs - if the selected NIC (or its attached switch) fails, we are forced to abort
* only one transport (i.e., component) can be "active"
The revised OOB resolves these problems:
* async progress is used for all application processes, with the progress thread blocking in the event library
* each available TCP NIC is supported by its own TCP module. The ability to asynchronously progress each module independently is provided, but not enabled by default (a runtime MCA parameter turns it "on")
* multi-address TCP NICs (e.g., a NIC with both an IPv4 and IPv6 address, or with virtual interfaces) are supported - reachability is determined by comparing the contact info for a peer against all addresses within the range covered by the address/mask pairs for the NIC.
* a message that arrives on one TCP NIC is automatically shifted to whatever NIC that is connected to the next "hop" if that peer cannot be reached by the incoming NIC. If no TCP module will reach the peer, then the OOB attempts to send the message via all other available components - if none can reach the peer, then an "error" is reported back to the RML, which then calls the errmgr for instructions.
* opal_buffer_t now conforms to standard object rules re OBJ_RETAIN as we no longer "unload" the incoming object
* NIC failure is reported to the TCP component, which then tries to resend the message across any other available TCP NIC. If that doesn't work, then the message is given back to the OOB base to try using other components. If all that fails, then the error is reported to the RML, which reports to the errmgr for instructions
* obviously from the above, multiple OOB components (e.g., TCP and UD) can be active in parallel
* the matching code has been moved to the RML (and out of the OOB/TCP component) so it is independent of transport
* routing is done by the individual OOB modules (as opposed to the RML). Thus, both routed and non-routed transports can simultaneously be active
* all blocking send/recv APIs have been removed. Everything operates asynchronously.
KNOWN LIMITATIONS:
* although provision is made for component failover as described above, the code for doing so has not been fully implemented yet. At the moment, if all connections for a given peer fail, the errmgr is notified of a "lost connection", which by default results in termination of the job if it was a lifeline
* the IPv6 code is present and compiles, but is not complete. Since the current IPv6 support in the OOB doesn't work anyway, I don't consider this a blocker
* routing is performed at the individual module level, yet the active routed component is selected on a global basis. We probably should update that to reflect that different transports may need/choose to route in different ways
* obviously, not every error path has been tested nor necessarily covered
* determining abnormal termination is more challenging than in the old code as we now potentially have multiple ways of connecting to a process. Ideally, we would declare "connection failed" when *all* transports can no longer reach the process, but that requires some additional (possibly complex) code. For now, the code replicates the old behavior only somewhat modified - i.e., if a module sees its connection fail, it checks to see if it is a lifeline. If so, it notifies the errmgr that the lifeline is lost - otherwise, it notifies the errmgr that a non-lifeline connection was lost.
* reachability is determined solely on the basis of a shared subnet address/mask - more sophisticated algorithms (e.g., the one used in the tcp btl) are required to handle routing via gateways
* the RML needs to assign sequence numbers to each message on a per-peer basis. The receiving RML will then deliver messages in order, thus preventing out-of-order messaging in the case where messages travel across different transports or a message needs to be redirected/resent due to failure of a NIC
This commit was SVN r29058.
2013-08-22 20:37:40 +04:00
|
|
|
orte_rml.set_contact_info(orte_parent_uri);
|
|
|
|
ret = orte_rml_base_parse_uris(orte_parent_uri, &parent, NULL);
|
|
|
|
if (ORTE_SUCCESS != ret) {
|
2011-11-26 06:33:05 +04:00
|
|
|
ORTE_ERROR_LOG(ret);
|
2013-03-28 01:09:41 +04:00
|
|
|
free (orte_parent_uri);
|
|
|
|
orte_parent_uri = NULL;
|
2011-11-26 06:33:05 +04:00
|
|
|
goto DONE;
|
|
|
|
}
|
2013-03-28 01:09:41 +04:00
|
|
|
|
|
|
|
/* don't need this value anymore */
|
As per the RFC, bring in the ORTE async progress code and the rewrite of OOB:
*** THIS RFC INCLUDES A MINOR CHANGE TO THE MPI-RTE INTERFACE ***
Note: during the course of this work, it was necessary to completely separate the MPI and RTE progress engines. There were multiple places in the MPI layer where ORTE_WAIT_FOR_COMPLETION was being used. A new OMPI_WAIT_FOR_COMPLETION macro was created (defined in ompi/mca/rte/rte.h) that simply cycles across opal_progress until the provided flag becomes false. Places where the MPI layer blocked waiting for RTE to complete an event have been modified to use this macro.
***************************************************************************************
I am reissuing this RFC because of the time that has passed since its original release. Since its initial release and review, I have debugged it further to ensure it fully supports tests like loop_spawn. It therefore seems ready for merge back to the trunk. Given its prior review, I have set the timeout for one week.
The code is in https://bitbucket.org/rhc/ompi-oob2
WHAT: Rewrite of ORTE OOB
WHY: Support asynchronous progress and a host of other features
WHEN: Wed, August 21
SYNOPSIS:
The current OOB has served us well, but a number of limitations have been identified over the years. Specifically:
* it is only progressed when called via opal_progress, which can lead to hangs or recursive calls into libevent (which is not supported by that code)
* we've had issues when multiple NICs are available as the code doesn't "shift" messages between transports - thus, all nodes had to be available via the same TCP interface.
* the OOB "unloads" incoming opal_buffer_t objects during the transmission, thus preventing use of OBJ_RETAIN in the code when repeatedly sending the same message to multiple recipients
* there is no failover mechanism across NICs - if the selected NIC (or its attached switch) fails, we are forced to abort
* only one transport (i.e., component) can be "active"
The revised OOB resolves these problems:
* async progress is used for all application processes, with the progress thread blocking in the event library
* each available TCP NIC is supported by its own TCP module. The ability to asynchronously progress each module independently is provided, but not enabled by default (a runtime MCA parameter turns it "on")
* multi-address TCP NICs (e.g., a NIC with both an IPv4 and IPv6 address, or with virtual interfaces) are supported - reachability is determined by comparing the contact info for a peer against all addresses within the range covered by the address/mask pairs for the NIC.
* a message that arrives on one TCP NIC is automatically shifted to whatever NIC that is connected to the next "hop" if that peer cannot be reached by the incoming NIC. If no TCP module will reach the peer, then the OOB attempts to send the message via all other available components - if none can reach the peer, then an "error" is reported back to the RML, which then calls the errmgr for instructions.
* opal_buffer_t now conforms to standard object rules re OBJ_RETAIN as we no longer "unload" the incoming object
* NIC failure is reported to the TCP component, which then tries to resend the message across any other available TCP NIC. If that doesn't work, then the message is given back to the OOB base to try using other components. If all that fails, then the error is reported to the RML, which reports to the errmgr for instructions
* obviously from the above, multiple OOB components (e.g., TCP and UD) can be active in parallel
* the matching code has been moved to the RML (and out of the OOB/TCP component) so it is independent of transport
* routing is done by the individual OOB modules (as opposed to the RML). Thus, both routed and non-routed transports can simultaneously be active
* all blocking send/recv APIs have been removed. Everything operates asynchronously.
KNOWN LIMITATIONS:
* although provision is made for component failover as described above, the code for doing so has not been fully implemented yet. At the moment, if all connections for a given peer fail, the errmgr is notified of a "lost connection", which by default results in termination of the job if it was a lifeline
* the IPv6 code is present and compiles, but is not complete. Since the current IPv6 support in the OOB doesn't work anyway, I don't consider this a blocker
* routing is performed at the individual module level, yet the active routed component is selected on a global basis. We probably should update that to reflect that different transports may need/choose to route in different ways
* obviously, not every error path has been tested nor necessarily covered
* determining abnormal termination is more challenging than in the old code as we now potentially have multiple ways of connecting to a process. Ideally, we would declare "connection failed" when *all* transports can no longer reach the process, but that requires some additional (possibly complex) code. For now, the code replicates the old behavior only somewhat modified - i.e., if a module sees its connection fail, it checks to see if it is a lifeline. If so, it notifies the errmgr that the lifeline is lost - otherwise, it notifies the errmgr that a non-lifeline connection was lost.
* reachability is determined solely on the basis of a shared subnet address/mask - more sophisticated algorithms (e.g., the one used in the tcp btl) are required to handle routing via gateways
* the RML needs to assign sequence numbers to each message on a per-peer basis. The receiving RML will then deliver messages in order, thus preventing out-of-order messaging in the case where messages travel across different transports or a message needs to be redirected/resent due to failure of a NIC
This commit was SVN r29058.
2013-08-22 20:37:40 +04:00
|
|
|
free(orte_parent_uri);
|
2013-03-28 01:09:41 +04:00
|
|
|
orte_parent_uri = NULL;
|
|
|
|
|
2011-11-26 06:33:05 +04:00
|
|
|
/* tell the routed module that we have a path
|
|
|
|
* back to the HNP
|
|
|
|
*/
|
2016-10-23 21:36:05 +03:00
|
|
|
if (ORTE_SUCCESS != (ret = orte_routed.update_route(NULL, ORTE_PROC_MY_HNP, &parent))) {
|
2011-11-26 06:33:05 +04:00
|
|
|
ORTE_ERROR_LOG(ret);
|
|
|
|
goto DONE;
|
|
|
|
}
|
2011-12-15 19:29:53 +04:00
|
|
|
/* set the lifeline to point to our parent so that we
|
|
|
|
* can handle the situation if that lifeline goes away
|
|
|
|
*/
|
2016-10-23 21:36:05 +03:00
|
|
|
if (ORTE_SUCCESS != (ret = orte_routed.set_lifeline(NULL, &parent))) {
|
2011-12-15 19:29:53 +04:00
|
|
|
ORTE_ERROR_LOG(ret);
|
|
|
|
goto DONE;
|
|
|
|
}
|
2011-11-26 06:33:05 +04:00
|
|
|
}
|
|
|
|
|
2008-02-28 04:57:57 +03:00
|
|
|
/* if we are not the HNP...the only time we will be an HNP
|
|
|
|
* is if we are launched by a singleton to provide support
|
|
|
|
* for it
|
|
|
|
*/
|
2011-07-07 22:54:30 +04:00
|
|
|
if (!ORTE_PROC_IS_HNP) {
|
2007-07-12 23:53:18 +04:00
|
|
|
/* send the information to the orted report-back point - this function
|
2008-02-28 04:57:57 +03:00
|
|
|
* will process the data, but also counts the number of
|
2007-07-12 23:53:18 +04:00
|
|
|
* orteds that reported back so the launch procedure can continue.
|
|
|
|
* We need to do this at the last possible second as the HNP
|
|
|
|
* can turn right around and begin issuing orders to us
|
|
|
|
*/
|
2008-04-14 22:26:08 +04:00
|
|
|
|
2008-02-28 04:57:57 +03:00
|
|
|
buffer = OBJ_NEW(opal_buffer_t);
|
2012-06-15 14:15:07 +04:00
|
|
|
/* insert our name for rollup purposes */
|
|
|
|
if (ORTE_SUCCESS != (ret = opal_dss.pack(buffer, ORTE_PROC_MY_NAME, 1, ORTE_NAME))) {
|
|
|
|
ORTE_ERROR_LOG(ret);
|
|
|
|
OBJ_RELEASE(buffer);
|
|
|
|
goto DONE;
|
|
|
|
}
|
2009-01-30 21:31:43 +03:00
|
|
|
/* for now, always include our contact info, even if we are using
|
|
|
|
* static ports. Eventually, this will be removed
|
2008-04-30 23:49:53 +04:00
|
|
|
*/
|
2009-01-30 21:31:43 +03:00
|
|
|
rml_uri = orte_rml.get_contact_info();
|
|
|
|
if (ORTE_SUCCESS != (ret = opal_dss.pack(buffer, &rml_uri, 1, OPAL_STRING))) {
|
|
|
|
ORTE_ERROR_LOG(ret);
|
|
|
|
OBJ_RELEASE(buffer);
|
2009-02-25 06:10:21 +03:00
|
|
|
goto DONE;
|
2008-04-30 23:49:53 +04:00
|
|
|
}
|
Repair the tree spawn. The problem seems to come from the fact
that now the HNP send the messages using the routed component. In the case
of tree spawn, when a intermediary node spawn a child it doesn't know how
to forward a message to it, so when the node-map message is coming from
the HNP (as there is nothing yet in the contact/routing table) the message
is sent back the way it came. As a result the node-map message keeps jumping
between the HNP and the first level orteds.
The solution is to add a new option to the children orte_parent_uri, which
is only set when the orted is _not_ directly spawned by the HNP. When this
option is present on the argument list, the orted will add the parent to
its routing, and force the parent to update his routes (by sending the URI).
With this approach, the routing tree is build in same time as the processes
are spawned, and all messages from the HNP can be routed to the leaves.
However, this is far from an optimal solution. Right now, this so called tree
spawn, only spawn the children in a tree without doing anything about the
"connect back to the HNP" step. The HNP is flooded with reports from all the
orted. The total number of messages is higher than in the non tree startup
scheme, so we do not expect this approach to be scalable in the current
incarnation. A complete overhaul of the tree startup is required in order
improve the scalability. Stay tuned!
This commit was SVN r21504.
2009-06-24 02:10:25 +04:00
|
|
|
|
2011-11-26 06:33:05 +04:00
|
|
|
/* include our node name */
|
|
|
|
opal_dss.pack(buffer, &orte_process_info.nodename, 1, OPAL_STRING);
|
2013-01-18 09:00:05 +04:00
|
|
|
|
2012-11-16 08:04:29 +04:00
|
|
|
/* if requested, include any non-loopback aliases for this node */
|
|
|
|
if (orte_retain_aliases) {
|
|
|
|
char **aliases=NULL;
|
|
|
|
uint8_t naliases, ni;
|
2016-04-16 03:47:42 +03:00
|
|
|
char hostname[OPAL_MAXHOSTNAMELEN];
|
2013-08-01 04:32:10 +04:00
|
|
|
|
|
|
|
/* if we stripped the prefix or removed the fqdn,
|
|
|
|
* include full hostname as an alias
|
|
|
|
*/
|
2016-04-16 03:47:42 +03:00
|
|
|
gethostname(hostname, sizeof(hostname));
|
2013-08-01 04:32:10 +04:00
|
|
|
if (strlen(orte_process_info.nodename) < strlen(hostname)) {
|
2013-01-18 09:00:05 +04:00
|
|
|
opal_argv_append_nosize(&aliases, hostname);
|
|
|
|
}
|
2012-11-16 08:04:29 +04:00
|
|
|
opal_ifgetaliases(&aliases);
|
|
|
|
naliases = opal_argv_count(aliases);
|
|
|
|
if (ORTE_SUCCESS != (ret = opal_dss.pack(buffer, &naliases, 1, OPAL_UINT8))) {
|
|
|
|
ORTE_ERROR_LOG(ret);
|
|
|
|
OBJ_RELEASE(buffer);
|
2015-06-03 07:58:07 +03:00
|
|
|
opal_argv_free(aliases);
|
2012-11-16 08:04:29 +04:00
|
|
|
goto DONE;
|
|
|
|
}
|
|
|
|
for (ni=0; ni < naliases; ni++) {
|
|
|
|
if (ORTE_SUCCESS != (ret = opal_dss.pack(buffer, &aliases[ni], 1, OPAL_STRING))) {
|
|
|
|
ORTE_ERROR_LOG(ret);
|
|
|
|
OBJ_RELEASE(buffer);
|
2015-06-03 07:58:07 +03:00
|
|
|
opal_argv_free(aliases);
|
2012-11-16 08:04:29 +04:00
|
|
|
goto DONE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
opal_argv_free(aliases);
|
|
|
|
}
|
|
|
|
|
2015-09-05 02:54:40 +03:00
|
|
|
/* add the local topology, if different from the HNP's or user directed us to,
|
|
|
|
* but always if we are the first daemon to ensure we get a compute node */
|
|
|
|
if (1 == ORTE_PROC_MY_NAME->vpid || orte_hetero_nodes ||
|
|
|
|
0 != strcmp(orte_topo_signature, orted_globals.hnp_topo_sig)) {
|
|
|
|
tflag = 1;
|
|
|
|
if (ORTE_SUCCESS != (ret = opal_dss.pack(buffer, &tflag, 1, OPAL_UINT8))) {
|
|
|
|
ORTE_ERROR_LOG(ret);
|
****************************************************************
This change contains a non-mandatory modification
of the MPI-RTE interface. Anyone wishing to support
coprocessors such as the Xeon Phi may wish to add
the required definition and underlying support
****************************************************************
Add locality support for coprocessors such as the Intel Xeon Phi.
Detecting that we are on a coprocessor inside of a host node isn't straightforward. There are no good "hooks" provided for programmatically detecting that "we are on a coprocessor running its own OS", and the ORTE daemon just thinks it is on another node. However, in order to properly use the Phi's public interface for MPI transport, it is necessary that the daemon detect that it is colocated with procs on the host.
So we have to split the locality to separately record "on the same host" vs "on the same board". We already have the board-level locality flag, but not quite enough flexibility to handle this use-case. Thus, do the following:
1. add OPAL_PROC_ON_HOST flag to indicate we share a host, but not necessarily the same board
2. modify OPAL_PROC_ON_NODE to indicate we share both a host AND the same board. Note that we have to modify the OPAL_PROC_ON_LOCAL_NODE macro to explicitly check both conditions
3. add support in opal/mca/hwloc/base/hwloc_base_util.c for the host to check for coprocessors, and for daemons to check to see if they are on a coprocessor. The former is done via hwloc, but support for the latter is not yet provided by hwloc. So the code for detecting we are on a coprocessor currently is Xeon Phi specific - hopefully, we will find more generic methods in the future.
4. modify the orted and the hnp startup so they check for coprocessors and to see if they are on a coprocessor, and have the orteds pass that info back in their callback message. Automatically detect that coprocessors have been found and identify which coprocessors are on which hosts. Note that this algo isn't scalable at the moment - this will hopefully be improved over time.
5. modify the ompi proc locality detection function to look for coprocessor host info IF the OMPI_RTE_HOST_ID database key has been defined. RTE's that choose not to provide this support do not have to do anything - the associated code will simply be ignored.
6. include some cleanup of the hwloc open/close code so it conforms to how we did things in other frameworks (e.g., having a single "frame" file instead of open/close). Also, fix the locality flags - e.g., being on the same node means you must also be on the same cluster/cu, so ensure those flags are also set.
cmr:v1.7.4:reviewer=hjelmn
This commit was SVN r29435.
2013-10-14 20:52:58 +04:00
|
|
|
}
|
2015-09-05 02:54:40 +03:00
|
|
|
if (ORTE_SUCCESS != (ret = opal_dss.pack(buffer, &orte_topo_signature, 1, OPAL_STRING))) {
|
****************************************************************
This change contains a non-mandatory modification
of the MPI-RTE interface. Anyone wishing to support
coprocessors such as the Xeon Phi may wish to add
the required definition and underlying support
****************************************************************
Add locality support for coprocessors such as the Intel Xeon Phi.
Detecting that we are on a coprocessor inside of a host node isn't straightforward. There are no good "hooks" provided for programmatically detecting that "we are on a coprocessor running its own OS", and the ORTE daemon just thinks it is on another node. However, in order to properly use the Phi's public interface for MPI transport, it is necessary that the daemon detect that it is colocated with procs on the host.
So we have to split the locality to separately record "on the same host" vs "on the same board". We already have the board-level locality flag, but not quite enough flexibility to handle this use-case. Thus, do the following:
1. add OPAL_PROC_ON_HOST flag to indicate we share a host, but not necessarily the same board
2. modify OPAL_PROC_ON_NODE to indicate we share both a host AND the same board. Note that we have to modify the OPAL_PROC_ON_LOCAL_NODE macro to explicitly check both conditions
3. add support in opal/mca/hwloc/base/hwloc_base_util.c for the host to check for coprocessors, and for daemons to check to see if they are on a coprocessor. The former is done via hwloc, but support for the latter is not yet provided by hwloc. So the code for detecting we are on a coprocessor currently is Xeon Phi specific - hopefully, we will find more generic methods in the future.
4. modify the orted and the hnp startup so they check for coprocessors and to see if they are on a coprocessor, and have the orteds pass that info back in their callback message. Automatically detect that coprocessors have been found and identify which coprocessors are on which hosts. Note that this algo isn't scalable at the moment - this will hopefully be improved over time.
5. modify the ompi proc locality detection function to look for coprocessor host info IF the OMPI_RTE_HOST_ID database key has been defined. RTE's that choose not to provide this support do not have to do anything - the associated code will simply be ignored.
6. include some cleanup of the hwloc open/close code so it conforms to how we did things in other frameworks (e.g., having a single "frame" file instead of open/close). Also, fix the locality flags - e.g., being on the same node means you must also be on the same cluster/cu, so ensure those flags are also set.
cmr:v1.7.4:reviewer=hjelmn
This commit was SVN r29435.
2013-10-14 20:52:58 +04:00
|
|
|
ORTE_ERROR_LOG(ret);
|
|
|
|
}
|
2015-09-05 02:54:40 +03:00
|
|
|
if (ORTE_SUCCESS != (ret = opal_dss.pack(buffer, &opal_hwloc_topology, 1, OPAL_HWLOC_TOPO))) {
|
2011-11-26 06:33:05 +04:00
|
|
|
ORTE_ERROR_LOG(ret);
|
2009-12-01 02:11:25 +03:00
|
|
|
}
|
2015-09-05 02:54:40 +03:00
|
|
|
} else {
|
|
|
|
tflag = 0;
|
|
|
|
if (ORTE_SUCCESS != (ret = opal_dss.pack(buffer, &tflag, 1, OPAL_UINT8))) {
|
|
|
|
ORTE_ERROR_LOG(ret);
|
2014-12-09 02:33:45 +03:00
|
|
|
}
|
2011-11-26 06:33:05 +04:00
|
|
|
}
|
2015-09-05 02:54:40 +03:00
|
|
|
/* detect and add any coprocessors */
|
|
|
|
coprocessors = opal_hwloc_base_find_coprocessors(opal_hwloc_topology);
|
|
|
|
if (ORTE_SUCCESS != (ret = opal_dss.pack(buffer, &coprocessors, 1, OPAL_STRING))) {
|
|
|
|
ORTE_ERROR_LOG(ret);
|
|
|
|
}
|
|
|
|
/* see if I am on a coprocessor */
|
|
|
|
coprocessors = opal_hwloc_base_check_on_coprocessor();
|
|
|
|
if (ORTE_SUCCESS != (ret = opal_dss.pack(buffer, &coprocessors, 1, OPAL_STRING))) {
|
|
|
|
ORTE_ERROR_LOG(ret);
|
|
|
|
}
|
|
|
|
if (NULL!= coprocessors) {
|
|
|
|
free(coprocessors);
|
|
|
|
}
|
2011-09-11 23:02:24 +04:00
|
|
|
|
2013-04-08 04:42:57 +04:00
|
|
|
/* send to the HNP's callback - will be routed if routes are available */
|
2016-10-23 21:36:05 +03:00
|
|
|
if (0 > (ret = orte_rml.send_buffer_nb(orte_coll_conduit,
|
|
|
|
ORTE_PROC_MY_HNP, buffer,
|
As per the RFC, bring in the ORTE async progress code and the rewrite of OOB:
*** THIS RFC INCLUDES A MINOR CHANGE TO THE MPI-RTE INTERFACE ***
Note: during the course of this work, it was necessary to completely separate the MPI and RTE progress engines. There were multiple places in the MPI layer where ORTE_WAIT_FOR_COMPLETION was being used. A new OMPI_WAIT_FOR_COMPLETION macro was created (defined in ompi/mca/rte/rte.h) that simply cycles across opal_progress until the provided flag becomes false. Places where the MPI layer blocked waiting for RTE to complete an event have been modified to use this macro.
***************************************************************************************
I am reissuing this RFC because of the time that has passed since its original release. Since its initial release and review, I have debugged it further to ensure it fully supports tests like loop_spawn. It therefore seems ready for merge back to the trunk. Given its prior review, I have set the timeout for one week.
The code is in https://bitbucket.org/rhc/ompi-oob2
WHAT: Rewrite of ORTE OOB
WHY: Support asynchronous progress and a host of other features
WHEN: Wed, August 21
SYNOPSIS:
The current OOB has served us well, but a number of limitations have been identified over the years. Specifically:
* it is only progressed when called via opal_progress, which can lead to hangs or recursive calls into libevent (which is not supported by that code)
* we've had issues when multiple NICs are available as the code doesn't "shift" messages between transports - thus, all nodes had to be available via the same TCP interface.
* the OOB "unloads" incoming opal_buffer_t objects during the transmission, thus preventing use of OBJ_RETAIN in the code when repeatedly sending the same message to multiple recipients
* there is no failover mechanism across NICs - if the selected NIC (or its attached switch) fails, we are forced to abort
* only one transport (i.e., component) can be "active"
The revised OOB resolves these problems:
* async progress is used for all application processes, with the progress thread blocking in the event library
* each available TCP NIC is supported by its own TCP module. The ability to asynchronously progress each module independently is provided, but not enabled by default (a runtime MCA parameter turns it "on")
* multi-address TCP NICs (e.g., a NIC with both an IPv4 and IPv6 address, or with virtual interfaces) are supported - reachability is determined by comparing the contact info for a peer against all addresses within the range covered by the address/mask pairs for the NIC.
* a message that arrives on one TCP NIC is automatically shifted to whatever NIC that is connected to the next "hop" if that peer cannot be reached by the incoming NIC. If no TCP module will reach the peer, then the OOB attempts to send the message via all other available components - if none can reach the peer, then an "error" is reported back to the RML, which then calls the errmgr for instructions.
* opal_buffer_t now conforms to standard object rules re OBJ_RETAIN as we no longer "unload" the incoming object
* NIC failure is reported to the TCP component, which then tries to resend the message across any other available TCP NIC. If that doesn't work, then the message is given back to the OOB base to try using other components. If all that fails, then the error is reported to the RML, which reports to the errmgr for instructions
* obviously from the above, multiple OOB components (e.g., TCP and UD) can be active in parallel
* the matching code has been moved to the RML (and out of the OOB/TCP component) so it is independent of transport
* routing is done by the individual OOB modules (as opposed to the RML). Thus, both routed and non-routed transports can simultaneously be active
* all blocking send/recv APIs have been removed. Everything operates asynchronously.
KNOWN LIMITATIONS:
* although provision is made for component failover as described above, the code for doing so has not been fully implemented yet. At the moment, if all connections for a given peer fail, the errmgr is notified of a "lost connection", which by default results in termination of the job if it was a lifeline
* the IPv6 code is present and compiles, but is not complete. Since the current IPv6 support in the OOB doesn't work anyway, I don't consider this a blocker
* routing is performed at the individual module level, yet the active routed component is selected on a global basis. We probably should update that to reflect that different transports may need/choose to route in different ways
* obviously, not every error path has been tested nor necessarily covered
* determining abnormal termination is more challenging than in the old code as we now potentially have multiple ways of connecting to a process. Ideally, we would declare "connection failed" when *all* transports can no longer reach the process, but that requires some additional (possibly complex) code. For now, the code replicates the old behavior only somewhat modified - i.e., if a module sees its connection fail, it checks to see if it is a lifeline. If so, it notifies the errmgr that the lifeline is lost - otherwise, it notifies the errmgr that a non-lifeline connection was lost.
* reachability is determined solely on the basis of a shared subnet address/mask - more sophisticated algorithms (e.g., the one used in the tcp btl) are required to handle routing via gateways
* the RML needs to assign sequence numbers to each message on a per-peer basis. The receiving RML will then deliver messages in order, thus preventing out-of-order messaging in the case where messages travel across different transports or a message needs to be redirected/resent due to failure of a NIC
This commit was SVN r29058.
2013-08-22 20:37:40 +04:00
|
|
|
ORTE_RML_TAG_ORTED_CALLBACK,
|
2013-04-08 04:42:57 +04:00
|
|
|
orte_rml_send_callback, NULL))) {
|
|
|
|
ORTE_ERROR_LOG(ret);
|
|
|
|
OBJ_RELEASE(buffer);
|
|
|
|
goto DONE;
|
2012-06-15 14:15:07 +04:00
|
|
|
}
|
2007-07-12 23:53:18 +04:00
|
|
|
}
|
|
|
|
|
2012-08-23 01:41:50 +04:00
|
|
|
/* if we are tree-spawning, then we need to capture the MCA params
|
|
|
|
* from our cmd line so we can pass them along to the daemons we spawn -
|
|
|
|
* otherwise, only the first layer of daemons will ever see them
|
|
|
|
*/
|
|
|
|
if (orted_globals.tree_spawn) {
|
|
|
|
int j, k;
|
|
|
|
bool ignore;
|
|
|
|
char *no_keep[] = {
|
|
|
|
"orte_hnp_uri",
|
|
|
|
"orte_ess_jobid",
|
|
|
|
"orte_ess_vpid",
|
|
|
|
"orte_ess_num_procs",
|
|
|
|
"orte_parent_uri",
|
2014-10-16 23:58:56 +04:00
|
|
|
"mca_base_env_list",
|
2012-08-23 01:41:50 +04:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
for (i=0; i < argc; i++) {
|
2014-10-23 00:56:37 +04:00
|
|
|
if (0 == strcmp("-"OPAL_MCA_CMD_LINE_ID, argv[i]) ||
|
|
|
|
0 == strcmp("--"OPAL_MCA_CMD_LINE_ID, argv[i]) ) {
|
2012-08-23 01:41:50 +04:00
|
|
|
ignore = false;
|
|
|
|
/* see if this is something we cannot pass along */
|
|
|
|
for (k=0; NULL != no_keep[k]; k++) {
|
|
|
|
if (0 == strcmp(no_keep[k], argv[i+1])) {
|
|
|
|
ignore = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!ignore) {
|
|
|
|
/* see if this is already present so we at least can
|
|
|
|
* avoid growing the cmd line with duplicates
|
|
|
|
*/
|
|
|
|
if (NULL != orted_cmd_line) {
|
|
|
|
for (j=0; NULL != orted_cmd_line[j]; j++) {
|
|
|
|
if (0 == strcmp(argv[i+1], orted_cmd_line[j])) {
|
|
|
|
/* already here - ignore it */
|
|
|
|
ignore = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!ignore) {
|
|
|
|
opal_argv_append_nosize(&orted_cmd_line, argv[i]);
|
|
|
|
opal_argv_append_nosize(&orted_cmd_line, argv[i+1]);
|
|
|
|
opal_argv_append_nosize(&orted_cmd_line, argv[i+2]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
i += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-06-24 06:59:57 +03:00
|
|
|
|
2007-07-12 23:53:18 +04:00
|
|
|
if (orte_debug_daemons_flag) {
|
2009-03-06 00:50:47 +03:00
|
|
|
opal_output(0, "%s orted: up and running - waiting for commands!", ORTE_NAME_PRINT(ORTE_PROC_MY_NAME));
|
2007-07-12 23:53:18 +04:00
|
|
|
}
|
2014-01-31 03:50:14 +04:00
|
|
|
ret = ORTE_SUCCESS;
|
2007-07-12 23:53:18 +04:00
|
|
|
|
2012-04-06 18:23:13 +04:00
|
|
|
/* loop the event lib until an exit event is detected */
|
2013-01-15 03:06:42 +04:00
|
|
|
while (orte_event_base_active) {
|
|
|
|
opal_event_loop(orte_event_base, OPAL_EVLOOP_ONCE);
|
|
|
|
}
|
2007-07-12 23:53:18 +04:00
|
|
|
|
2012-05-19 03:37:40 +04:00
|
|
|
/* ensure all local procs are dead */
|
|
|
|
orte_odls.kill_local_procs(NULL);
|
|
|
|
|
2011-07-07 22:54:30 +04:00
|
|
|
DONE:
|
2012-04-06 18:23:13 +04:00
|
|
|
/* update the exit status, in case it wasn't done */
|
2014-01-31 03:50:14 +04:00
|
|
|
ORTE_UPDATE_EXIT_STATUS(ret);
|
2012-04-06 18:23:13 +04:00
|
|
|
|
|
|
|
/* cleanup and leave */
|
|
|
|
orte_finalize();
|
|
|
|
|
|
|
|
if (orte_debug_flag) {
|
|
|
|
fprintf(stderr, "exiting with status %d\n", orte_exit_status);
|
|
|
|
}
|
|
|
|
exit(orte_exit_status);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pipe_closed(int fd, short flags, void *arg)
|
|
|
|
{
|
|
|
|
opal_event_t *ev = (opal_event_t*)arg;
|
|
|
|
|
|
|
|
/* no error here - we just want to terminate */
|
|
|
|
opal_event_free(ev);
|
|
|
|
ORTE_ACTIVATE_JOB_STATE(NULL, ORTE_JOB_STATE_DAEMONS_TERMINATED);
|
2008-02-28 04:57:57 +03:00
|
|
|
}
|
2007-07-12 23:53:18 +04:00
|
|
|
|
2008-02-28 04:57:57 +03:00
|
|
|
static void shutdown_callback(int fd, short flags, void *arg)
|
|
|
|
{
|
2012-04-06 18:23:13 +04:00
|
|
|
orte_timer_t *tm = (orte_timer_t*)arg;
|
|
|
|
|
|
|
|
if (NULL != tm) {
|
|
|
|
/* release the timer */
|
|
|
|
OBJ_RELEASE(tm);
|
2007-07-12 23:53:18 +04:00
|
|
|
}
|
2015-06-24 06:59:57 +03:00
|
|
|
|
2008-08-06 15:31:06 +04:00
|
|
|
/* if we were ordered to abort, do so */
|
|
|
|
if (orted_globals.abort) {
|
2016-03-03 01:30:57 +03:00
|
|
|
opal_output(0, "%s is executing %s abort", ORTE_NAME_PRINT(ORTE_PROC_MY_NAME),
|
|
|
|
(orted_globals.test_suicide) ? "suicide" : "clean");
|
2008-08-06 15:31:06 +04:00
|
|
|
/* do -not- call finalize as this will send a message to the HNP
|
2010-07-18 01:03:27 +04:00
|
|
|
* indicating clean termination! Instead, just kill our
|
|
|
|
* local procs, forcibly cleanup the local session_dir tree, and abort
|
2008-08-06 15:31:06 +04:00
|
|
|
*/
|
2016-03-03 01:30:57 +03:00
|
|
|
if (orted_globals.test_suicide) {
|
|
|
|
exit(1);
|
|
|
|
}
|
2010-07-18 01:03:27 +04:00
|
|
|
orte_odls.kill_local_procs(NULL);
|
2008-08-06 15:31:06 +04:00
|
|
|
orte_session_dir_cleanup(ORTE_JOBID_WILDCARD);
|
|
|
|
abort();
|
|
|
|
}
|
2012-04-06 18:23:13 +04:00
|
|
|
opal_output(0, "%s is executing clean abnormal termination", ORTE_NAME_PRINT(ORTE_PROC_MY_NAME));
|
|
|
|
/* do -not- call finalize as this will send a message to the HNP
|
|
|
|
* indicating clean termination! Instead, just forcibly cleanup
|
|
|
|
* the local session_dir tree and exit
|
|
|
|
*/
|
|
|
|
orte_odls.kill_local_procs(NULL);
|
|
|
|
orte_session_dir_cleanup(ORTE_JOBID_WILDCARD);
|
|
|
|
exit(ORTE_ERROR_DEFAULT_EXIT_CODE);
|
2007-09-12 18:32:31 +04:00
|
|
|
}
|