root/ompi/mca/op/op.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


   1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
   2 /*
   3  * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana
   4  *                         University Research and Technology
   5  *                         Corporation.  All rights reserved.
   6  * Copyright (c) 2004-2010 The University of Tennessee and The University
   7  *                         of Tennessee Research Foundation.  All rights
   8  *                         reserved.
   9  * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
  10  *                         University of Stuttgart.  All rights reserved.
  11  * Copyright (c) 2004-2005 The Regents of the University of California.
  12  *                         All rights reserved.
  13  * Copyright (c) 2006-2007 Los Alamos National Security, LLC.  All rights
  14  *                         reserved.
  15  * Copyright (c) 2007-2008 UT-Battelle, LLC
  16  * Copyright (c) 2007-2009 Cisco Systems, Inc.  All rights reserved.
  17  * Copyright (c) 2013-2015 Los Alamos National Security, LLC. All rights
  18  *                         reserved.
  19  * Copyright (c) 2018      FUJITSU LIMITED.  All rights reserved.
  20  * $COPYRIGHT$
  21  *
  22  * Additional copyrights may follow
  23  *
  24  * $HEADER$
  25  */
  26 /**
  27  * @file
  28  *
  29  * MPI_Op back-end operation framework.  This framework allows
  30  * component-izing the back-end operations of MPI_Op in order to use
  31  * specialized hardware (e.g., mathematical accelerators).  In short:
  32  * each MPI_Op contains a table of function pointers; one for
  33  * implementing the operation on each predefined datatype.
  34  *
  35  * The MPI interface provides error checking and error handler
  36  * invocation, but the op components provide all other functionality.
  37  *
  38  * Component selection is done on a per-MPI_Op basis when each MPI_Op
  39  * is created.  All MPI_Ops go through the selection process, even
  40  * user-defined MPI_Ops -- although it is expected that most (all?)
  41  * op components will only be able to handle the predefined MPI_Ops.
  42  *
  43  * The general sequence of usage for the op framework is:
  44  *
  45  * 1. ompi_op_base_open() is invoked during MPI_INIT to find/open all
  46  * op components.
  47  *
  48  * 2. ompi_op_base_find_available() is invoked during MPI_INIT to call
  49  * each successfully opened op component's opc_init_query() function.
  50  * All op components that return OMPI_SUCCESS are kept; all others are
  51  * closed and removed from the process.
  52  *
  53  * 3. ompi_op_base_op_select() is invoked during MPI_INIT for each
  54  * predefined MPI_Op (e.g., MPI_SUM).  This function will call each
  55  * available op component's opc_op_query() function to see if this
  56  * component wants to provide a module for one or more of the function
  57  * pointers on this MPI_Op.  Priorities are used to rank returned
  58  * modules; the module with the highest priority has its function
  59  * pointers set in the MPI_Op function table.
  60  *
  61  * Note that a module may only have *some* non-NULL function pointers
  62  * (i.e., for the functions that it can support).  For example, some
  63  * modules may only support operations on single-precision floating
  64  * point datatypes.  These modules would provide function pointers for
  65  * these datatypes and NULL for all the rest.  The op framework will
  66  * mix-n-match function pointers between modules to obtain a full set
  67  * of non-NULL function pointers for a given MPI_Op (note that the op
  68  * base provides a complete set of functions for the MPI_Op, usually a
  69  * simple C loop around the operation, such as "+=" -- so even if
  70  * there is no specialized op component available, there will *always*
  71  * be a full set of MPI_Op function pointers).  The op framework will
  72  * OBJ_RETAIN an op module once for each function pointer where it is
  73  * used on a given MPI_Op.
  74  *
  75  * Note that this scheme can result in up to N different modules being
  76  * used for a single MPI_Op, one per needed datatype function.
  77  *
  78  * 5. Finally, during MPI_FINALIZE, ompi_op_base_close() is invoked to
  79  * close all available op components.
  80  */
  81 
  82 #ifndef MCA_OP_H
  83 #define MCA_OP_H
  84 
  85 #include "ompi_config.h"
  86 
  87 #include "opal/class/opal_object.h"
  88 #include "ompi/mca/mca.h"
  89 
  90 /*
  91  * This file includes some basic struct declarations (but not
  92  * definitions) just so that we can avoid including files like op/op.h
  93  * and datatype/datatype.h, which would create #include file loops.
  94  */
  95 #include "ompi/types.h"
  96 
  97 BEGIN_C_DECLS
  98 
  99 /**
 100  * Corresponding to the types that we can reduce over.  See
 101  * MPI-1:4.9.2, p114-115 and
 102  * MPI-2:4.15, p76-77
 103  */
 104 enum {
 105     /** C integer: int8_t */
 106     OMPI_OP_BASE_TYPE_INT8_T,
 107     /** C integer: uint8_t */
 108     OMPI_OP_BASE_TYPE_UINT8_T,
 109     /** C integer: int16_t */
 110     OMPI_OP_BASE_TYPE_INT16_T,
 111     /** C integer: uint16_t */
 112     OMPI_OP_BASE_TYPE_UINT16_T,
 113     /** C integer: int32_t */
 114     OMPI_OP_BASE_TYPE_INT32_T,
 115     /** C integer: uint32_t */
 116     OMPI_OP_BASE_TYPE_UINT32_T,
 117     /** C integer: int64_t */
 118     OMPI_OP_BASE_TYPE_INT64_T,
 119     /** C integer: uint64_t */
 120     OMPI_OP_BASE_TYPE_UINT64_T,
 121 
 122     /** Fortran integer */
 123     OMPI_OP_BASE_TYPE_INTEGER,
 124     /** Fortran integer*1 */
 125     OMPI_OP_BASE_TYPE_INTEGER1,
 126     /** Fortran integer*2 */
 127     OMPI_OP_BASE_TYPE_INTEGER2,
 128     /** Fortran integer*4 */
 129     OMPI_OP_BASE_TYPE_INTEGER4,
 130     /** Fortran integer*8 */
 131     OMPI_OP_BASE_TYPE_INTEGER8,
 132     /** Fortran integer*16 */
 133     OMPI_OP_BASE_TYPE_INTEGER16,
 134 
 135     /** Floating point: short float */
 136     OMPI_OP_BASE_TYPE_SHORT_FLOAT,
 137     /** Floating point: float */
 138     OMPI_OP_BASE_TYPE_FLOAT,
 139     /** Floating point: double */
 140     OMPI_OP_BASE_TYPE_DOUBLE,
 141     /** Floating point: real */
 142     OMPI_OP_BASE_TYPE_REAL,
 143     /** Floating point: real*2 */
 144     OMPI_OP_BASE_TYPE_REAL2,
 145     /** Floating point: real*4 */
 146     OMPI_OP_BASE_TYPE_REAL4,
 147     /** Floating point: real*8 */
 148     OMPI_OP_BASE_TYPE_REAL8,
 149     /** Floating point: real*16 */
 150     OMPI_OP_BASE_TYPE_REAL16,
 151     /** Floating point: double precision */
 152     OMPI_OP_BASE_TYPE_DOUBLE_PRECISION,
 153     /** Floating point: long double */
 154     OMPI_OP_BASE_TYPE_LONG_DOUBLE,
 155 
 156     /** Logical */
 157     OMPI_OP_BASE_TYPE_LOGICAL,
 158     /** Bool */
 159     OMPI_OP_BASE_TYPE_BOOL,
 160 
 161     /** Complex */
 162     /* short float complex */
 163     OMPI_OP_BASE_TYPE_C_SHORT_FLOAT_COMPLEX,
 164     /* float complex */
 165     OMPI_OP_BASE_TYPE_C_FLOAT_COMPLEX,
 166     /* double complex */
 167     OMPI_OP_BASE_TYPE_C_DOUBLE_COMPLEX,
 168     /* long double complex */
 169     OMPI_OP_BASE_TYPE_C_LONG_DOUBLE_COMPLEX,
 170 
 171     /** Byte */
 172     OMPI_OP_BASE_TYPE_BYTE,
 173 
 174     /** 2 location Fortran: 2 real */
 175     OMPI_OP_BASE_TYPE_2REAL,
 176     /** 2 location Fortran: 2 double precision */
 177     OMPI_OP_BASE_TYPE_2DOUBLE_PRECISION,
 178     /** 2 location Fortran: 2 integer */
 179     OMPI_OP_BASE_TYPE_2INTEGER,
 180 
 181     /** 2 location C: float int */
 182     OMPI_OP_BASE_TYPE_FLOAT_INT,
 183     /** 2 location C: double int */
 184     OMPI_OP_BASE_TYPE_DOUBLE_INT,
 185     /** 2 location C: long int */
 186     OMPI_OP_BASE_TYPE_LONG_INT,
 187     /** 2 location C: int int */
 188     OMPI_OP_BASE_TYPE_2INT,
 189     /** 2 location C: short int */
 190     OMPI_OP_BASE_TYPE_SHORT_INT,
 191     /** 2 location C: long double int */
 192     OMPI_OP_BASE_TYPE_LONG_DOUBLE_INT,
 193 
 194     /** 2 location C: wchar_t */
 195     OMPI_OP_BASE_TYPE_WCHAR,
 196 
 197     /** Maximum type */
 198     OMPI_OP_BASE_TYPE_MAX
 199 };
 200 
 201 
 202 /**
 203  * Fortran handles; must be [manually set to be] equivalent to the
 204  * values in mpif.h.
 205  */
 206 enum {
 207     /** Corresponds to Fortran MPI_OP_NULL */
 208     OMPI_OP_BASE_FORTRAN_NULL = 0,
 209     /** Corresponds to Fortran MPI_MAX */
 210     OMPI_OP_BASE_FORTRAN_MAX,
 211     /** Corresponds to Fortran MPI_MIN */
 212     OMPI_OP_BASE_FORTRAN_MIN,
 213     /** Corresponds to Fortran MPI_SUM */
 214     OMPI_OP_BASE_FORTRAN_SUM,
 215     /** Corresponds to Fortran MPI_PROD */
 216     OMPI_OP_BASE_FORTRAN_PROD,
 217     /** Corresponds to Fortran MPI_LAND */
 218     OMPI_OP_BASE_FORTRAN_LAND,
 219     /** Corresponds to Fortran MPI_BAND */
 220     OMPI_OP_BASE_FORTRAN_BAND,
 221     /** Corresponds to Fortran MPI_LOR */
 222     OMPI_OP_BASE_FORTRAN_LOR,
 223     /** Corresponds to Fortran MPI_BOR */
 224     OMPI_OP_BASE_FORTRAN_BOR,
 225     /** Corresponds to Fortran MPI_LXOR */
 226     OMPI_OP_BASE_FORTRAN_LXOR,
 227     /** Corresponds to Fortran MPI_BXOR */
 228     OMPI_OP_BASE_FORTRAN_BXOR,
 229     /** Corresponds to Fortran MPI_MAXLOC */
 230     OMPI_OP_BASE_FORTRAN_MAXLOC,
 231     /** Corresponds to Fortran MPI_MINLOC */
 232     OMPI_OP_BASE_FORTRAN_MINLOC,
 233     /** Corresponds to Fortran MPI_REPLACE */
 234     OMPI_OP_BASE_FORTRAN_REPLACE,
 235     /** Corresponds to Fortran MPI_NO_OP */
 236     OMPI_OP_BASE_FORTRAN_NO_OP,
 237 
 238     /** Maximum value */
 239     OMPI_OP_BASE_FORTRAN_OP_MAX
 240 };
 241 
 242 /**
 243  * Pre-declare this so that we can pass it as an argument to the
 244  * typedef'ed functions.
 245  */
 246 struct ompi_op_base_module_1_0_0_t;
 247 
 248 typedef struct ompi_op_base_module_1_0_0_t ompi_op_base_module_t;
 249 
 250 /**
 251  * Typedef for 2-buffer op functions.
 252  *
 253  * We don't use MPI_User_function because this would create a
 254  * confusing dependency loop between this file and mpi.h.  So this is
 255  * repeated code, but it's better this way (and this typedef will
 256  * never change, so there's not much of a maintenance worry).
 257  */
 258 typedef void (*ompi_op_base_handler_fn_1_0_0_t)(void *, void *, int *,
 259                                                 struct ompi_datatype_t **,
 260                                                 struct ompi_op_base_module_1_0_0_t *);
 261 
 262 typedef ompi_op_base_handler_fn_1_0_0_t ompi_op_base_handler_fn_t;
 263 
 264 /*
 265  * Typedef for 3-buffer (two input and one output) op functions.
 266  */
 267 typedef void (*ompi_op_base_3buff_handler_fn_1_0_0_t)(void *,
 268                                                       void *,
 269                                                       void *, int *,
 270                                                       struct ompi_datatype_t **,
 271                                                       struct ompi_op_base_module_1_0_0_t *);
 272 
 273 typedef ompi_op_base_3buff_handler_fn_1_0_0_t ompi_op_base_3buff_handler_fn_t;
 274 
 275 /**
 276  * Op component initialization
 277  *
 278  * Initialize the given op component.  This function should initialize
 279  * any component-level. data.  It will be called exactly once during
 280  * MPI_INIT.
 281  *
 282  * @note The component framework is not lazily opened, so attempts
 283  * should be made to minimze the amount of memory allocated during
 284  * this function.
 285  *
 286  * @param[in] enable_progress_threads True if the component needs to
 287  *                                support progress threads
 288  * @param[in] enable_mpi_threads  True if the component needs to
 289  *                                support MPI_THREAD_MULTIPLE
 290  *
 291  * @retval OMPI_SUCCESS Component successfully initialized
 292  * @retval OMPI_ERROR   An unspecified error occurred
 293  */
 294 typedef int (*ompi_op_base_component_init_query_fn_t)
 295      (bool enable_progress_threads, bool enable_mpi_threads);
 296 
 297 
 298 /**
 299  * Query whether a component is available for a specific MPI_Op.
 300  *
 301  * If the component is available, an object should be allocated and
 302  * returned (with refcount at 1).  The module will not be used for
 303  * reduction operations until module_enable() is called on the module,
 304  * but may be destroyed (via OBJ_RELEASE) either before or after
 305  * module_enable() is called.  If the module needs to release
 306  * resources obtained during query(), it should do so in the module
 307  * destructor.
 308  *
 309  * A component may provide NULL to this function to indicate it does
 310  * not wish to run or return an error during module_enable().
 311  *
 312  * @param[in] op          The MPI_Op being created
 313  * @param[out] priority   Priority setting for component on
 314  *                        this op
 315  *
 316  * @returns An initialized module structure if the component can
 317  * provide a module with the requested functionality or NULL if the
 318  * component should not be used on the given communicator.
 319  */
 320 typedef struct ompi_op_base_module_1_0_0_t *
 321   (*ompi_op_base_component_op_query_1_0_0_fn_t)
 322     (struct ompi_op_t *op, int *priority);
 323 
 324 /**
 325  * Op component interface.
 326  *
 327  * Component interface for the op framework.  A public instance of
 328  * this structure, called mca_op_[component_name]_component, must
 329  * exist in any op component.
 330  */
 331 typedef struct ompi_op_base_component_1_0_0_t {
 332     /** Base component description */
 333     mca_base_component_t opc_version;
 334     /** Base component data block */
 335     mca_base_component_data_t opc_data;
 336 
 337     /** Component initialization function */
 338     ompi_op_base_component_init_query_fn_t opc_init_query;
 339     /** Query whether component is useable for given op */
 340     ompi_op_base_component_op_query_1_0_0_fn_t opc_op_query;
 341 } ompi_op_base_component_1_0_0_t;
 342 
 343 
 344 /** Per guidence in mca.h, use the unversioned struct name if you just
 345     want to always keep up with the most recent version of the
 346     interace. */
 347 typedef struct ompi_op_base_component_1_0_0_t ompi_op_base_component_t;
 348 
 349 /**
 350  * Module initialization function.  Should return OPAL_SUCCESS if
 351  * everything goes ok.  This function can be NULL in the module struct
 352  * if the module doesn't need to do anything between the component
 353  * query function and being invoked for MPI_Op operations.
 354  */
 355 typedef int (*ompi_op_base_module_enable_1_0_0_fn_t)
 356     (struct ompi_op_base_module_1_0_0_t *module,
 357      struct ompi_op_t *op);
 358 
 359 /**
 360  * Module struct
 361  */
 362 typedef struct ompi_op_base_module_1_0_0_t {
 363     /** Op modules all inherit from opal_object */
 364     opal_object_t super;
 365 
 366     /** Enable function called when an op module is (possibly) going
 367         to be used for the given MPI_Op */
 368     ompi_op_base_module_enable_1_0_0_fn_t opm_enable;
 369 
 370     /** Just for reference -- a pointer to the MPI_Op that this module
 371         is being used for */
 372     struct ompi_op_t *opm_op;
 373 
 374     /** Function pointers for all the different datatypes to be used
 375         with the MPI_Op that this module is used with */
 376     ompi_op_base_handler_fn_1_0_0_t opm_fns[OMPI_OP_BASE_TYPE_MAX];
 377     ompi_op_base_3buff_handler_fn_1_0_0_t opm_3buff_fns[OMPI_OP_BASE_TYPE_MAX];
 378 } ompi_op_base_module_1_0_0_t;
 379 
 380 /**
 381  * Declare the module as a class, unversioned
 382  */
 383 OMPI_DECLSPEC OBJ_CLASS_DECLARATION(ompi_op_base_module_t);
 384 
 385 /**
 386  * Declare the module as a class, unversioned
 387  */
 388 OMPI_DECLSPEC OBJ_CLASS_DECLARATION(ompi_op_base_module_1_0_0_t);
 389 
 390 /**
 391  * Struct that is used in op.h to hold all the function pointers and
 392  * pointers to the corresopnding modules (so that we can properly
 393  * RETAIN/RELEASE them)
 394  */
 395 typedef struct ompi_op_base_op_fns_1_0_0_t {
 396     ompi_op_base_handler_fn_1_0_0_t fns[OMPI_OP_BASE_TYPE_MAX];
 397     ompi_op_base_module_t *modules[OMPI_OP_BASE_TYPE_MAX];
 398 } ompi_op_base_op_fns_1_0_0_t;
 399 
 400 typedef ompi_op_base_op_fns_1_0_0_t ompi_op_base_op_fns_t;
 401 
 402 /**
 403  * Struct that is used in op.h to hold all the function pointers and
 404  * pointers to the corresopnding modules (so that we can properly
 405  * RETAIN/RELEASE them)
 406  */
 407 typedef struct ompi_op_base_op_3buff_fns_1_0_0_t {
 408     ompi_op_base_3buff_handler_fn_1_0_0_t fns[OMPI_OP_BASE_TYPE_MAX];
 409     ompi_op_base_module_t *modules[OMPI_OP_BASE_TYPE_MAX];
 410 } ompi_op_base_op_3buff_fns_1_0_0_t;
 411 
 412 typedef ompi_op_base_op_3buff_fns_1_0_0_t ompi_op_base_op_3buff_fns_t;
 413 
 414 /*
 415  * Macro for use in modules that are of type op v2.0.0
 416  */
 417 #define OMPI_OP_BASE_VERSION_1_0_0 \
 418     OMPI_MCA_BASE_VERSION_2_1_0("op", 1, 0, 0)
 419 
 420 END_C_DECLS
 421 
 422 #endif /* OMPI_MCA_OP_H */

/* [<][>][^][v][top][bottom][index][help] */