2004-01-10 11:20:36 +03:00
|
|
|
/*
|
|
|
|
* $HEADER$
|
|
|
|
*/
|
2004-06-29 04:02:25 +04:00
|
|
|
/**
|
|
|
|
* @file
|
|
|
|
*
|
|
|
|
* Public interface for the MPI_Op handle.
|
|
|
|
*/
|
2004-01-10 11:20:36 +03:00
|
|
|
|
2004-06-07 19:33:53 +04:00
|
|
|
#ifndef OMPI_OP_H
|
|
|
|
#define OMPI_OP_H
|
2004-01-10 11:20:36 +03:00
|
|
|
|
2004-06-07 19:33:53 +04:00
|
|
|
#include "ompi_config.h"
|
2004-04-21 02:37:46 +04:00
|
|
|
|
2004-01-10 11:20:36 +03:00
|
|
|
#include "mpi.h"
|
2004-06-29 04:02:25 +04:00
|
|
|
#include "datatype/datatype.h"
|
2004-06-07 19:33:53 +04:00
|
|
|
#include "class/ompi_object.h"
|
|
|
|
#include "class/ompi_pointer_array.h"
|
2004-04-21 02:37:46 +04:00
|
|
|
|
|
|
|
|
2004-06-29 04:02:25 +04:00
|
|
|
/**
|
|
|
|
* Fortran handles; must be [manually set to be] equivalent to the
|
|
|
|
* values in mpif.h.
|
2004-04-21 02:37:46 +04:00
|
|
|
*/
|
2004-06-29 04:02:25 +04:00
|
|
|
enum {
|
|
|
|
OMPI_OP_FORTRAN_NULL = 0,
|
|
|
|
/**< Corresponds to Fortran MPI_OP_NULL */
|
|
|
|
OMPI_OP_FORTRAN_MAX,
|
|
|
|
/**< Corresponds to Fortran MPI_MAX */
|
|
|
|
OMPI_OP_FORTRAN_MIN,
|
|
|
|
/**< Corresponds to Fortran MPI_MIN */
|
|
|
|
OMPI_OP_FORTRAN_SUM,
|
|
|
|
/**< Corresponds to Fortran MPI_SUM */
|
|
|
|
OMPI_OP_FORTRAN_PROD,
|
|
|
|
/**< Corresponds to Fortran MPI_PROD */
|
|
|
|
OMPI_OP_FORTRAN_LAND,
|
|
|
|
/**< Corresponds to Fortran MPI_LAND */
|
|
|
|
OMPI_OP_FORTRAN_BAND,
|
|
|
|
/**< Corresponds to Fortran MPI_BAND */
|
|
|
|
OMPI_OP_FORTRAN_LOR,
|
|
|
|
/**< Corresponds to Fortran MPI_LOR */
|
|
|
|
OMPI_OP_FORTRAN_BOR,
|
|
|
|
/**< Corresponds to Fortran MPI_BOR */
|
|
|
|
OMPI_OP_FORTRAN_LXOR,
|
|
|
|
/**< Corresponds to Fortran MPI_LXOR */
|
|
|
|
OMPI_OP_FORTRAN_BXOR,
|
|
|
|
/**< Corresponds to Fortran MPI_BXOR */
|
|
|
|
OMPI_OP_FORTRAN_MAXLOC,
|
|
|
|
/**< Corresponds to Fortran MPI_MAXLOC */
|
|
|
|
OMPI_OP_FORTRAN_MINLOC,
|
|
|
|
/**< Corresponds to Fortran MPI_MINLOC */
|
|
|
|
OMPI_OP_FORTRAN_REPLACE,
|
|
|
|
/**< Corresponds to Fortran MPI_REPLACE */
|
|
|
|
|
|
|
|
OMPI_OP_FORTRAN_MAX_TYPE
|
|
|
|
/**< Maximum value */
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Corresponding to the types that we can reduce over. See
|
|
|
|
* MPI-1:4.9.2, p114-115.
|
|
|
|
*/
|
|
|
|
enum {
|
|
|
|
OMPI_OP_TYPE_INT,
|
|
|
|
/**< C integer: int */
|
|
|
|
OMPI_OP_TYPE_LONG,
|
|
|
|
/**< C integer: long */
|
|
|
|
OMPI_OP_TYPE_SHORT,
|
|
|
|
/**< C integer: short */
|
|
|
|
OMPI_OP_TYPE_UNSIGNED_SHORT,
|
|
|
|
/**< C integer: unsigned short */
|
|
|
|
OMPI_OP_TYPE_UNSIGNED,
|
|
|
|
/**< C integer: unsigned */
|
|
|
|
OMPI_OP_TYPE_UNSIGNED_LONG,
|
|
|
|
/**< C integer: unsigned long */
|
|
|
|
|
|
|
|
OMPI_OP_TYPE_INTEGER,
|
|
|
|
/**< Fortran integer */
|
|
|
|
|
|
|
|
OMPI_OP_TYPE_FLOAT,
|
|
|
|
/**< Floating point: float */
|
|
|
|
OMPI_OP_TYPE_DOUBLE,
|
|
|
|
/**< Floating point: double */
|
|
|
|
OMPI_OP_TYPE_REAL,
|
|
|
|
/**< Floating point: real */
|
|
|
|
OMPI_OP_TYPE_DOUBLE_PRECISION,
|
|
|
|
/**< Floating point: double precision */
|
|
|
|
OMPI_OP_TYPE_LONG_DOUBLE,
|
|
|
|
/**< Floating point: long double */
|
|
|
|
|
|
|
|
OMPI_OP_TYPE_LOGICAL,
|
|
|
|
/**< Logical */
|
|
|
|
|
|
|
|
OMPI_OP_TYPE_COMPLEX,
|
|
|
|
/**< Complex */
|
|
|
|
|
|
|
|
OMPI_OP_TYPE_BYTE,
|
|
|
|
/**< Byte */
|
|
|
|
|
|
|
|
OMPI_OP_TYPE_2REAL,
|
|
|
|
/**< 2 location Fortran: 2 real */
|
|
|
|
OMPI_OP_TYPE_2DOUBLE_PRECISION,
|
|
|
|
/**< 2 location Fortran: 2 double precision */
|
|
|
|
OMPI_OP_TYPE_2INTEGER,
|
|
|
|
/**< 2 location Fortran: 2 integer */
|
|
|
|
|
|
|
|
OMPI_OP_TYPE_FLOAT_INT,
|
|
|
|
/**< 2 location C: float int */
|
|
|
|
OMPI_OP_TYPE_DOUBLE_INT,
|
|
|
|
/**< 2 location C: double int */
|
|
|
|
OMPI_OP_TYPE_LONG_INT,
|
|
|
|
/**< 2 location C: long int */
|
|
|
|
OMPI_OP_TYPE_2INT,
|
|
|
|
/**< 2 location C: int int */
|
|
|
|
OMPI_OP_TYPE_SHORT_INT,
|
|
|
|
/**< 2 location C: short int */
|
|
|
|
OMPI_OP_TYPE_LONG_DOUBLE_INT,
|
|
|
|
/**< 2 location C: long double int */
|
|
|
|
|
|
|
|
OMPI_OP_TYPE_WCHAR,
|
|
|
|
/**< 2 location C: wchar_t */
|
|
|
|
|
|
|
|
OMPI_OP_TYPE_MAX
|
|
|
|
/**< Maximum type */
|
|
|
|
};
|
2004-04-21 02:37:46 +04:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
2004-06-29 04:02:25 +04:00
|
|
|
* Typedef for C op functions.
|
|
|
|
*
|
|
|
|
* We don't use MPI_User_function because this would create a
|
|
|
|
* confusing dependency loop between this file and mpi.h. So this is
|
|
|
|
* repeated code, but it's better this way (and this typedef will
|
|
|
|
* never change, so there's not much of a maintenance worry).
|
2004-04-21 02:37:46 +04:00
|
|
|
*/
|
2004-06-07 19:33:53 +04:00
|
|
|
typedef void (ompi_op_c_handler_fn_t)(void *, void *, int *, MPI_Datatype *);
|
2004-04-21 02:37:46 +04:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
2004-06-29 04:02:25 +04:00
|
|
|
* Typedef for fortran op functions.
|
2004-04-21 02:37:46 +04:00
|
|
|
*/
|
2004-06-07 19:33:53 +04:00
|
|
|
typedef void (ompi_op_fortran_handler_fn_t)(void *, void *, int *, MPI_Fint *);
|
2004-01-10 11:20:36 +03:00
|
|
|
|
2004-04-21 02:37:46 +04:00
|
|
|
|
2004-06-29 04:02:25 +04:00
|
|
|
/*
|
|
|
|
* Flags for MPI_Op
|
|
|
|
*/
|
|
|
|
#define OMPI_OP_FLAGS_INTRINSIC 0x0001
|
|
|
|
/**< Set if the MPI_Op is a built-in operation */
|
|
|
|
#define OMPI_OP_FLAGS_FORTRAN_FUNC 0x0002
|
|
|
|
/**< Set if the callback function is in Fortran */
|
|
|
|
#define OMPI_OP_FLAGS_ASSOC 0x0004
|
|
|
|
/**< Set if the callback function is associative */
|
|
|
|
#define OMPI_OP_FLAGS_COMMUTE 0x0008
|
|
|
|
/**< Set if the callback function is communative */
|
|
|
|
|
|
|
|
|
2004-04-21 02:37:46 +04:00
|
|
|
/**
|
|
|
|
* Back-end type of MPI_Op
|
|
|
|
*/
|
2004-06-07 19:33:53 +04:00
|
|
|
struct ompi_op_t {
|
|
|
|
ompi_object_t super;
|
2004-06-29 04:02:25 +04:00
|
|
|
/**< Parent class, for reference counting */
|
2004-04-21 02:37:46 +04:00
|
|
|
|
|
|
|
char o_name[MPI_MAX_OBJECT_NAME];
|
2004-06-29 04:02:25 +04:00
|
|
|
/**< Name, for debugging purposes */
|
2004-01-10 11:20:36 +03:00
|
|
|
|
2004-06-29 04:02:25 +04:00
|
|
|
uint32_t o_flags;
|
|
|
|
/**< Flags about the op */
|
2004-04-21 02:37:46 +04:00
|
|
|
|
|
|
|
union {
|
2004-06-07 19:33:53 +04:00
|
|
|
ompi_op_c_handler_fn_t *c_fn;
|
2004-06-29 04:02:25 +04:00
|
|
|
/**< C handler function pointer */
|
2004-06-07 19:33:53 +04:00
|
|
|
ompi_op_fortran_handler_fn_t *fort_fn;
|
2004-06-29 04:02:25 +04:00
|
|
|
/**< Fortran handler function pointer */
|
|
|
|
} o_func[OMPI_OP_TYPE_MAX];
|
|
|
|
/**< Array of function pointers, indexed on the operation type. For
|
|
|
|
non-intrinsice MPI_Op's, only the 0th element will be
|
|
|
|
meaningful. */
|
2004-04-21 02:37:46 +04:00
|
|
|
|
|
|
|
int o_f_to_c_index;
|
2004-06-29 04:02:25 +04:00
|
|
|
/**< Index in Fortran <-> C translation array */
|
2004-01-10 20:10:29 +03:00
|
|
|
};
|
2004-06-29 04:02:25 +04:00
|
|
|
/**
|
|
|
|
* Convenience typedef
|
|
|
|
*/
|
2004-06-07 19:33:53 +04:00
|
|
|
typedef struct ompi_op_t ompi_op_t;
|
2004-01-10 11:20:36 +03:00
|
|
|
|
2004-04-21 02:37:46 +04:00
|
|
|
|
|
|
|
/**
|
2004-06-29 04:02:25 +04:00
|
|
|
* Array to map ddt->id values to the corresponding position in the op
|
|
|
|
* function array.
|
|
|
|
*
|
|
|
|
* NOTE: It is possible to have an implementation without this map.
|
|
|
|
* There are basically 3 choices for implementing "how to find the
|
|
|
|
* right position in the op array based on the datatype":
|
|
|
|
*
|
|
|
|
* 1. Use the exact same ordering as ddt->id in the op map. This is
|
|
|
|
* nice in that it's always a direct lookup via one memory
|
|
|
|
* de-reference. But it makes a sparse op array, and it's at least
|
|
|
|
* somewhat wasteful. It also chains the ddt and op implementations
|
|
|
|
* together. If the ddt ever changes its ordering, op is screwed. It
|
|
|
|
* seemed safer from a maintenance point of view not to do it that
|
|
|
|
* way.
|
|
|
|
*
|
|
|
|
* 2. Re-arrange the ddt ID values so that all the reducable types are
|
|
|
|
* at the beginning. This means that we can have a dense array here
|
|
|
|
* in op, but then we have the same problem as number one -- and so
|
|
|
|
* this didn't seem like a good idea from a maintenance point of view.
|
|
|
|
*
|
|
|
|
* 3. Create a mapping between the ddt->id values and the position in
|
|
|
|
* the op array. This allows a nice dense op array, and if we make
|
|
|
|
* the map based on symbolic values, then if ddt ever changes its
|
|
|
|
* ordering, it won't matter to op. This seemed like the safest thing
|
|
|
|
* to do from a maintenance perspective, and since it only costs one
|
|
|
|
* extra lookup, and that lookup is way cheaper than the function call
|
|
|
|
* to invoke the reduction operation, it seemed like the best idea.
|
|
|
|
*/
|
|
|
|
extern int ompi_op_ddt_map[DT_MAX_PREDEFINED];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Global variable for MPI_OP_NULL
|
2004-04-21 02:37:46 +04:00
|
|
|
*/
|
2004-06-07 19:33:53 +04:00
|
|
|
extern ompi_op_t ompi_mpi_op_null;
|
2004-04-21 02:37:46 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Global variable for MPI_MAX
|
|
|
|
*/
|
2004-06-07 19:33:53 +04:00
|
|
|
extern ompi_op_t ompi_mpi_op_max;
|
2004-04-21 02:37:46 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Global variable for MPI_MIN
|
|
|
|
*/
|
2004-06-07 19:33:53 +04:00
|
|
|
extern ompi_op_t ompi_mpi_op_min;
|
2004-04-21 02:37:46 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Global variable for MPI_SUM
|
|
|
|
*/
|
2004-06-07 19:33:53 +04:00
|
|
|
extern ompi_op_t ompi_mpi_op_sum;
|
2004-04-21 02:37:46 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Global variable for MPI_PROD
|
|
|
|
*/
|
2004-06-07 19:33:53 +04:00
|
|
|
extern ompi_op_t ompi_mpi_op_prod;
|
2004-04-21 02:37:46 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Global variable for MPI_LAND
|
|
|
|
*/
|
2004-06-07 19:33:53 +04:00
|
|
|
extern ompi_op_t ompi_mpi_op_land;
|
2004-04-21 02:37:46 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Global variable for MPI_BAND
|
|
|
|
*/
|
2004-06-07 19:33:53 +04:00
|
|
|
extern ompi_op_t ompi_mpi_op_band;
|
2004-04-21 02:37:46 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Global variable for MPI_LOR
|
|
|
|
*/
|
2004-06-07 19:33:53 +04:00
|
|
|
extern ompi_op_t ompi_mpi_op_lor;
|
2004-04-21 02:37:46 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Global variable for MPI_BOR
|
|
|
|
*/
|
2004-06-07 19:33:53 +04:00
|
|
|
extern ompi_op_t ompi_mpi_op_bor;
|
2004-04-21 02:37:46 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Global variable for MPI_LXOR
|
|
|
|
*/
|
2004-06-07 19:33:53 +04:00
|
|
|
extern ompi_op_t ompi_mpi_op_lxor;
|
2004-04-21 02:37:46 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Global variable for MPI_BXOR
|
|
|
|
*/
|
2004-06-07 19:33:53 +04:00
|
|
|
extern ompi_op_t ompi_mpi_op_bxor;
|
2004-04-21 02:37:46 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Global variable for MPI_MAXLOC
|
|
|
|
*/
|
2004-06-07 19:33:53 +04:00
|
|
|
extern ompi_op_t ompi_mpi_op_maxloc;
|
2004-04-21 02:37:46 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Global variable for MPI_MINLOC
|
|
|
|
*/
|
2004-06-07 19:33:53 +04:00
|
|
|
extern ompi_op_t ompi_mpi_op_minloc;
|
2004-04-21 02:37:46 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Global variable for MPI_REPLACE
|
|
|
|
*/
|
2004-06-07 19:33:53 +04:00
|
|
|
extern ompi_op_t ompi_mpi_op_replace;
|
2004-04-21 02:37:46 +04:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Table for Fortran <-> C op handle conversion
|
|
|
|
*/
|
2004-06-07 19:33:53 +04:00
|
|
|
extern ompi_pointer_array_t *ompi_op_f_to_c_table;
|
2004-04-21 02:37:46 +04:00
|
|
|
|
|
|
|
|
|
|
|
#if defined(c_plusplus) || defined(__cplusplus)
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize the op interface.
|
|
|
|
*
|
2004-06-07 19:33:53 +04:00
|
|
|
* @returns OMPI_SUCCESS Upon success
|
|
|
|
* @returns OMPI_ERROR Otherwise
|
2004-04-21 02:37:46 +04:00
|
|
|
*
|
2004-06-07 19:33:53 +04:00
|
|
|
* Invoked from ompi_mpi_init(); sets up the op interface, creates
|
2004-04-21 02:37:46 +04:00
|
|
|
* the predefined MPI operations, and creates the corresopnding F2C
|
|
|
|
* translation table.
|
|
|
|
*/
|
2004-06-07 19:33:53 +04:00
|
|
|
int ompi_op_init(void);
|
2004-04-21 02:37:46 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Finalize the op interface.
|
|
|
|
*
|
2004-06-07 19:33:53 +04:00
|
|
|
* @returns OMPI_SUCCESS Always
|
2004-04-21 02:37:46 +04:00
|
|
|
*
|
2004-06-07 19:33:53 +04:00
|
|
|
* Invokes from ompi_mpi_finalize(); tears down the op interface, and
|
2004-04-21 02:37:46 +04:00
|
|
|
* destroys the F2C translation table.
|
|
|
|
*/
|
2004-06-07 19:33:53 +04:00
|
|
|
int ompi_op_finalize(void);
|
2004-04-21 02:37:46 +04:00
|
|
|
|
|
|
|
/**
|
2004-06-07 19:33:53 +04:00
|
|
|
* Create a ompi_op_t
|
2004-04-21 02:37:46 +04:00
|
|
|
*
|
2004-04-21 03:11:11 +04:00
|
|
|
* @param commute Boolean indicating whether the operation is
|
|
|
|
* communative or not
|
|
|
|
* @param func Function pointer of the error handler
|
|
|
|
*
|
2004-06-07 19:33:53 +04:00
|
|
|
* @returns op Pointer to the ompi_op_t that will be
|
2004-04-21 03:11:11 +04:00
|
|
|
* created and returned
|
|
|
|
*
|
|
|
|
* This function is called as the back-end of all the MPI_OP_CREATE
|
2004-06-07 19:33:53 +04:00
|
|
|
* functions. It creates a new ompi_op_t object, initializes it to
|
2004-04-21 03:11:11 +04:00
|
|
|
* the correct object type, and sets the callback function on it.
|
|
|
|
*
|
|
|
|
* The type of the function pointer is (arbitrarily) the fortran
|
|
|
|
* function handler type. Since this function has to accept 2
|
|
|
|
* different function pointer types (lest we have 2 different
|
|
|
|
* functions to create errhandlers), the fortran one was picked
|
|
|
|
* arbitrarily. Note that (void*) is not sufficient because at
|
|
|
|
* least theoretically, a sizeof(void*) may not necessarily be the
|
|
|
|
* same as sizeof(void(*)).
|
|
|
|
*
|
|
|
|
* NOTE: It *always* sets the "fortran" flag to false. The Fortran
|
|
|
|
* wrapper for MPI_OP_CREATE is expected to reset this flag to true
|
|
|
|
* manually.
|
2004-04-21 02:37:46 +04:00
|
|
|
*/
|
2004-06-07 19:33:53 +04:00
|
|
|
ompi_op_t *ompi_op_create(bool commute, ompi_op_fortran_handler_fn_t *func);
|
2004-04-21 03:11:11 +04:00
|
|
|
|
2004-04-21 02:37:46 +04:00
|
|
|
#if defined(c_plusplus) || defined(__cplusplus)
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2004-04-21 03:11:11 +04:00
|
|
|
/**
|
|
|
|
* Check to see if an op is intrinsic.
|
|
|
|
*
|
|
|
|
* @param op The op to check
|
|
|
|
*
|
|
|
|
* @returns true If the op is intrinsic
|
|
|
|
* @returns false If the op is not intrinsic
|
|
|
|
*
|
|
|
|
* Self-explanitory. This is needed in a few top-level MPI functions;
|
|
|
|
* this function is provided to hide the internal structure field
|
|
|
|
* names.
|
|
|
|
*/
|
2004-06-07 19:33:53 +04:00
|
|
|
static inline bool ompi_op_is_intrinsic(ompi_op_t *op)
|
2004-04-21 03:11:11 +04:00
|
|
|
{
|
2004-06-29 04:02:25 +04:00
|
|
|
return (bool) (0 != (op->o_flags & OMPI_OP_FLAGS_INTRINSIC));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check to see if an op's callback function is fortran.
|
|
|
|
*
|
|
|
|
* @param op The op to check
|
|
|
|
*
|
|
|
|
* @returns true If the callback function is in fortran
|
|
|
|
* @returns false If the callback function is not in fortran
|
|
|
|
*
|
|
|
|
* Self-explanitory. This is needed in a few top-level MPI functions;
|
|
|
|
* this function is provided to hide the internal structure field
|
|
|
|
* names.
|
|
|
|
*/
|
|
|
|
static inline bool ompi_op_is_fortran(ompi_op_t *op)
|
|
|
|
{
|
|
|
|
return (bool) (0 != (op->o_flags & OMPI_OP_FLAGS_FORTRAN_FUNC));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check to see if an op is communative or not
|
|
|
|
*
|
|
|
|
* @param op The op to check
|
|
|
|
*
|
|
|
|
* @returns true If the op is communative
|
|
|
|
* @returns false If the op is not communative
|
|
|
|
*
|
|
|
|
* Self-explanitory. This is needed in a few top-level MPI functions;
|
|
|
|
* this function is provided to hide the internal structure field
|
|
|
|
* names.
|
|
|
|
*/
|
|
|
|
static inline bool ompi_op_is_commute(ompi_op_t *op)
|
|
|
|
{
|
|
|
|
return (bool) (0 != (op->o_flags & OMPI_OP_FLAGS_COMMUTE));
|
2004-04-21 03:11:11 +04:00
|
|
|
}
|
|
|
|
|
2004-06-07 19:33:53 +04:00
|
|
|
#endif /* OMPI_OP_H */
|