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