1 /*
2 * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana
3 * University Research and Technology
4 * Corporation. All rights reserved.
5 * Copyright (c) 2004-2007 The University of Tennessee and The University
6 * of Tennessee Research Foundation. All rights
7 * reserved.
8 * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
9 * University of Stuttgart. All rights reserved.
10 * Copyright (c) 2004-2005 The Regents of the University of California.
11 * All rights reserved.
12 * Copyright (c) 2008-2009 Cisco Systems, Inc. All rights reserved.
13 * $COPYRIGHT$
14 *
15 * Additional copyrights may follow
16 *
17 * $HEADER$
18 */
19
20 /** @file
21 *
22 * This is the bxor module source code. It contains the "setup"
23 * functions that will create a module for the MPI_BXOR MPI_Op.
24 */
25
26 #include "ompi_config.h"
27
28 #include "opal/class/opal_object.h"
29 #include "opal/util/output.h"
30
31 #include "ompi/constants.h"
32 #include "ompi/op/op.h"
33 #include "ompi/mca/op/op.h"
34 #include "ompi/mca/op/base/base.h"
35 #include "ompi/mca/op/example/op_example.h"
36
37 /**
38 * Derive a struct from the base op module struct, allowing us to
39 * cache some module-specific information for BXOR. Note that
40 * information that should be shared across all modules should be put
41 * on the example component.
42 */
43 typedef struct {
44 ompi_op_base_module_1_0_0_t super;
45
46 /* Just like the ompi_op_example_component_t, this struct is meant to
47 cache information on a per-module basis. What follows are
48 examples; replace them with whatever is relevant for your
49 component/module. Keep in mind that there will be one distinct
50 module for each MPI_Op; you may want to have different data
51 cached on the module, depending on the MPI_Op that it is
52 supporting.
53
54 In this example, we'll keep the fallback function pointers for
55 several integer types. */
56 ompi_op_base_handler_fn_t fallback_int;
57 ompi_op_base_module_t *fallback_int_module;
58 ompi_op_base_handler_fn_t fallback_long;
59 ompi_op_base_module_t *fallback_long_module;
60 ompi_op_base_handler_fn_t fallback_integer;
61 ompi_op_base_module_t *fallback_integer_module;
62 } module_bxor_t;
63
64 /**
65 * "Constructor" for the bxor module class
66 */
67 static void module_bxor_constructor(module_bxor_t *m)
68 {
69 /* Use this function to initialize any data in the class that is
70 specific to this class (i.e. do *not* initialize the parent
71 data members!). */
72 m->fallback_int = NULL;
73 m->fallback_int_module = NULL;
74 m->fallback_long = NULL;
75 m->fallback_long_module = NULL;
76 m->fallback_integer = NULL;
77 m->fallback_integer_module = NULL;
78 }
79
80 /**
81 * "Destructor" for the bxor module class
82 */
83 static void module_bxor_destructor(module_bxor_t *m)
84 {
85 /* Use this function to clean up any data members that may be
86 necessary. This may include freeing resources and/or setting
87 members to sentinel values to know that the object has been
88 destructed. */
89 m->fallback_int = (ompi_op_base_handler_fn_t) 0xdeadbeef;
90 m->fallback_int_module = (ompi_op_base_module_t*) 0xdeadbeef;
91 m->fallback_long = (ompi_op_base_handler_fn_t) 0xdeadbeef;
92 m->fallback_long_module = (ompi_op_base_module_t*) 0xdeadbeef;
93 m->fallback_integer = (ompi_op_base_handler_fn_t) 0xdeadbeef;
94 m->fallback_integer_module = (ompi_op_base_module_t*) 0xdeadbeef;
95 }
96
97 /**
98 * Setup the class for the bxor module, listing:
99 * - the name of the class
100 * - the "parent" of the class
101 * - function pointer for the constructor (or NULL)
102 * - function pointer for the destructor (or NULL)
103 */
104 static OBJ_CLASS_INSTANCE(module_bxor_t,
105 ompi_op_base_module_t,
106 module_bxor_constructor,
107 module_bxor_destructor);
108
109 /**
110 * Bxor function for C int
111 */
112 static void bxor_int(void *in, void *out, int *count,
113 ompi_datatype_t **type, ompi_op_base_module_t *module)
114 {
115 module_bxor_t *m = (module_bxor_t*) module;
116
117 /* Be chatty to the output, just so that we can see that this
118 function was called */
119 opal_output(0, "In example bxor int function");
120
121 /* This is where you can decide at run-time whether to use the
122 hardware or the fallback function. For example, you could have
123 logic something like this:
124
125 extent = *count * size(int);
126 if (memory_accessible_on_hw(in, extent) &&
127 memory_accessible_on_hw(out, extent)) {
128 ...do the function on hardware...
129 } else if (extent >= large_enough) {
130 ...copy host memory -> hardware memory...
131 ...do the function on hardware...
132 ...copy hardware memory -> host memory...
133 } else {
134 m->fallback_int(in, out, count, type, m->fallback_int_module);
135 }
136 */
137
138 /* But for this example, we'll just call the fallback function to
139 actually do the work */
140 m->fallback_int(in, out, count, type, m->fallback_int_module);
141 }
142
143 /**
144 * Bxor function for C long
145 */
146 static void bxor_long(void *in, void *out, int *count,
147 ompi_datatype_t **type, ompi_op_base_module_t *module)
148 {
149 module_bxor_t *m = (module_bxor_t*) module;
150 opal_output(0, "In example bxor long function");
151
152 /* Just another example function -- similar to bxor_int() */
153
154 m->fallback_long(in, out, count, type, m->fallback_long_module);
155 }
156
157 /**
158 * Bxor function for Fortran INTEGER
159 */
160 static void bxor_integer(void *in, void *out, int *count,
161 ompi_datatype_t **type, ompi_op_base_module_t *module)
162 {
163 module_bxor_t *m = (module_bxor_t*) module;
164 opal_output(0, "In example bxor integer function");
165
166 /* Just another example function -- similar to bxor_int() */
167
168 m->fallback_integer(in, out, count, type, m->fallback_integer_module);
169 }
170
171 /**
172 * Setup function for MPI_BXOR. If we get here, we can assume that a)
173 * the hardware is present, b) the MPI thread scenario is what we
174 * want, and c) the BXOR operation is supported. So this function's
175 * job is to create a module and fill in function pointers for the
176 * functions that this hardware supports.
177 *
178 * This function is *not* allowed to changed the op; it can only read
179 * it to save functions/modules that were already set. The op base
180 * will analyze what was returned in the module and re-set values on
181 * the op if necessary.
182 */
183 ompi_op_base_module_t *ompi_op_example_setup_bxor(ompi_op_t *op)
184 {
185 module_bxor_t *module = OBJ_NEW(module_bxor_t);
186
187 /* Remember that we created an *example* module (vs. a *base*
188 module), so we can cache extra information on there that is
189 specific for the BXOR operation. Let's cache the original
190 fallback function pointers, that were passed to us in this call
191 (i.e., they're already assigned on the op). */
192
193 /* C int */
194 module->super.opm_fns[OMPI_OP_BASE_TYPE_INT] = bxor_int;
195 module->fallback_int = op->o_func.intrinsic.fns[OMPI_OP_BASE_TYPE_INT];
196 module->fallback_int_module =
197 op->o_func.intrinsic.modules[OMPI_OP_BASE_TYPE_INT];
198 /* If you cache a fallback function, you *must* RETAIN (i.e.,
199 increase the refcount) its module so that the module knows that
200 it is being used and won't be freed/destructed. */
201 OBJ_RETAIN(module->fallback_int_module);
202
203 /* C long */
204 module->super.opm_fns[OMPI_OP_BASE_TYPE_LONG] = bxor_long;
205 module->fallback_long = op->o_func.intrinsic.fns[OMPI_OP_BASE_TYPE_LONG];
206 module->fallback_long_module =
207 op->o_func.intrinsic.modules[OMPI_OP_BASE_TYPE_LONG];
208 OBJ_RETAIN(module->fallback_long_module);
209
210 /* Fortran INTEGER */
211 module->super.opm_fns[OMPI_OP_BASE_TYPE_INTEGER] = bxor_integer;
212 module->fallback_integer =
213 op->o_func.intrinsic.fns[OMPI_OP_BASE_TYPE_INTEGER];
214 module->fallback_integer_module =
215 op->o_func.intrinsic.modules[OMPI_OP_BASE_TYPE_INTEGER];
216 OBJ_RETAIN(module->fallback_integer_module);
217
218 /* ...not listing the rest of the integer-typed functions in this
219 example... */
220
221 return (ompi_op_base_module_t*) module;
222 }