1
1
openmpi/ompi/communicator/communicator.h
Jeff Squyres e7ecd56bd2 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-13 20:00:55 +00:00

447 строки
16 KiB
C

/* -*- Mode: C; c-basic-offset:4 ; -*- */
/*
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
* University Research and Technology
* Corporation. All rights reserved.
* Copyright (c) 2004-2007 The University of Tennessee and The University
* 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.
* Copyright (c) 2006 Cisco Systems, Inc. All rights reserved.
* Copyright (c) 2006-2007 University of Houston. All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#ifndef OMPI_COMMUNICATOR_H
#define OMPI_COMMUNICATOR_H
#include "opal/class/opal_object.h"
#include "ompi/errhandler/errhandler.h"
#include "opal/threads/mutex.h"
#include "mpi.h"
#include "ompi/group/group.h"
#include "ompi/mca/coll/coll.h"
#include "orte/mca/rml/rml_types.h"
#include "ompi/proc/proc.h"
BEGIN_C_DECLS
OMPI_DECLSPEC OBJ_CLASS_DECLARATION(ompi_communicator_t);
#define OMPI_COMM_INTER 0x00000001
#define OMPI_COMM_CART 0x00000002
#define OMPI_COMM_GRAPH 0x00000004
#define OMPI_COMM_NAMEISSET 0x00000008
#define OMPI_COMM_ISFREED 0x00000010
#define OMPI_COMM_INTRINSIC 0x00000020
#define OMPI_COMM_DYNAMIC 0x00000040
#define OMPI_COMM_INVALID 0x00000080
#define OMPI_COMM_PML_ADDED 0x00000100
/* some utility #defines */
#define OMPI_COMM_IS_INTER(comm) ((comm)->c_flags & OMPI_COMM_INTER)
#define OMPI_COMM_IS_INTRA(comm) (!((comm)->c_flags & OMPI_COMM_INTER))
#define OMPI_COMM_IS_CART(comm) ((comm)->c_flags & OMPI_COMM_CART)
#define OMPI_COMM_IS_GRAPH(comm) ((comm)->c_flags & OMPI_COMM_GRAPH)
#define OMPI_COMM_IS_INTRINSIC(comm) ((comm)->c_flags & OMPI_COMM_INTRINSIC)
#define OMPI_COMM_IS_FREED(comm) ((comm)->c_flags & OMPI_COMM_ISFREED)
#define OMPI_COMM_IS_DYNAMIC(comm) ((comm)->c_flags & OMPI_COMM_DYNAMIC)
#define OMPI_COMM_IS_INVALID(comm) ((comm)->c_flags & OMPI_COMM_INVALID)
#define OMPI_COMM_IS_PML_ADDED(comm) ((comm)->c_flags & OMPI_COMM_PML_ADDED)
#define OMPI_COMM_SET_DYNAMIC(comm) ((comm)->c_flags |= OMPI_COMM_DYNAMIC)
#define OMPI_COMM_SET_INVALID(comm) ((comm)->c_flags |= OMPI_COMM_INVALID)
#define OMPI_COMM_SET_PML_ADDED(comm) ((comm)->c_flags |= OMPI_COMM_PML_ADDED)
/* a set of special tags: */
/* to recognize an MPI_Comm_join in the comm_connect_accept routine. */
#define OMPI_COMM_ALLGATHER_TAG -31078
#define OMPI_COMM_BARRIER_TAG -31079
#define OMPI_COMM_ALLREDUCE_TAG -31080
/**
* Modes required for acquiring the new comm-id.
* The first (INTER/INTRA) indicates whether the
* input comm was an inter/intra-comm, the second
* whether the new communicator will be an inter/intra
* comm
*/
#define OMPI_COMM_CID_INTRA 0x00000020
#define OMPI_COMM_CID_INTER 0x00000040
#define OMPI_COMM_CID_INTRA_BRIDGE 0x00000080
#define OMPI_COMM_CID_INTRA_OOB 0x00000100
/**
* The block of CIDs allocated for MPI_COMM_WORLD
* and other communicators
*/
#define OMPI_COMM_BLOCK_WORLD 16
#define OMPI_COMM_BLOCK_OTHERS 8
OMPI_DECLSPEC extern opal_pointer_array_t ompi_mpi_communicators;
struct ompi_communicator_t {
opal_object_t c_base;
opal_mutex_t c_lock; /* mutex for name and potentially
attributes */
char c_name[MPI_MAX_OBJECT_NAME];
uint32_t c_contextid;
int c_my_rank;
uint32_t c_flags; /* flags, e.g. intercomm,
topology, etc. */
int c_id_available; /* the currently available Cid for allocation
to a child*/
int c_id_start_index; /* the starting index of the block of cids
allocated to tthis communicator*/
ompi_group_t *c_local_group;
ompi_group_t *c_remote_group;
struct ompi_communicator_t *c_local_comm; /* a duplicate of the local
communicator in case the comm
is an inter-comm*/
/* Attributes */
struct opal_hash_table_t *c_keyhash;
/**< inscribing cube dimension */
int c_cube_dim;
/* Hooks for topo module to hang things */
mca_base_component_t *c_topo_component;
const struct mca_topo_base_module_1_0_0_t* c_topo;
/**< structure of function pointers */
struct mca_topo_base_comm_1_0_0_t* c_topo_comm;
/**< structure containing basic information about the topology */
struct mca_topo_base_module_comm_t *c_topo_module;
/**< module specific data */
/* index in Fortran <-> C translation array */
int c_f_to_c_index;
#ifdef OMPI_WANT_PERUSE
/*
* Place holder for the PERUSE events.
*/
struct ompi_peruse_handle_t** c_peruse_handles;
#endif
/* Error handling. This field does not have the "c_" prefix so
that the OMPI_ERRHDL_* macros can find it, regardless of whether
it's a comm, window, or file. */
ompi_errhandler_t *error_handler;
ompi_errhandler_type_t errhandler_type;
/* Hooks for PML to hang things */
struct mca_pml_comm_t *c_pml_comm;
/* Collectives module interface and data */
mca_coll_base_comm_coll_t c_coll;
};
typedef struct ompi_communicator_t ompi_communicator_t;
OMPI_DECLSPEC extern ompi_communicator_t *ompi_mpi_comm_parent;
OMPI_DECLSPEC extern ompi_communicator_t ompi_mpi_comm_null;
/**
* Is this a valid communicator? This is a complicated question.
* :-)
*
* According to MPI-1:5.2.4 (p137):
*
* "The predefined constant MPI_COMM_NULL is the value used for
* invalid communicator handles."
*
* Hence, MPI_COMM_NULL is not valid. However, MPI-2:4.12.4 (p50)
* clearly states that the MPI_*_C2F and MPI_*_F2C functions
* should treat MPI_COMM_NULL as a valid communicator -- it
* distinctly differentiates between "invalid" handles and
* "MPI_*_NULL" handles. Some feel that the MPI-1 definition
* still holds for all other MPI functions; others feel that the
* MPi-2 definitions trump the MPI-1 definition. Regardless of
* who is right, there is ambiguity here. So we have left
* ompi_comm_invalid() as originally coded -- per the MPI-1
* definition, where MPI_COMM_NULL is an invalid communicator.
* The MPI_Comm_c2f() function, therefore, calls
* ompi_comm_invalid() but also explictily checks to see if the
* handle is MPI_COMM_NULL.
*/
static inline int ompi_comm_invalid(ompi_communicator_t* comm)
{
if ((NULL == comm) || (MPI_COMM_NULL == comm) ||
(OMPI_COMM_IS_FREED(comm)) || (OMPI_COMM_IS_INVALID(comm)) )
return true;
else
return false;
}
/**
* rank w/in the communicator
*/
static inline int ompi_comm_rank(ompi_communicator_t* comm)
{
return comm->c_my_rank;
}
/**
* size of the communicator
*/
static inline int ompi_comm_size(ompi_communicator_t* comm)
{
return comm->c_local_group->grp_proc_count;
}
/**
* size of the remote group for inter-communicators.
* returns zero for an intra-communicator
*/
static inline int ompi_comm_remote_size(ompi_communicator_t* comm)
{
return (comm->c_flags & OMPI_COMM_INTER ? comm->c_remote_group->grp_proc_count : 0);
}
/**
* Context ID for the communicator, suitable for passing to
* ompi_comm_lookup for getting the communicator back
*/
static inline uint32_t ompi_comm_get_cid(ompi_communicator_t* comm)
{
return comm->c_contextid;
}
/* return pointer to communicator associated with context id cid,
* No error checking is done*/
static inline ompi_communicator_t *ompi_comm_lookup(uint32_t cid)
{
/* array of pointers to communicators, indexed by context ID */
return (ompi_communicator_t*)opal_pointer_array_get_item(&ompi_mpi_communicators, cid);
}
static inline struct ompi_proc_t* ompi_comm_peer_lookup(ompi_communicator_t* comm, int peer_id)
{
#if OMPI_ENABLE_DEBUG
if(peer_id >= comm->c_remote_group->grp_proc_count) {
orte_output(0, "ompi_comm_lookup_peer: invalid peer index (%d)", peer_id);
return (struct ompi_proc_t *) NULL;
}
#endif
/*return comm->c_remote_group->grp_proc_pointers[peer_id];*/
return ompi_group_peer_lookup(comm->c_remote_group,peer_id);
}
static inline bool ompi_comm_peer_invalid(ompi_communicator_t* comm, int peer_id)
{
if(peer_id < 0 || peer_id >= comm->c_remote_group->grp_proc_count) {
return true;
}
return false;
}
/**
* Initialise MPI_COMM_WORLD and MPI_COMM_SELF
*/
int ompi_comm_init(void);
OMPI_DECLSPEC int ompi_comm_link_function(void);
/**
* extract the local group from a communicator
*/
OMPI_DECLSPEC int ompi_comm_group (ompi_communicator_t *comm, ompi_group_t **group);
/**
* create a communicator based on a group
*/
int ompi_comm_create (ompi_communicator_t* comm, ompi_group_t *group,
ompi_communicator_t** newcomm);
/**
* create a cartesian communicator
*/
int ompi_topo_create (ompi_communicator_t *old_comm,
int ndims_or_nnodes,
int *dims_or_index,
int *periods_or_edges,
bool reorder,
ompi_communicator_t **comm_cart,
int cart_or_graph);
/**
* split a communicator based on color and key. Parameters
* are identical to the MPI-counterpart of the function.
*
* @param comm: input communicator
* @param color
* @param key
*
* @
*/
OMPI_DECLSPEC int ompi_comm_split (ompi_communicator_t *comm, int color, int key,
ompi_communicator_t** newcomm, bool pass_on_topo);
/**
* dup a communicator. Parameter are identical to the MPI-counterpart
* of the function. It has been extracted, since we need to be able
* to dup a communicator internally as well.
*
* @param comm: input communicator
* sync_flag: 0 if processes need to synchronize in activate
* 1 if the do not (optimization to c_local_comm creation)
*
*/
OMPI_DECLSPEC int ompi_comm_dup (ompi_communicator_t *comm, ompi_communicator_t **newcomm,
int sync_flag);
/**
* compare two communicators.
*
* @param comm1,comm2: input communicators
*
*/
int ompi_comm_compare(ompi_communicator_t *comm1, ompi_communicator_t *comm2, int *result);
/**
* free a communicator
*/
OMPI_DECLSPEC int ompi_comm_free (ompi_communicator_t **comm);
/**
* allocate a new communicator structure
* @param local_group_size
* @param remote_group_size
*
* This routine allocates the structure, the according local and
* remote groups, the proc-arrays in the local and remote group.
* It furthermore sets the fortran index correctly,
* and sets all other elements to zero.
*/
ompi_communicator_t* ompi_comm_allocate (int local_group_size,
int remote_group_size);
/**
* allocate new communicator ID
* @param newcomm: pointer to the new communicator
* @param oldcomm: original comm
* @param bridgecomm: bridge comm for intercomm_create
* @param mode: combination of input
* OMPI_COMM_CID_INTRA: intra-comm
* OMPI_COMM_CID_INTER: inter-comm
* OMPI_COMM_CID_INTRA_BRIDGE: 2 intracomms connected by
* a bridge comm. local_leader
* and remote leader are in this
* case an int (rank in bridge-comm).
* OMPI_COMM_CID_INTRA_OOB: 2 intracomms, leaders talk
* through OOB. lleader and rleader
* are the required contact information.
* @param send_first: to avoid a potential deadlock for
* the OOB version.
* This routine has to be thread safe in the final version.
*/
OMPI_DECLSPEC int ompi_comm_nextcid ( ompi_communicator_t* newcomm,
ompi_communicator_t* oldcomm,
ompi_communicator_t* bridgecomm,
void* local_leader,
void* remote_leader,
int mode,
int send_first);
/**
* shut down the communicator infrastructure.
*/
int ompi_comm_finalize (void);
/**
* This is THE routine, where all the communicator stuff
* is really set.
*/
OMPI_DECLSPEC int ompi_comm_set ( ompi_communicator_t** newcomm,
ompi_communicator_t* oldcomm,
int local_size,
int *local_ranks,
int remote_size,
int *remote_ranks,
opal_hash_table_t *attr,
ompi_errhandler_t *errh,
mca_base_component_t *topocomponent,
ompi_group_t *local_group,
ompi_group_t *remote_group );
/**
* This is a short-hand routine used in intercomm_create.
* The routine makes sure, that all processes have afterwards
* a list of ompi_proc_t pointers for the remote group.
*/
struct ompi_proc_t **ompi_comm_get_rprocs ( ompi_communicator_t *local_comm,
ompi_communicator_t *bridge_comm,
int local_leader,
int remote_leader,
orte_rml_tag_t tag,
int rsize);
/**
* This routine verifies, whether local_group and remote group are overlapping
* in intercomm_create
*/
int ompi_comm_overlapping_groups (int size, struct ompi_proc_t ** lprocs,
int rsize, struct ompi_proc_t ** rprocs);
/**
* This is a routine determining whether the local or the
* remote group will be first in the new intra-comm.
* Just used from within MPI_Intercomm_merge.
*/
int ompi_comm_determine_first ( ompi_communicator_t *intercomm,
int high );
OMPI_DECLSPEC int ompi_comm_activate ( ompi_communicator_t* newcomm,
ompi_communicator_t* oldcomm,
ompi_communicator_t* bridgecomm,
void* local_leader,
void* remote_leader,
int mode,
int send_first,
int sync_flag );
/**
* a simple function to dump the structure
*/
int ompi_comm_dump ( ompi_communicator_t *comm );
/* setting name */
int ompi_comm_set_name (ompi_communicator_t *comm, char *name );
/*
* these are the init and finalize functions for the comm_reg
* stuff. These routines are necessary for handling multi-threading
* scenarious in the communicator_cid allocation
*/
void ompi_comm_reg_init(void);
void ompi_comm_reg_finalize(void);
/* global variable to save the number od dynamic communicators */
extern int ompi_comm_num_dyncomm;
END_C_DECLS
#endif /* OMPI_COMMUNICATOR_H */