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