2004-01-10 11:20:36 +03:00
/*
2005-11-05 22:57:48 +03:00
* Copyright ( c ) 2004 - 2005 The Trustees of Indiana University and Indiana
* University Research and Technology
* Corporation . All rights reserved .
* Copyright ( c ) 2004 - 2005 The University of Tennessee and The University
* of Tennessee Research Foundation . All rights
* reserved .
2004-11-28 23:09:25 +03:00
* Copyright ( c ) 2004 - 2005 High Performance Computing Center Stuttgart ,
* University of Stuttgart . All rights reserved .
2005-03-24 15:43:37 +03:00
* Copyright ( c ) 2004 - 2005 The Regents of the University of California .
* All rights reserved .
2004-11-22 04:38:40 +03:00
* $ COPYRIGHT $
*
* Additional copyrights may follow
*
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"
2005-07-03 20:06:07 +04:00
# include "opal/class/opal_object.h"
2005-03-25 23:43:19 +03:00
# include "mpi/f77/fint_2_int.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 */
2005-11-01 06:28:59 +03:00
OMPI_OP_TYPE_LONG_LONG ,
/**< C integer: long long (optional) */
OMPI_OP_TYPE_LONG_LONG_INT ,
/**< C integer: long long int (optional) */
OMPI_OP_TYPE_UNSIGNED_LONG_LONG ,
/**< C integer: unsigned long long (optional) */
2004-06-29 04:02:25 +04:00
OMPI_OP_TYPE_INTEGER ,
/**< Fortran integer */
2005-05-20 03:56:02 +04:00
OMPI_OP_TYPE_INTEGER1 ,
/**< Fortran integer*1 */
OMPI_OP_TYPE_INTEGER2 ,
/**< Fortran integer*2 */
OMPI_OP_TYPE_INTEGER4 ,
/**< Fortran integer*4 */
OMPI_OP_TYPE_INTEGER8 ,
/**< Fortran integer*8 */
OMPI_OP_TYPE_INTEGER16 ,
/**< Fortran integer*16 */
2004-06-29 04:02:25 +04:00
OMPI_OP_TYPE_FLOAT ,
/**< Floating point: float */
OMPI_OP_TYPE_DOUBLE ,
/**< Floating point: double */
OMPI_OP_TYPE_REAL ,
/**< Floating point: real */
2005-05-20 03:56:02 +04:00
OMPI_OP_TYPE_REAL4 ,
/**< Floating point: real*4 */
OMPI_OP_TYPE_REAL8 ,
/**< Floating point: real*8 */
OMPI_OP_TYPE_REAL16 ,
/**< Floating point: real*16 */
2004-06-29 04:02:25 +04:00
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 */
2005-10-12 06:31:28 +04:00
OMPI_OP_TYPE_DOUBLE_COMPLEX ,
/**< Double complex */
2005-05-20 03:56:02 +04:00
OMPI_OP_TYPE_COMPLEX8 ,
/**< Complex8 */
OMPI_OP_TYPE_COMPLEX16 ,
/**< Complex16 */
OMPI_OP_TYPE_COMPLEX32 ,
/**< Complex32 */
2004-06-29 04:02:25 +04:00
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
*/
2005-03-25 23:43:19 +03:00
typedef void ( ompi_op_fortran_handler_fn_t ) ( void * , void * ,
MPI_Fint * , MPI_Fint * ) ;
2004-01-10 11:20:36 +03:00
2004-04-21 02:37:46 +04:00
2005-12-23 19:49:09 +03:00
/**
* Typedef for C + + op functions intercept .
*
* See the lengthy explanation for why this is different than the C
* intercept in ompi / mpi / cxx / intercepts . cc in the
* ompi_mpi_cxx_op_intercept ( ) function .
*/
typedef void ( ompi_op_cxx_handler_fn_t ) ( void * , void * , int * ,
MPI_Datatype * , MPI_User_function * op ) ;
2004-06-29 04:02:25 +04:00
/*
* Flags for MPI_Op
*/
2005-09-08 13:47:27 +04:00
/** Set if the MPI_Op is a built-in operation */
2004-06-29 04:02:25 +04:00
# define OMPI_OP_FLAGS_INTRINSIC 0x0001
2005-09-08 13:47:27 +04:00
/** Set if the callback function is in Fortran */
2004-06-29 04:02:25 +04:00
# define OMPI_OP_FLAGS_FORTRAN_FUNC 0x0002
2005-12-23 19:49:09 +03:00
/** Set if the callback function is in C++ */
# define OMPI_OP_FLAGS_CXX_FUNC 0x0004
2005-09-08 13:47:27 +04:00
/** Set if the callback function is associative (MAX and SUM will both
have ASSOC set - - in fact , it will only * not * be set if we
implement some extensions to MPI , because MPI says that all
MPI_Op ' s should be associative , so this flag is really here for
future expansion ) */
2005-12-23 19:49:09 +03:00
# define OMPI_OP_FLAGS_ASSOC 0x0008
2005-09-08 13:47:27 +04:00
/** Set if the callback function is associative for floating point
operands ( e . g . , MPI_SUM will have ASSOC set , b ut will * not * have
FLOAT_ASSOC set ) */
2005-12-23 19:49:09 +03:00
# define OMPI_OP_FLAGS_FLOAT_ASSOC 0x0010
2005-09-08 13:47:27 +04:00
/** Set if the callback function is communative */
2005-12-23 19:49:09 +03:00
# define OMPI_OP_FLAGS_COMMUTE 0x0020
2004-06-29 04:02:25 +04:00
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 {
2005-07-03 20:06:07 +04:00
opal_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 {
2005-12-23 19:49:09 +03:00
/** C handler function pointer */
ompi_op_c_handler_fn_t * c_fn ;
/** Fortran handler function pointer */
ompi_op_fortran_handler_fn_t * fort_fn ;
/** C++ intercept function pointer -- see lengthy comment in
ompi / mpi / cxx / intercepts . cc : : ompi_mpi_cxx_op_intercept ( ) for
an explanation */
ompi_op_cxx_handler_fn_t * cxx_intercept_fn ;
2004-06-29 04:02:25 +04:00
} o_func [ OMPI_OP_TYPE_MAX ] ;
/**< Array of function pointers, indexed on the operation type. For
non - intrinsice MPI_Op ' s , only the 0 th element will be
meaningful . */
2004-04-21 02:37:46 +04:00
2005-12-23 19:49:09 +03:00
/** Index in Fortran <-> C translation array */
2004-04-21 02:37:46 +04:00
int o_f_to_c_index ;
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 ;
2005-10-25 00:31:14 +04:00
OBJ_CLASS_DECLARATION ( ompi_op_t ) ;
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 .
*/
2004-10-22 20:06:05 +04:00
OMPI_DECLSPEC extern int ompi_op_ddt_map [ DT_MAX_PREDEFINED ] ;
2004-06-29 04:02:25 +04:00
/**
* Global variable for MPI_OP_NULL
2004-04-21 02:37:46 +04:00
*/
2004-10-22 20:06:05 +04:00
OMPI_DECLSPEC extern ompi_op_t ompi_mpi_op_null ;
2004-04-21 02:37:46 +04:00
/**
* Global variable for MPI_MAX
*/
2004-10-22 20:06:05 +04:00
OMPI_DECLSPEC extern ompi_op_t ompi_mpi_op_max ;
2004-04-21 02:37:46 +04:00
/**
* Global variable for MPI_MIN
*/
2004-10-22 20:06:05 +04:00
OMPI_DECLSPEC extern ompi_op_t ompi_mpi_op_min ;
2004-04-21 02:37:46 +04:00
/**
* Global variable for MPI_SUM
*/
2004-10-22 20:06:05 +04:00
OMPI_DECLSPEC extern ompi_op_t ompi_mpi_op_sum ;
2004-04-21 02:37:46 +04:00
/**
* Global variable for MPI_PROD
*/
2004-10-22 20:06:05 +04:00
OMPI_DECLSPEC extern ompi_op_t ompi_mpi_op_prod ;
2004-04-21 02:37:46 +04:00
/**
* Global variable for MPI_LAND
*/
2004-10-22 20:06:05 +04:00
OMPI_DECLSPEC extern ompi_op_t ompi_mpi_op_land ;
2004-04-21 02:37:46 +04:00
/**
* Global variable for MPI_BAND
*/
2004-10-22 20:06:05 +04:00
OMPI_DECLSPEC extern ompi_op_t ompi_mpi_op_band ;
2004-04-21 02:37:46 +04:00
/**
* Global variable for MPI_LOR
*/
2004-10-22 20:06:05 +04:00
OMPI_DECLSPEC extern ompi_op_t ompi_mpi_op_lor ;
2004-04-21 02:37:46 +04:00
/**
* Global variable for MPI_BOR
*/
2004-10-22 20:06:05 +04:00
OMPI_DECLSPEC extern ompi_op_t ompi_mpi_op_bor ;
2004-04-21 02:37:46 +04:00
/**
* Global variable for MPI_LXOR
*/
2004-10-22 20:06:05 +04:00
OMPI_DECLSPEC extern ompi_op_t ompi_mpi_op_lxor ;
2004-04-21 02:37:46 +04:00
/**
* Global variable for MPI_BXOR
*/
2004-10-22 20:06:05 +04:00
OMPI_DECLSPEC extern ompi_op_t ompi_mpi_op_bxor ;
2004-04-21 02:37:46 +04:00
/**
* Global variable for MPI_MAXLOC
*/
2004-10-22 20:06:05 +04:00
OMPI_DECLSPEC extern ompi_op_t ompi_mpi_op_maxloc ;
2004-04-21 02:37:46 +04:00
/**
* Global variable for MPI_MINLOC
*/
2004-10-22 20:06:05 +04:00
OMPI_DECLSPEC extern ompi_op_t ompi_mpi_op_minloc ;
2004-04-21 02:37:46 +04:00
/**
* Global variable for MPI_REPLACE
*/
2004-10-22 20:06:05 +04:00
OMPI_DECLSPEC extern ompi_op_t ompi_mpi_op_replace ;
2004-04-21 02:37:46 +04:00
/**
* Table for Fortran < - > C op handle conversion
*/
2005-12-09 08:14:18 +03:00
OMPI_DECLSPEC extern struct 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
2005-12-23 19:49:09 +03:00
/**
* Mark an MPI_Op as holding a C + + callback function , and cache
* that function in the MPI_Op . See a lenghty comment in
* ompi / mpi / cxx / op . c : : ompi_mpi_cxx_op_intercept ( ) for a full
* expalantion .
*/
void ompi_op_set_cxx_callback ( ompi_op_t * op , MPI_User_function * fn ) ;
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 ) ) ;
}
/**
2004-06-29 17:04:38 +04:00
* Check to see if an op is communative or not
2004-06-29 04:02:25 +04:00
*
* @ param op The op to check
*
2004-06-29 17:04:38 +04:00
* @ returns true If the op is communative
* @ returns false If the op is not communative
2004-06-29 04:02:25 +04:00
*
* 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-29 17:04:38 +04:00
static inline bool ompi_op_is_commute ( ompi_op_t * op )
2004-06-29 04:02:25 +04:00
{
2004-06-29 17:04:38 +04:00
return ( bool ) ( 0 ! = ( op - > o_flags & OMPI_OP_FLAGS_COMMUTE ) ) ;
2004-06-29 04:02:25 +04:00
}
2005-09-08 13:47:27 +04:00
/**
* Check to see if an op is floating point associative or not
*
* @ param op The op to check
*
* @ returns true If the op is floating point associative
* @ returns false If the op is not floating point associative
*
* 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_float_assoc ( ompi_op_t * op )
{
return ( bool ) ( 0 ! = ( op - > o_flags & OMPI_OP_FLAGS_FLOAT_ASSOC ) ) ;
}
2004-06-29 17:04:38 +04:00
2005-10-28 20:47:32 +04:00
/**
* Check to see if an op is valid on a given datatype
*
* @ param op The op to check
* @ param ddt The datatype to check
*
* @ returns true If the op is valid on that datatype
* @ returns false If the op is not valid on that datatype
*
* 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_valid ( ompi_op_t * op , ompi_datatype_t * ddt ,
char * * msg , const char * func )
{
/* Check:
- non - intrinsic ddt ' s cannot be invoked on intrinsic op ' s
- if intrinsic ddt invoked on intrinsic op :
- ensure the datatype is defined in the op map
- ensure we have a function pointer for that combination
*/
if ( ompi_op_is_intrinsic ( op ) ) {
2006-02-06 21:01:45 +03:00
if ( ompi_ddt_is_predefined ( ddt ) ) {
2005-10-28 20:47:32 +04:00
/* Intrinsic ddt on intrinsic op */
if ( ( - 1 = = ompi_op_ddt_map [ ddt - > id ] | |
( 0 ! = ( op - > o_flags & OMPI_OP_FLAGS_FORTRAN_FUNC ) & &
NULL = = op - > o_func [ ompi_op_ddt_map [ ddt - > id ] ] . fort_fn ) | |
( 0 = = ( op - > o_flags & OMPI_OP_FLAGS_FORTRAN_FUNC ) & &
NULL = = op - > o_func [ ompi_op_ddt_map [ ddt - > id ] ] . c_fn ) ) ) {
asprintf ( msg , " %s: the reduction operation %s is not defined on the %s datatype " , func , op - > o_name , ddt - > name ) ;
return false ;
}
} else {
/* Non-intrinsic ddt on intrinsic op */
if ( ' \0 ' ! = ddt - > name [ 0 ] ) {
asprintf ( msg , " %s: the reduction operation %s is not defined for non-intrinsic datatypes (attempted with datatype named \" %s \" ) " , func , op - > o_name , ddt - > name ) ;
} else {
asprintf ( msg , " %s: the reduction operation %s is not defined for non-intrinsic datatypes " , func , op - > o_name ) ;
}
return false ;
}
}
/* All other cases ok */
return true ;
}
2004-06-29 04:02:25 +04:00
/**
2004-06-29 17:04:38 +04:00
* Perform a reduction operation .
2004-06-29 04:02:25 +04:00
*
2004-06-29 17:04:38 +04:00
* @ param op The operation ( IN )
* @ param source Source ( input ) buffer ( IN )
* @ param target Target ( output ) buffer ( IN / OUT )
* @ param count Number of elements ( IN )
* @ param dtype MPI datatype ( IN )
2004-06-29 04:02:25 +04:00
*
2004-06-29 17:04:38 +04:00
* @ returns void As with MPI user - defined reduction functions , there
* is no return code from this function .
2004-06-29 04:02:25 +04:00
*
2004-06-29 17:04:38 +04:00
* Perform a reduction operation with count elements of type dtype in
* the buffers source and target . The target buffer obtains the
* result ( i . e . , the original values in the target buffer are reduced
* with the values in the source buffer and the result is stored in
* the target buffer ) .
*
* This function figures out which reduction operation function to
2005-03-25 23:43:19 +03:00
* invoke and whether to invoke it with C - or Fortran - style invocation
2004-06-29 17:04:38 +04:00
* methods . If the op is intrinsic and has the operation defined for
2005-03-25 23:43:19 +03:00
* dtype , the appropriate back - end function will be invoked .
2004-06-29 17:04:38 +04:00
* Otherwise , the op is assumed to be a user op and the first function
* pointer in the op array will be used .
*
* NOTE : This function assumes that a correct combination will be
* given to it ; it makes no provision for errors ( in the name of
* optimization ) . If you give it an intrinsic op with a datatype that
2005-03-25 23:43:19 +03:00
* is not defined to have that operation , it is likely to seg fault .
2004-06-29 04:02:25 +04:00
*/
2004-06-29 17:04:38 +04:00
static inline void ompi_op_reduce ( ompi_op_t * op , void * source , void * target ,
int count , ompi_datatype_t * dtype )
2004-06-29 04:02:25 +04:00
{
2005-03-25 23:43:19 +03:00
MPI_Fint f_dtype , f_count ;
2004-06-29 17:04:38 +04:00
/*
* Call the reduction function . Two dimensions : a ) if both the op
* and the datatype are intrinsic , we have a series of predefined
* functions for each datatype , b ) if the op has a fortran callback
* function or not .
*
* NOTE : We assume here that we will get a valid result back from
* the ompi_op_ddt_map [ ] ( and not - 1 ) - - if we do , then the
* parameter check in the top - level MPI function should have caught
2005-03-25 23:43:19 +03:00
* it . If we get - 1 because the top - level parameter check is turned
* off , then it ' s an erroneous program and it ' s the user ' s fault .
* : - )
2004-06-29 17:04:38 +04:00
*/
if ( 0 ! = ( op - > o_flags & OMPI_OP_FLAGS_INTRINSIC ) & &
2006-02-06 21:01:45 +03:00
ompi_ddt_is_predefined ( dtype ) ) {
2004-06-29 17:04:38 +04:00
if ( 0 ! = ( op - > o_flags & OMPI_OP_FLAGS_FORTRAN_FUNC ) ) {
2005-03-25 23:43:19 +03:00
f_dtype = OMPI_INT_2_FINT ( dtype - > d_f_to_c_index ) ;
f_count = OMPI_INT_2_FINT ( count ) ;
2004-06-29 17:04:38 +04:00
op - > o_func [ ompi_op_ddt_map [ dtype - > id ] ] . fort_fn ( source , target ,
2005-03-25 23:43:19 +03:00
& f_count , & f_dtype ) ;
2004-06-29 17:04:38 +04:00
} else {
op - > o_func [ ompi_op_ddt_map [ dtype - > id ] ] . c_fn ( source , target , & count ,
& dtype ) ;
}
}
/* User-defined function */
else if ( 0 ! = ( op - > o_flags & OMPI_OP_FLAGS_FORTRAN_FUNC ) ) {
2005-03-25 23:43:19 +03:00
f_dtype = OMPI_INT_2_FINT ( dtype - > d_f_to_c_index ) ;
f_count = OMPI_INT_2_FINT ( count ) ;
op - > o_func [ 0 ] . fort_fn ( source , target , & f_count , & f_dtype ) ;
2005-12-23 19:49:09 +03:00
} else if ( 0 ! = ( op - > o_flags & OMPI_OP_FLAGS_CXX_FUNC ) ) {
op - > o_func [ 0 ] . cxx_intercept_fn ( source , target , & count , & dtype ,
op - > o_func [ 1 ] . c_fn ) ;
2004-06-29 17:04:38 +04:00
} else {
op - > o_func [ 0 ] . c_fn ( source , target , & count , & dtype ) ;
}
2004-04-21 03:11:11 +04:00
}
2004-06-07 19:33:53 +04:00
# endif /* OMPI_OP_H */