1 /*
2  * Copyright (C) by Argonne National Laboratory
3  *     See COPYRIGHT in top-level directory
4  */
5 
6 /* Types and interfaces in this file are internally used by MPIR_T itself.
7  * Other modules should call higher level interfaces in mpit.h instead.
8  */
9 #ifndef MPITIMPL_H_INCLUDED
10 #define MPITIMPL_H_INCLUDED
11 
12 #include "mpi.h"
13 #include "mpir_strerror.h"
14 #include "mpir_type_defs.h"
15 #include "mpir_assert.h"
16 #include "mpir_pointers.h"
17 #include "utarray.h"
18 #include "uthash.h"
19 #include "mpir_objects.h"
20 
21 #ifdef HAVE_ERROR_CHECKING
22 typedef enum {
23     MPIR_T_OBJECT_INVALID = 0,
24     MPIR_T_ENUM_HANDLE,
25     MPIR_T_CVAR_HANDLE,
26     MPIR_T_PVAR_HANDLE,
27     MPIR_T_PVAR_SESSION
28 } MPIR_T_object_kind;
29 #endif
30 
31 /* MPI_T enum
32  */
33 typedef struct enum_item_s {
34     const char *name;
35     int value;
36 } enum_item_t;
37 
38 typedef struct MPIR_T_enum_s {
39 #ifdef HAVE_ERROR_CHECKING
40     MPIR_T_object_kind kind;
41 #endif
42     const char *name;
43     UT_array *items;
44 } MPIR_T_enum_t;
45 
46 /* MPI_T category (cat)
47  */
48 typedef struct {
49     const char *name;
50     UT_array *cvar_indices;
51     UT_array *pvar_indices;
52     UT_array *subcat_indices;
53     const char *desc;
54 } cat_table_entry_t;
55 
56 /* Hash names to indices in a table */
57 typedef struct {
58     const char *name;
59     unsigned idx;
60     UT_hash_handle hh;          /* Makes this structure hashable */
61 } name2index_hash_t;
62 
63 /* MPI_T control variable (cvar)
64  */
65 typedef struct MPIR_T_cvar_range_value_s {
66     int low;
67     int high;
68 } MPIR_T_cvar_range_value_t;
69 
70 /* Type used to represent cvar default values */
71 typedef union MPIR_T_cvar_value_s {
72     int d;
73     unsigned u;
74     unsigned ul;
75     unsigned ull;
76     MPI_Count c;
77     const char *str;
78     double f;
79     MPIR_T_cvar_range_value_t range;
80 } MPIR_T_cvar_value_t;
81 
82 typedef int MPIR_T_cvar_get_addr_cb(void *obj_handle, void **addr);
83 typedef int MPIR_T_cvar_get_count_cb(void *obj_handle, int *count);
84 
85 typedef struct cvar_table_entry_s {
86     /* Is the cvar currently in use? False if the cvar is unregistered */
87     int active;
88 
89     /* cvar name */
90     const char *name;
91 
92     /* Address of the cvar. May be NULL when get_addr != NULL */
93     void *addr;
94 
95     /* cvar data type */
96     MPI_Datatype datatype;
97 
98     /* Num. of elements of the cvar. May be ignored when get_count != NULL */
99     int count;
100 
101     /* Properties of the cvar */
102     MPI_T_enum enumtype;
103     MPIR_T_verbosity_t verbosity;
104     MPIR_T_bind_t bind;
105     MPIR_T_scope_t scope;
106 
107     /* Default value */
108     MPIR_T_cvar_value_t defaultval;
109 
110     /* If not NULL, components provide this callback to get addr of the cvar */
111     MPIR_T_cvar_get_addr_cb *get_addr;
112 
113     /* If not NULL, components provide this callback to get count */
114     MPIR_T_cvar_get_count_cb *get_count;
115 
116     /* Description of the cvar */
117     const char *desc;
118 } cvar_table_entry_t;
119 
120 typedef struct MPIR_T_cvar_handle_s {
121 #ifdef HAVE_ERROR_CHECKING
122     MPIR_T_object_kind kind;
123 #endif
124 
125     /* Address and count of the cvar. Set at handle allocation time */
126     void *addr;
127     int count;
128 
129     /* Cached value from cvar_table_entry_t to avoid indirection */
130     MPI_Datatype datatype;
131     MPIR_T_scope_t scope;
132 } MPIR_T_cvar_handle_t;
133 
134 void MPIR_T_CVAR_REGISTER_impl(MPI_Datatype dtype, const char *name, const void *addr, int count,
135                                MPIR_T_enum_t * etype, MPIR_T_verbosity_t verb, MPIR_T_bind_t bind,
136                                MPIR_T_scope_t scope, MPIR_T_cvar_get_addr_cb get_addr,
137                                MPIR_T_cvar_get_count_cb get_count, MPIR_T_cvar_value_t defaultval,
138                                const char *cat, const char *desc);
139 
140 /* MPI_T performance variable (pvar)
141  */
142 
143 /* Forward declaration */
144 struct MPIR_T_pvar_handle_s;
145 struct MPIR_T_pvar_session_s;
146 
147 typedef void MPIR_T_pvar_get_value_cb(void *addr, void *obj_handle, int count, void *buf);
148 typedef void MPIR_T_pvar_get_count_cb(void *addr, void *obj_handle, int *count);
149 
150 /* Basic pvar flags defined by MPI_T standard */
151 #define MPIR_T_PVAR_FLAG_READONLY      0x01
152 #define MPIR_T_PVAR_FLAG_CONTINUOUS    0x02
153 #define MPIR_T_PVAR_FLAG_ATOMIC        0x04
154 
155 /* Auxlilary flags used by MPIR_T */
156 
157 /* pvar is MPI_T_PVAR_CLASS_{COUNTER, TIMER, AGGREGATE} */
158 #define MPIR_T_PVAR_FLAG_SUM           0x08
159 
160 /* pvar is MPI_T_PVAR_CLASS_{HIGH, LOW}WATERMARK */
161 #define MPIR_T_PVAR_FLAG_WATERMARK     0x10
162 
163 /* pvar is continuous. If not, it has been started at least once */
164 #define MPIR_T_PVAR_FLAG_ONCESTARTED   0x20
165 
166 /* pvar is continuous. If not, it is started */
167 #define MPIR_T_PVAR_FLAG_STARTED       0x40
168 
169 /* Used only for watermark handles. Set if a pvar handle is the
170  * first handle of an associated watermark.
171  */
172 #define MPIR_T_PVAR_FLAG_FIRST         0x80
173 
174 /* MPI_T performance variable (pvar) stuff */
175 typedef struct {
176     /* Is the pvar in use (i.e., not unregistered)? */
177     int active;
178 
179     /* pvar name */
180     const char *name;
181 
182     /* If not NULL, it is address of the pvar */
183     void *addr;
184 
185     /* pvar data type */
186     MPI_Datatype datatype;
187 
188     /* Num. of elements of the pvar */
189     int count;
190 
191     /* Properties of the pvar */
192     MPIR_T_pvar_class_t varclass;
193     MPIR_T_verbosity_t verbosity;
194     MPIR_T_enum_t *enumtype;
195     MPIR_T_bind_t bind;
196 
197     /* Basic flags of the pvar */
198     int flags;
199 
200     /* If not NULL, components provide this callback to read the pvar */
201     MPIR_T_pvar_get_value_cb *get_value;
202 
203     /* If not NULL, components provide this callback to get count */
204     MPIR_T_pvar_get_count_cb *get_count;
205 
206     /* Description of the pvar */
207     const char *desc;
208 } pvar_table_entry_t;
209 
210 /*
211  The following two macros do not work since C preprocessor does not support
212  nested ifdefs. So we use another woarkable but a little ugly approach.
213 
214 #define PVAR_GATED_ACTION(MODULE, action_) \
215     do { \
216         #ifdef ENABLE_PVAR_##MODULE \
217             action_; \
218         #endif \
219     } while (0)
220 */
221 
222 /* ENABLE_PVAR_##MODULE must be defined by configure script either to 0 or 1 */
223 #define PVAR_GATED_ACTION(MODULE, action_) \
224     do { \
225         if (ENABLE_PVAR_##MODULE) { \
226             action_; \
227         } \
228     } while (0)
229 
230 /* For some classes of pvars, internally we can not represent them
231  * in basic data types. So come the following typedefs.
232  */
233 
234 /* Timer type */
235 typedef struct {
236     /* Accumulated time */
237     MPL_time_t total;
238 
239     /* Time when the timer was started recently */
240     MPL_time_t curstart;
241 
242     /* A counter recording how many times the timer is started */
243     unsigned long long count;
244 } MPIR_T_pvar_timer_t;
245 
246 /* An union to represent a watermark value */
247 typedef union {
248     double f;
249     unsigned u;
250     unsigned long ul;
251     unsigned long long ull;
252 } watermark_value_t;
253 
254 /* Watermark type */
255 typedef struct {
256     /* current -- current resource utilization level
257      * waterarmk -- cached value for the first pvar handle
258      */
259     watermark_value_t current, watermark;
260 
261     /* Datatype of the watermark */
262     MPI_Datatype datatype;
263 
264     /* Is the cached value (i.e, watermark) in use by a pvar handle? */
265     int first_used;
266 
267     /* Is the first pvar handle started? */
268     int first_started;
269 
270     /* A double-linked list of handles of the pvar */
271     struct MPIR_T_pvar_handle_s *hlist;
272 } MPIR_T_pvar_watermark_t;
273 
274 typedef struct MPIR_T_pvar_handle_s {
275 #ifdef HAVE_ERROR_CHECKING
276     MPIR_T_object_kind kind;
277 #endif
278 
279     /* These are cached fields from pvar table. Do so to avoid extra
280      * indirection when accessing them through pvar handles.
281      */
282     void *addr;
283     MPI_Datatype datatype;
284     int count;
285     MPIR_T_pvar_get_value_cb *get_value;
286     MPIR_T_pvar_class_t varclass;
287 
288     /* Bytes of an element of datatype */
289     int bytes;
290 
291     /* Basic flags copied from pvar info + auxilary flags in pvar handle */
292     int flags;
293 
294     /* Store info here in case we need other fields */
295     const pvar_table_entry_t *info;
296 
297     /* Owner session from which the handle is allocated */
298     struct MPIR_T_pvar_session_s *session;
299 
300     /* Object which this pvar is bound to. NULL if no binding */
301     void *obj_handle;
302 
303     /* This is how we support pvar sessions.
304      *
305      * For pvars of counter, timer or aggregate type, we cache their value at
306      * the last start time in offset, their current value in current, and
307      * their accumlated value in accum. Generally, when such a pvar is running,
308      * reading the pvar should return
309      *      accum[i] + current[i] - offset[i], 0 <= i < count - 1.
310      * When the pvar is stopped, reading just returns accum.
311      *
312      * For pvars of high/lowwatermark type, above method does not work.
313      * We have a copy of such a pvar in every handle of the pvar.
314      * Handles are registered to the pvar. Whenever a watermark changes,
315      * its copies in non-stopped handles are updated. That sounds non-scalable.
316      * Considering single-session is common, we reserve room in watermark
317      * themselves for cache buffer for the first handle. So when such a pvar
318      * changes, it also updates the watermark close to it in memory.
319      *
320      * For pvars of other classes,  since they are supposed to be readonly
321      * and continuous (FIXME: Is it true?), caching is not needed.
322      */
323     void *accum;
324     void *offset;
325     void *current;
326 
327     watermark_value_t watermark;
328 
329     /* To chain handles in a session */
330     struct MPIR_T_pvar_handle_s *prev, *next;
331 
332     /* To chain handles of a watermark pvar */
333     struct MPIR_T_pvar_handle_s *prev2, *next2;
334 } MPIR_T_pvar_handle_t;
335 
336 typedef struct MPIR_T_pvar_session_s {
337 #ifdef HAVE_ERROR_CHECKING
338     MPIR_T_object_kind kind;
339 #endif
340 
341     /* A linked list of pvar handles */
342     MPIR_T_pvar_handle_t *hlist;
343 } MPIR_T_pvar_session_t;
344 
345 extern void MPIR_T_PVAR_REGISTER_impl(MPIR_T_pvar_class_t varclass, MPI_Datatype dtype,
346                                       const char *name, void *addr, int count,
347                                       MPIR_T_enum_t * etype, MPIR_T_verbosity_t verb,
348                                       MPIR_T_bind_t bind, int flags,
349                                       MPIR_T_pvar_get_value_cb get_value,
350                                       MPIR_T_pvar_get_count_cb get_count, const char *cat,
351                                       const char *desc);
352 
353 /* For static pvars (i.e., pvars with static storage), we embed their class name
354  * into their variable name, so that users can declare pvars with the same name
355  * for different classes, without worry of name conflict. "class + pvar name"
356  * should be unique as required by MPI_T.
357  */
358 
359 /* MPI_T_PVAR_CLASS_STATE (continuous only)
360  */
361 
362 /* Interfaces through pointer or name */
363 #define MPIR_T_PVAR_STATE_SET_VAR_impl(ptr_, val_) \
364     do { *(ptr_) = (val_); } while (0)
365 #define MPIR_T_PVAR_STATE_GET_VAR_impl(ptr_) \
366     (*(ptr_))
367 
368 #define MPIR_T_PVAR_STATE_SET_impl(name_, val_) \
369     MPIR_T_PVAR_STATE_SET_VAR_impl(&PVAR_STATE_##name_, val_)
370 #define MPIR_T_PVAR_STATE_GET_impl(name_) \
371     MPIR_T_PVAR_STATE_GET_VAR_impl(&PVAR_STATE_##name_)
372 
373 /* Registration AND initialization for static pvar */
374 #define MPIR_T_PVAR_STATE_REGISTER_STATIC_impl(dtype_, name_, \
375             initval_, etype_, verb_, bind_, flags_, cat_, desc_) \
376     do { \
377         void *addr_; \
378         /* Allowable datatypes only */ \
379         MPIR_Assert((dtype_) == MPI_INT); \
380         /* Double check if dtype_ and name_ match */ \
381         MPIR_Assert(sizeof(PVAR_STATE_##name_) == MPIR_Datatype_get_basic_size(dtype_)); \
382         MPIR_Assert((flags_) & MPIR_T_PVAR_FLAG_CONTINUOUS); \
383         /* State pvars should be describled further by an enum */ \
384         MPIR_Assert((etype_) != MPI_T_ENUM_NULL); \
385         PVAR_STATE_##name_ = (initval_); \
386         addr_ = &PVAR_STATE_##name_; \
387         MPIR_T_PVAR_REGISTER_impl(MPI_T_PVAR_CLASS_STATE, dtype_, #name_, \
388             addr_, 1, etype_, verb_, bind_, flags_, NULL, NULL, cat_, desc_); \
389     } while (0)
390 
391 /* Registration for dynamic pvar w/ or w/o callback. Init is left to users */
392 #define MPIR_T_PVAR_STATE_REGISTER_DYNAMIC_impl(dtype_, name_, addr_, count_, \
393             etype_, verb_, bind_, flags_, get_value_, get_count_, cat_, desc_) \
394     do { \
395         /* Allowable datatypes */ \
396         MPIR_Assert((dtype_) == MPI_INT); \
397         MPIR_Assert((flags_) & MPIR_T_PVAR_FLAG_CONTINUOUS); \
398         MPIR_Assert((etype_) != MPI_T_ENUM_NULL); \
399         MPIR_Assert((addr_) != NULL || (get_value_) != NULL); \
400         MPIR_T_PVAR_REGISTER_impl(MPI_T_PVAR_CLASS_STATE, dtype_, #name_, \
401             addr_, count_, etype_, verb_, bind_, flags_, get_value_, cat_, desc_); \
402     } while (0)
403 
404 
405 /* MPI_T_PVAR_CLASS_LEVEL (continuous only)
406  */
407 
408 /* Interfaces through pointer or name */
409 #define MPIR_T_PVAR_LEVEL_SET_VAR_impl(ptr_, val_) \
410     do { *(ptr_) = (val_); } while (0)
411 #define MPIR_T_PVAR_LEVEL_GET_VAR_impl(ptr_) \
412     (*(ptr_))
413 #define MPIR_T_PVAR_LEVEL_INC_VAR_impl(ptr_, val_) \
414     do { *(ptr_) += (val_); } while (0)
415 #define MPIR_T_PVAR_LEVEL_DEC_VAR_impl(ptr_, val_) \
416     do { *(ptr_) -= (val_); } while (0)
417 
418 #define MPIR_T_PVAR_LEVEL_SET_impl(name_, val_) \
419     MPIR_T_PVAR_LEVEL_SET_VAR_impl(&PVAR_LEVEL_##name_, val_)
420 #define MPIR_T_PVAR_LEVEL_GET_impl(name_) \
421     MPIR_T_PVAR_LEVEL_GET_VAR_impl(&PVAR_LEVEL_##name_)
422 #define MPIR_T_PVAR_LEVEL_INC_impl(name_, val_) \
423     MPIR_T_PVAR_LEVEL_INC_VAR_impl(&PVAR_LEVEL_##name_, val_)
424 #define MPIR_T_PVAR_LEVEL_DEC_impl(name_, val_) \
425     MPIR_T_PVAR_LEVEL_DEC_VAR_impl(&PVAR_LEVEL_##name_, val_)
426 
427 /* Registration AND initialization for static pvar */
428 #define MPIR_T_PVAR_LEVEL_REGISTER_STATIC_impl(dtype_, name_, \
429             initval_, verb_, bind_, flags_, cat_, desc_) \
430     do { \
431         void *addr_; \
432         /* Allowable datatypes only */ \
433         MPIR_Assert((dtype_) == MPI_UNSIGNED || (dtype_) == MPI_UNSIGNED_LONG || \
434                     (dtype_) == MPI_UNSIGNED_LONG_LONG || (dtype_) == MPI_DOUBLE); \
435         /* Double check if dtype_ and name_ match */ \
436         MPIR_Assert(sizeof(PVAR_LEVEL_##name_) == MPIR_Datatype_get_basic_size(dtype_)); \
437         MPIR_Assert((flags_) & MPIR_T_PVAR_FLAG_CONTINUOUS); \
438         PVAR_LEVEL_##name_ = (initval_); \
439         addr_ = &PVAR_LEVEL_##name_; \
440         MPIR_T_PVAR_REGISTER_impl(MPI_T_PVAR_CLASS_LEVEL, dtype_, #name_, \
441             addr_, 1, MPI_T_ENUM_NULL, verb_, bind_, flags_, NULL, NULL, cat_, desc_); \
442     } while (0)
443 
444 /* Registration for dynamic pvar w/ or w/o callback. Init is left to users */
445 #define MPIR_T_PVAR_LEVEL_REGISTER_DYNAMIC_impl(dtype_, name_, \
446             addr_, count_, verb_, bind_, flags_, get_value_, get_count, cat_, desc_) \
447     do { \
448         /* Allowable datatypes */ \
449         MPIR_Assert((dtype_) == MPI_UNSIGNED || (dtype_) == MPI_UNSIGNED_LONG || \
450                     (dtype_) == MPI_UNSIGNED_LONG_LONG || (dtype_) == MPI_DOUBLE); \
451         MPIR_Assert((flags_) & MPIR_T_PVAR_FLAG_CONTINUOUS); \
452         MPIR_Assert((addr_) != NULL || (get_value_) != NULL); \
453         MPIR_T_PVAR_REGISTER_impl(MPI_T_PVAR_CLASS_LEVEL, dtype_, #name_, \
454             addr_, count_, MPI_T_ENUM_NULL, verb_, bind_, flags_, get_value_, \
455             get_count, cat_, desc_); \
456     } while (0)
457 
458 
459 /* MPI_T_PVAR_CLASS_SIZE (continuous only)
460  */
461 
462 /* Interfaces through pointer or name */
463 #define MPIR_T_PVAR_SIZE_SET_VAR_impl(ptr_, val_) \
464     do { *(ptr_) = (val_); } while (0)
465 #define MPIR_T_PVAR_SIZE_GET_VAR_impl(ptr_) \
466     (*(ptr_))
467 
468 #define MPIR_T_PVAR_SIZE_SET_impl(name_, val_) \
469     MPIR_T_PVAR_SIZE_SET_VAR_impl(&PVAR_SIZE_##name_, val_)
470 #define MPIR_T_PVAR_SIZE_GET_impl(name_) \
471     MPIR_T_PVAR_SIZE_GET_VAR_impl(&PVAR_SIZE_##name_)
472 
473 /* Registration AND initialization for static pvar */
474 #define MPIR_T_PVAR_SIZE_REGISTER_STATIC_impl(dtype_, name_, \
475             initval_, verb_, bind_, flags_, cat_, desc_) \
476     do { \
477         void *addr_; \
478         /* Allowable datatypes only */ \
479         MPIR_Assert((dtype_) == MPI_UNSIGNED || (dtype_) == MPI_UNSIGNED_LONG || \
480                     (dtype_) == MPI_UNSIGNED_LONG_LONG || (dtype_) == MPI_DOUBLE); \
481         /* Double check if dtype_ and name_ match */ \
482         MPIR_Assert(sizeof(PVAR_SIZE_##name_) == MPIR_Datatype_get_basic_size(dtype_)); \
483         MPIR_Assert((flags_) & MPIR_T_PVAR_FLAG_CONTINUOUS); \
484         PVAR_SIZE_##name_ = (initval_); \
485         addr_ = &PVAR_SIZE_##name_; \
486         MPIR_T_PVAR_REGISTER_impl(MPI_T_PVAR_CLASS_SIZE, dtype_, #name_, \
487             addr_, 1, MPI_T_ENUM_NULL, verb_, bind_, flags_, NULL, NULL, cat_, desc_); \
488     } while (0)
489 
490 /* Registration for dynamic pvar w/ or w/o callback. Init is left to users */
491 #define MPIR_T_PVAR_SIZE_REGISTER_DYNAMIC_impl(dtype_, name_, \
492             addr_, count_, verb_, bind_, flags_, get_value_, get_count_, cat_, desc_) \
493     do { \
494         /* Allowable datatypes */ \
495         MPIR_Assert((dtype_) == MPI_UNSIGNED || (dtype_) == MPI_UNSIGNED_LONG || \
496                     (dtype_) == MPI_UNSIGNED_LONG_LONG || (dtype_) == MPI_DOUBLE); \
497         MPIR_Assert((flags_) & MPIR_T_PVAR_FLAG_CONTINUOUS); \
498         MPIR_Assert((addr_) != NULL || (get_value_) != NULL); \
499         MPIR_T_PVAR_REGISTER_impl(MPI_T_PVAR_CLASS_SIZE, dtype_, #name_, \
500             addr_, count_, MPI_T_ENUM_NULL, verb_, bind_, flags_, get_value_, \
501             get_count_, cat_, desc_); \
502     } while (0)
503 
504 
505 /* MPI_T_PVAR_CLASS_PERCENTAGE (continuous only)
506  */
507 
508 /* Interfaces through pointer or name */
509 #define MPIR_T_PVAR_PERCENTAGE_SET_VAR_impl(ptr_, val_) \
510     do { \
511         MPIR_Assert(0.0 <= (val_) && (val_) <= 1.0); \
512         *(ptr_) = (val_); \
513     } while (0)
514 #define MPIR_T_PVAR_PERCENTAGE_GET_VAR_impl(ptr_) \
515     (*(ptr_))
516 
517 #define MPIR_T_PVAR_PERCENTAGE_SET_impl(name_, val_) \
518     MPIR_T_PVAR_PERCENTAGE_SET_VAR_impl(&PVAR_PERCENTAGE_##name_, val_)
519 #define MPIR_T_PVAR_PERCENTAGE_GET_impl(name_) \
520     MPIR_T_PVAR_PERCENTAGE_GET_VAR_impl(&PVAR_PERCENTAGE_##name_)
521 
522 /* Registration AND initialization for static pvar */
523 #define MPIR_T_PVAR_PERCENTAGE_REGISTER_STATIC_impl(dtype_, name_, \
524             initval_, verb_, bind_, flags_, cat_, desc_) \
525     do { \
526         void *addr_; \
527         /* Allowable datatypes only */ \
528         MPIR_Assert((dtype_) == MPI_DOUBLE); \
529         /* Double check if dtype_ and name_ match */ \
530         MPIR_Assert(sizeof(PVAR_PERCENTAGE_##name_) == MPIR_Datatype_get_basic_size(dtype_)); \
531         MPIR_Assert((flags_) & MPIR_T_PVAR_FLAG_CONTINUOUS); \
532         addr_ = &PVAR_PERCENTAGE_##name_; \
533         PVAR_PERCENTAGE_##name_ = (initval_); \
534         MPIR_T_PVAR_REGISTER_impl(MPI_T_PVAR_CLASS_PERCENTAGE, dtype_, #name_, \
535             addr_, 1, MPI_T_ENUM_NULL, verb_, bind_, flags_, NULL, NULL, cat_, desc_); \
536     } while (0)
537 
538 /* Registration for dynamic pvar w/ or w/o callback. Init is left to users */
539 #define MPIR_T_PVAR_PERCENTAGE_REGISTER_DYNAMIC_impl(dtype_, name_, \
540             addr_, count_, verb_, bind_, flags_, get_value_, get_count_, cat_, desc_) \
541     do { \
542         /* Allowable datatypes */ \
543         MPIR_Assert((dtype_) == MPI_DOUBLE); \
544         MPIR_Assert((flags_) & MPIR_T_PVAR_FLAG_CONTINUOUS); \
545         MPIR_Assert((addr_) != NULL || (get_value_) != NULL); \
546         MPIR_T_PVAR_REGISTER_impl(MPI_T_PVAR_CLASS_PERCENTAGE, dtype_, #name_, \
547             addr_, count_, MPI_T_ENUM_NULL, verb_, bind_, flags_, get_value_, \
548             get_count_, cat_, desc_); \
549     } while (0)
550 
551 
552 /* MPI_T_PVAR_CLASS_COUNTER (continuous or not)
553  */
554 
555 /* Interfaces through pointer or name */
556 #define MPIR_T_PVAR_COUNTER_INIT_VAR_impl(ptr_) \
557     do { *(ptr_) = 0; } while (0)
558 /* _COUNTER_SET is intentionally not provided. Users should only INC counters */
559 #define MPIR_T_PVAR_COUNTER_GET_VAR_impl(ptr_) \
560     (*(ptr_))
561 #define MPIR_T_PVAR_COUNTER_INC_VAR_impl(ptr_, inc_) \
562     do { *(ptr_) += (inc_); } while (0)
563 
564 #define MPIR_T_PVAR_COUNTER_INIT_impl(name_) \
565     MPIR_T_PVAR_COUNTER_INIT_VAR_impl(&PVAR_COUNTER_##name_)
566 #define MPIR_T_PVAR_COUNTER_GET_impl(name_) \
567     MPIR_T_PVAR_COUNTER_GET_VAR_impl(&PVAR_COUNTER_##name_)
568 #define MPIR_T_PVAR_COUNTER_INC_impl(name_, inc_) \
569     MPIR_T_PVAR_COUNTER_INC_VAR_impl(&PVAR_COUNTER_##name_, inc_)
570 #define MPIR_T_PVAR_COUNTER_ADDR_impl(name_) \
571     (&PVAR_COUNTER_##name_)
572 
573 /* Registration AND initialization to zero for static pvar.  */
574 #define MPIR_T_PVAR_COUNTER_REGISTER_STATIC_impl(dtype_, name_, \
575             verb_, bind_, flags_, cat_, desc_) \
576     do { \
577         void *addr_; \
578         /* Allowable datatypes only */ \
579         MPIR_Assert((dtype_) == MPI_UNSIGNED || (dtype_) == MPI_UNSIGNED_LONG || \
580                     (dtype_) == MPI_UNSIGNED_LONG_LONG); \
581         /* Double check if dtype_ and name_ match*/ \
582         MPIR_Assert(sizeof(PVAR_COUNTER_##name_) == MPIR_Datatype_get_basic_size(dtype_)); \
583         PVAR_COUNTER_##name_ = 0; \
584         addr_ = &PVAR_COUNTER_##name_; \
585         MPIR_T_PVAR_REGISTER_impl(MPI_T_PVAR_CLASS_COUNTER, dtype_, #name_, \
586             addr_, 1, MPI_T_ENUM_NULL, verb_, bind_, flags_, NULL, NULL, cat_, desc_); \
587     } while (0)
588 
589 /* Registration for dynamic pvar w/ or w/o callback. Init is left to users */
590 #define MPIR_T_PVAR_COUNTER_REGISTER_DYNAMIC_impl(dtype_, name_, \
591             addr_, count_, verb_, bind_, flags_, get_value_, get_count_, cat_, desc_) \
592     do { \
593         /* Allowable datatypes */ \
594         MPIR_Assert((dtype_) == MPI_UNSIGNED || (dtype_) == MPI_UNSIGNED_LONG || \
595                     (dtype_) == MPI_UNSIGNED_LONG_LONG); \
596         MPIR_Assert((addr_) != NULL || (get_value_) != NULL); \
597         MPIR_T_PVAR_REGISTER_impl(MPI_T_PVAR_CLASS_COUNTER, dtype_, #name_, \
598             addr_, count_, MPI_T_ENUM_NULL, verb_, bind_, flags_, get_value_, \
599             get_count_, cat_, desc_); \
600     } while (0)
601 
602 /* Interfaces through pointer or name */
603 #define MPIR_T_PVAR_COUNTER_ARRAY_INIT_VAR_impl(ptr_, count_) \
604     do { \
605         int idx_; \
606         idx_ = 0; \
607         for (; idx_ < (count_); idx_++) \
608             *((ptr_) + idx_) = 0; \
609     } while (0)
610 #define MPIR_T_PVAR_COUNTER_ARRAY_GET_VAR_impl(ptr_, idx_) \
611     *((ptr_) + (idx_))
612 #define MPIR_T_PVAR_COUNTER_ARRAY_INC_VAR_impl(ptr_, idx_, inc_) \
613     do { *((ptr_) + (idx_)) += (inc_); } while (0)
614 
615 #define MPIR_T_PVAR_COUNTER_ARRAY_INIT_impl(name_) \
616     do { \
617         int count_; \
618         count_ = sizeof(PVAR_COUNTER_##name_)/sizeof(PVAR_COUNTER_##name_[0]); \
619         MPIR_T_PVAR_COUNTER_ARRAY_INIT_VAR_impl(PVAR_COUNTER_##name_, count_); \
620     } while (0)
621 #define MPIR_T_PVAR_COUNTER_ARRAY_GET_impl(name_, idx_) \
622     MPIR_T_PVAR_COUNTER_ARRAY_GET_VAR_impl(PVAR_COUNTER_##name_, idx_)
623 #define MPIR_T_PVAR_COUNTER_ARRAY_INC_impl(ptr_, idx_, inc_) \
624     MPIR_T_PVAR_COUNTER_ARRAY_INC_VAR_impl(PVAR_COUNTER_##name_, idx_, inc_)
625 
626 /* Registration AND initialization to zero for static counter array  */
627 #define MPIR_T_PVAR_COUNTER_ARRAY_REGISTER_STATIC_impl(dtype_, name_, \
628             verb_, bind_, flags_, cat_, desc_) \
629     do { \
630         void *addr_; \
631         int count_;  \
632         /* Allowable datatypes only */ \
633         MPIR_Assert((dtype_) == MPI_UNSIGNED || (dtype_) == MPI_UNSIGNED_LONG || \
634                     (dtype_) == MPI_UNSIGNED_LONG_LONG); \
635         /* Double check if dtype_ and name_ match */ \
636         MPIR_Assert(sizeof(PVAR_COUNTER_##name_[0]) == MPIR_Datatype_get_basic_size(dtype_)); \
637         addr_ = PVAR_COUNTER_##name_; \
638         MPIR_T_PVAR_COUNTER_ARRAY_INIT_impl(name_); \
639         count_ = sizeof(PVAR_COUNTER_##name_)/sizeof(PVAR_COUNTER_##name_[0]); \
640         MPIR_T_PVAR_REGISTER_impl(MPI_T_PVAR_CLASS_COUNTER, dtype_, #name_, \
641             addr_, count_, MPI_T_ENUM_NULL, verb_, bind_, flags_, NULL, NULL, cat_, desc_); \
642     } while (0)
643 
644 /* Dynamic counter array is already provided by MPIR_T_PVAR_COUNTER_REGISTER_DYNAMIC */
645 
646 /* MPI_T_PVAR_CLASS_AGGREGATE (continuous or not)
647  */
648 
649 /* Interfaces through pointer or name */
650 #define MPIR_T_PVAR_AGGREGATE_INIT_VAR_impl(ptr_) \
651     do { *(ptr_) = 0; } while (0)
652 /* _AGGREGATE_SET is intentionally not provided as for counters */
653 #define MPIR_T_PVAR_AGGREGATE_GET_VAR_impl(ptr_) \
654     (*(ptr_))
655 #define MPIR_T_PVAR_AGGREGATE_INC_VAR_impl(ptr_, inc_) \
656     do { *(ptr_) += (inc_); } while (0)
657 
658 #define MPIR_T_PVAR_AGGREGATE_INIT_impl(name_) \
659     MPIR_T_PVAR_AGGREGATE_INIT_VAR_impl(&PVAR_AGGREGATE_##name_)
660 #define MPIR_T_PVAR_AGGREGATE_GET_impl(name_) \
661     MPIR_T_PVAR_AGGREGATE_GET_VAR_impl(&PVAR_AGGREGATE_##name_)
662 #define MPIR_T_PVAR_AGGREGATE_INC_impl(name_, inc_) \
663     MPIR_T_PVAR_AGGREGATE_INC_VAR_impl(&PVAR_AGGREGATE_##name_, inc_)
664 
665 /* Registration AND initialization to zero for static aggregate  */
666 #define MPIR_T_PVAR_AGGREGATE_REGISTER_STATIC_impl(dtype_, name_, \
667             verb_, bind_, flags_, cat_, desc_) \
668     do { \
669         void *addr; \
670         /* Allowable datatypes only */ \
671         MPIR_Assert((dtype_) == MPI_UNSIGNED || (dtype_) == MPI_UNSIGNED_LONG || \
672                     (dtype_) == MPI_UNSIGNED_LONG_LONG || (dtype_) == MPI_DOUBLE); \
673         /* Double check if dtype_ and name_ match*/ \
674         MPIR_Assert(sizeof(PVAR_AGGREGATE_##name_) == MPIR_Datatype_get_basic_size(dtype_)); \
675         PVAR_AGGREGATE_##name_ = 0; \
676         addr_ = &PVAR_AGGREGATE_##name_; \
677         MPIR_T_PVAR_REGISTER_impl(MPI_T_PVAR_CLASS_AGGREGATE, dtype_, #name_, \
678             addr_, 1, MPI_T_ENUM_NULL, verb_, bind_, flags_, NULL, NULL, cat_, desc_); \
679     } while (0)
680 
681 /* Registration for dynamic pvar w/ or w/o callback. Init is left to users */
682 #define MPIR_T_PVAR_AGGREGATE_REGISTER_DYNAMIC_impl(dtype_, name_, \
683             addr_, count_, verb_, bind_, flags_, get_value_, get_count_, cat_, desc_) \
684     do { \
685         /* Allowable datatypes */ \
686         MPIR_Assert((dtype_) == MPI_UNSIGNED || (dtype_) == MPI_UNSIGNED_LONG || \
687                     (dtype_) == MPI_UNSIGNED_LONG_LONG || (dtype_) == MPI_DOUBLE); \
688         MPIR_Assert((addr_) != NULL || (get_value_) != NULL); \
689         MPIR_T_PVAR_REGISTER_impl(MPI_T_PVAR_CLASS_AGGREGATE, dtype_, #name_, \
690             addr_, count_, MPI_T_ENUM_NULL, verb_, bind_, flags_, get_value_, \
691             get_count_, cat_, desc_); \
692     } while (0)
693 
694 
695 /* MPI_T_PVAR_CLASS_TIMER (continuous or not)
696  */
697 
698 /* Interfaces through pointer or name */
699 #define MPIR_T_PVAR_TIMER_INIT_VAR_impl(ptr_) \
700     do { \
701         /* FIXME: need a generic approach to init a timer */ \
702         memset(&((ptr_)->total), 0, sizeof(MPL_time_t)); \
703     } while (0)
704 #define MPIR_T_PVAR_TIMER_GET_VAR_impl(ptr_, buf) \
705     do { \
706         MPL_wtime_todouble(&((ptr_)->total), buf); \
707     } while (0)
708 #define MPIR_T_PVAR_TIMER_START_VAR_impl(ptr_) \
709     do { \
710         MPL_wtime(&((ptr_)->curstart)); \
711         (ptr_)->count++; \
712     } while (0)
713 #define MPIR_T_PVAR_TIMER_END_VAR_impl(ptr_) \
714     do { \
715         MPL_time_t tmp_; \
716         MPL_wtime(&tmp_); \
717         MPL_wtime_acc(&((ptr_)->curstart), &tmp_, &((ptr_)->total)); \
718     } while (0)
719 
720 #define MPIR_T_PVAR_TIMER_INIT_impl(name_) \
721     MPIR_T_PVAR_TIMER_INIT_VAR_impl(&PVAR_TIMER_##name_)
722 #define MPIR_T_PVAR_TIMER_GET_impl(name_, buf_) \
723     MPIR_T_PVAR_TIMER_GET_VAR_impl(&PVAR_TIMER_##name_, buf_)
724 #define MPIR_T_PVAR_TIMER_START_impl(name_) \
725     MPIR_T_PVAR_TIMER_START_VAR_impl(&PVAR_TIMER_##name_)
726 #define MPIR_T_PVAR_TIMER_END_impl(name_) \
727     MPIR_T_PVAR_TIMER_END_VAR_impl(&PVAR_TIMER_##name_)
728 #define MPIR_T_PVAR_TIMER_ADDR_impl(name_) \
729     (&PVAR_TIMER_##name_)
730 
731 /* Customized get_value() for MPIR_T_pvar_timer_t */
732 static inline
get_timer_time_in_double(MPIR_T_pvar_timer_t * timer,void * obj_handle,int count,double * buf)733     void get_timer_time_in_double(MPIR_T_pvar_timer_t * timer, void *obj_handle,
734                                   int count, double *buf)
735 {
736     int i;
737     for (i = 0; i < count; i++)
738         MPL_wtime_todouble(&(timer[i].total), &buf[i]);
739 }
740 
741 /* Registration for static storage */
742 #define MPIR_T_PVAR_TIMER_REGISTER_STATIC_impl(dtype_, name_, \
743             verb_, bind_, flags_, cat_, desc_) \
744     do { \
745         void *addr_; \
746         void *count_addr_; \
747         /* Allowable datatypes only */ \
748         MPIR_Assert((dtype_) == MPI_DOUBLE); \
749         MPIR_T_PVAR_TIMER_INIT_impl(name_); \
750         addr_ = &PVAR_TIMER_##name_; \
751         count_addr_ = &(PVAR_TIMER_##name_.count); \
752         MPIR_T_PVAR_REGISTER_impl(MPI_T_PVAR_CLASS_TIMER, dtype_, #name_, \
753             addr_, 1, MPI_T_ENUM_NULL, verb_, bind_, flags_, \
754             (MPIR_T_pvar_get_value_cb *)&get_timer_time_in_double, NULL, cat_, desc_); \
755         MPIR_T_PVAR_REGISTER_impl(MPI_T_PVAR_CLASS_COUNTER, MPI_UNSIGNED_LONG_LONG, #name_, \
756             count_addr_, 1, MPI_T_ENUM_NULL, verb_, bind_, flags_, \
757             NULL, NULL, cat_, desc_); \
758     } while (0)
759 
760 
761 /* MPI_T_PVAR_CLASS_HIGHWATERMARK (continuous or not)
762  */
763 
764 /* Interfaces through pointer or name.
765  * In contrast to previous pvar classes, for each type we create a set
766  * of interfaces. That is because we have a pointer and a union in the
767  * struct. We need to know types to (de)reference them.
768 */
769 #define MPIR_T_PVAR_UINT_HIGHWATERMARK_INIT_VAR_impl(ptr_, val_) \
770     do { \
771         (ptr_)->datatype = MPI_UNSIGNED; \
772         (ptr_)->current.u = (val_); \
773         (ptr_)->first_started = 0;    \
774         (ptr_)->first_used = 0; \
775         (ptr_)->hlist = NULL;  \
776     } while (0)
777 
778 #define MPIR_T_PVAR_ULONG_HIGHWATERMARK_INIT_VAR_impl(ptr_, val_) \
779     do { \
780         (ptr_)->datatype = MPI_UNSIGNED_LONG; \
781         (ptr_)->current.ul = (val_); \
782         (ptr_)->first_started = 0;    \
783         (ptr_)->first_used = 0; \
784         (ptr_)->hlist = NULL;  \
785     } while (0)
786 
787 #define MPIR_T_PVAR_ULONG2_HIGHWATERMARK_INIT_VAR_impl(ptr_, val_) \
788     do { \
789         (ptr_)->datatype = MPI_UNSIGNED_LONG_LONG; \
790         (ptr_)->current.ull = (val_); \
791         (ptr_)->first_started = 0;    \
792         (ptr_)->first_used = 0; \
793         (ptr_)->hlist = NULL;  \
794     } while (0)
795 
796 #define MPIR_T_PVAR_DOUBLE_HIGHWATERMARK_INIT_VAR_impl(ptr_, val_) \
797     do { \
798         (ptr_)->datatype = MPI_DOUBLE; \
799         (ptr_)->current.f = (val_); \
800         (ptr_)->first_started = 0;    \
801         (ptr_)->first_used = 0; \
802         (ptr_)->hlist = NULL;  \
803     } while (0)
804 
805 #define MPIR_T_PVAR_UINT_HIGHWATERMARK_UPDATE_VAR_impl(ptr_, val_) \
806     do { \
807         MPIR_T_pvar_handle_t *head; \
808         (ptr_)->current.u = (val_); \
809         if ((ptr_)->first_used && (ptr_)->first_started) { \
810             if ((val_) > (ptr_)->watermark.u) \
811                 (ptr_)->watermark.u = (val_); \
812         } \
813         head = (ptr_)->hlist; \
814         while (head != NULL) { \
815             if (MPIR_T_pvar_is_started(head) && (val_) > head->watermark.u) { \
816                 head->watermark.u = (val_); \
817             } \
818             head = head->next2; \
819         } \
820     } while (0)
821 
822 #define MPIR_T_PVAR_ULONG_HIGHWATERMARK_UPDATE_VAR_impl(ptr_, val_) \
823     do { \
824         MPIR_T_pvar_handle_t *head; \
825         (ptr_)->current.ul = (val_); \
826         if ((ptr_)->first_used && (ptr_)->first_started) { \
827             if ((val_) > (ptr_)->watermark.ul) \
828                 (ptr_)->watermark.ul = (val_); \
829         } \
830         head = (ptr_)->hlist; \
831         while (head != NULL) { \
832             if (MPIR_T_pvar_is_started(head) && (val_) > head->watermark.ul) { \
833                 head->watermark.ul = (val_); \
834             } \
835             head = head->next2; \
836         } \
837     } while (0)
838 
839 #define MPIR_T_PVAR_ULONG2_HIGHWATERMARK_UPDATE_VAR_impl(ptr_, val_) \
840     do { \
841         MPIR_T_pvar_handle_t *head; \
842         (ptr_)->current.ull = (val_); \
843         if ((ptr_)->first_used && (ptr_)->first_started) { \
844             if ((val_) > (ptr_)->watermark.ull) \
845                 (ptr_)->watermark.ull = (val_); \
846         } \
847         head = (ptr_)->hlist; \
848         while (head != NULL) { \
849             if (MPIR_T_pvar_is_started(head) && (val_) > head->watermark.ull) { \
850                 head->watermark.ull = (val_); \
851             } \
852             head = head->next2; \
853         } \
854     } while (0)
855 
856 #define MPIR_T_PVAR_DOUBLE_HIGHWATERMARK_UPDATE_VAR_impl(ptr_, val_) \
857     do { \
858         MPIR_T_pvar_handle_t *head; \
859         (ptr_)->current.f = (val_); \
860         if ((ptr_)->first_used && (ptr_)->first_started) { \
861             if ((val_) > (ptr_)->watermark.f) \
862                 (ptr_)->watermark.f = (val_); \
863         } \
864         head = (ptr_)->hlist; \
865         while (head != NULL) { \
866             if (MPIR_T_pvar_is_started(head) && (val_) > head->watermark.f) { \
867                 head->watermark.f = (val_); \
868             } \
869             head = head->next2; \
870         } \
871     } while (0)
872 
873 #define MPIR_T_PVAR_UINT_HIGHWATERMARK_INIT_impl(name_, val_) \
874     MPIR_T_PVAR_UINT_HIGHWATERMARK_INIT_VAR_impl(&PVAR_HIGHWATERMARK_##name_, val_)
875 #define MPIR_T_PVAR_ULONG_HIGHWATERMARK_INIT_impl(name_, val_) \
876     MPIR_T_PVAR_ULONG_HIGHWATERMARK_INIT_VAR_impl(&PVAR_HIGHWATERMARK_##name_, val_)
877 #define MPIR_T_PVAR_ULONG2_HIGHWATERMARK_INIT_impl(name_, val_) \
878     MPIR_T_PVAR_ULONG2_HIGHWATERMARK_INIT_VAR_impl(&PVAR_HIGHWATERMARK_##name_, val_)
879 #define MPIR_T_PVAR_DOUBLE_HIGHWATERMARK_INIT_impl(name_, val_) \
880     MPIR_T_PVAR_DOUBLE_HIGHWATERMARK_INIT_VAR_impl(&PVAR_HIGHWATERMARK_##name_, val_)
881 
882 #define MPIR_T_PVAR_UINT_HIGHWATERMARK_UPDATE_impl(name_, val_) \
883     MPIR_T_PVAR_UINT_HIGHWATERMARK_UPDATE_VAR_impl(&PVAR_HIGHWATERMARK_##name_, val_)
884 #define MPIR_T_PVAR_ULONG_HIGHWATERMARK_UPDATE_impl(name_, val_) \
885     MPIR_T_PVAR_ULONG_HIGHWATERMARK_UPDATE_VAR_impl(&PVAR_HIGHWATERMARK_##name_, val_)
886 #define MPIR_T_PVAR_ULONG2_HIGHWATERMARK_UPDATE_impl(name_, val_) \
887     MPIR_T_PVAR_ULONG2_HIGHWATERMARK_UPDATE_VAR_impl(&PVAR_HIGHWATERMARK_##name_, val_)
888 #define MPIR_T_PVAR_DOUBLE_HIGHWATERMARK_UPDATE_impl(name_, val_) \
889     MPIR_T_PVAR_DOUBLE_HIGHWATERMARK_UPDATE_VAR_impl(&PVAR_HIGHWATERMARK_##name_, val_)
890 
891 /* Registration AND initialization for static pvar  */
892 #define MPIR_T_PVAR_HIGHWATERMARK_REGISTER_STATIC_impl(dtype_, name_, \
893             initval_, verb_, bind_, flags_, cat_, desc_) \
894     do { \
895         void *addr_; \
896         /* Allowable datatypes only */ \
897         MPIR_Assert((dtype_) == MPI_UNSIGNED || (dtype_) == MPI_UNSIGNED_LONG || \
898                     (dtype_) == MPI_UNSIGNED_LONG_LONG || (dtype_) == MPI_DOUBLE); \
899         switch (dtype_) { \
900         case MPI_UNSIGNED: \
901             MPIR_T_PVAR_UINT_HIGHWATERMARK_INIT_impl(name_, initval_); break; \
902         case MPI_UNSIGNED_LONG: \
903             MPIR_T_PVAR_ULONG_HIGHWATERMARK_INIT_impl(name_, initval_); break; \
904         case MPI_UNSIGNED_LONG_LONG: \
905             MPIR_T_PVAR_ULONG2_HIGHWATERMARK_INIT_impl(name_, initval_); break; \
906         case MPI_DOUBLE: \
907             MPIR_T_PVAR_DOUBLE_HIGHWATERMARK_INIT_impl(name_, initval_); break; \
908         default: \
909             break; \
910         }; \
911         addr_ = &PVAR_HIGHWATERMARK_##name_; \
912         MPIR_T_PVAR_REGISTER_impl(MPI_T_PVAR_CLASS_HIGHWATERMARK, dtype_, #name_, \
913             addr_, 1, MPI_T_ENUM_NULL, verb_, bind_, flags_, NULL, NULL, cat_, desc_); \
914     } while (0)
915 
916 /* Registration for dynamic pvar w/ or w/o callback. Init is left to users */
917 #define MPIR_T_PVAR_HIGHWATERMARK_REGISTER_DYNAMIC_impl(dtype_, name_, \
918             addr_, count_, verb_, bind_, flags_, get_value_, get_count_, cat_, desc_) \
919     do { \
920         /* Allowable datatypes */ \
921         MPIR_Assert((dtype_) == MPI_UNSIGNED || (dtype_) == MPI_UNSIGNED_LONG || \
922                     (dtype_) == MPI_UNSIGNED_LONG_LONG || (dtype_) == MPI_DOUBLE); \
923         MPIR_Assert((addr_) != NULL || (get_value_) != NULL); \
924         MPIR_T_PVAR_REGISTER_impl(MPI_T_PVAR_CLASS_HIGHWATERMARK, dtype_, #name_, \
925             addr_, count_, MPI_T_ENUM_NULL, verb_, bind_, flags_, get_value_, \
926             get_count_, cat_, desc_); \
927     } while (0)
928 
929 
930 /* MPI_T_PVAR_CLASS_LOWWATERMARK (continuous or not)
931  */
932 
933 #define MPIR_T_PVAR_UINT_LOWWATERMARK_INIT_VAR_impl(ptr_, val_) \
934     do { \
935         (ptr_)->datatype = MPI_UNSIGNED; \
936         (ptr_)->current.u = (val_); \
937         (ptr_)->first_started = 0;    \
938         (ptr_)->first_used = 0; \
939         (ptr_)->hlist = NULL;  \
940     } while (0)
941 
942 #define MPIR_T_PVAR_ULONG_LOWWATERMARK_INIT_VAR_impl(ptr_, val_) \
943     do { \
944         (ptr_)->datatype = MPI_UNSIGNED_LONG; \
945         (ptr_)->current.ul = (val_); \
946         (ptr_)->first_started = 0;    \
947         (ptr_)->first_used = 0; \
948         (ptr_)->hlist = NULL;  \
949     } while (0)
950 
951 #define MPIR_T_PVAR_ULONG2_LOWWATERMARK_INIT_VAR_impl(ptr_, val_) \
952     do { \
953         (ptr_)->datatype = MPI_UNSIGNED_LONG_LONG; \
954         (ptr_)->current.ull = (val_); \
955         (ptr_)->first_started = 0;    \
956         (ptr_)->first_used = 0; \
957         (ptr_)->hlist = NULL;  \
958     } while (0)
959 
960 #define MPIR_T_PVAR_DOUBLE_LOWWATERMARK_INIT_VAR_impl(ptr_, val_) \
961     do { \
962         (ptr_)->datatype = MPI_DOUBLE; \
963         (ptr_)->current.f = (val_); \
964         (ptr_)->first_started = 0;    \
965         (ptr_)->first_used = 0; \
966         (ptr_)->hlist = NULL;  \
967     } while (0)
968 
969 #define MPIR_T_PVAR_UINT_LOWWATERMARK_UPDATE_VAR_impl(ptr_, val_) \
970     do { \
971         MPIR_T_pvar_handle_t *head; \
972         (ptr_)->current.u = (val_); \
973         /* Update values in all handles */ \
974         if ((ptr_)->first_used && (ptr_)->first_started) { \
975             if ((val_) < (ptr_)->watermark.u) \
976                 (ptr_)->watermark.u = (val_); \
977         } \
978         head = (ptr_)->hlist; \
979         while (head != NULL) { \
980             if (MPIR_T_pvar_is_started(head) && (val_) < head->watermark.u) { \
981                 head->watermark.u = (val_); \
982             } \
983             head = head->next2; \
984         } \
985     } while (0)
986 
987 #define MPIR_T_PVAR_ULONG_LOWWATERMARK_UPDATE_VAR_impl(ptr_, val_) \
988     do { \
989         MPIR_T_pvar_handle_t *head; \
990         (ptr_)->current.ul = (val_); \
991         if ((ptr_)->first_used && (ptr_)->first_started) { \
992             if ((val_) < (ptr_)->watermark.ul) \
993                 (ptr_)->watermark.ul = (val_); \
994         } \
995         head = (ptr_)->hlist; \
996         while (head != NULL) { \
997             if (MPIR_T_pvar_is_started(head) && (val_) < head->watermark.ul) { \
998                 head->watermark.ul = (val_); \
999             } \
1000             head = head->next2; \
1001         } \
1002     } while (0)
1003 
1004 #define MPIR_T_PVAR_ULONG2_LOWWATERMARK_UPDATE_VAR_impl(ptr_, val_) \
1005     do { \
1006         MPIR_T_pvar_handle_t *head; \
1007         (ptr_)->current.ull = (val_); \
1008         if ((ptr_)->first_used && (ptr_)->first_started) { \
1009             if ((val_) < (ptr_)->watermark.ull) \
1010                 (ptr_)->watermark.ull = (val_); \
1011         } \
1012         head = (ptr_)->hlist; \
1013         while (head != NULL) { \
1014             if (MPIR_T_pvar_is_started(head) && (val_) < head->watermark.ull) { \
1015                 head->watermark.ull = (val_); \
1016             } \
1017             head = head->next2; \
1018         } \
1019     } while (0)
1020 
1021 #define MPIR_T_PVAR_DOUBLE_LOWWATERMARK_UPDATE_VAR_impl(ptr_, val_) \
1022     do { \
1023         MPIR_T_pvar_handle_t *head; \
1024         (ptr_)->current.f = (val_); \
1025         if ((ptr_)->first_used && (ptr_)->first_started) { \
1026             if ((val_) < (ptr_)->watermark.f) \
1027                 (ptr_)->watermark.f = (val_); \
1028         } \
1029         head = (ptr_)->hlist; \
1030         while (head != NULL) { \
1031             if (MPIR_T_pvar_is_started(head) && (val_) < head->watermark.f) { \
1032                 head->watermark.f = (val_); \
1033             } \
1034             head = head->next2; \
1035         } \
1036     } while (0)
1037 
1038 #define MPIR_T_PVAR_UINT_LOWWATERMARK_INIT_impl(name_, val_) \
1039     MPIR_T_PVAR_UINT_LOWWATERMARK_INIT_VAR_impl(&PVAR_LOWWATERMARK_##name_, val_)
1040 #define MPIR_T_PVAR_ULONG_LOWWATERMARK_INIT_impl(name_, val_) \
1041     MPIR_T_PVAR_ULONG_LOWWATERMARK_INIT_VAR_impl(&PVAR_LOWWATERMARK_##name_, val_)
1042 #define MPIR_T_PVAR_ULONG2_LOWWATERMARK_INIT_impl(name_, val_) \
1043     MPIR_T_PVAR_ULONG2_LOWWATERMARK_INIT_VAR_impl(&PVAR_LOWWATERMARK_##name_, val_)
1044 #define MPIR_T_PVAR_DOUBLE_LOWWATERMARK_INIT_impl(name_, val_) \
1045     MPIR_T_PVAR_DOUBLE_LOWWATERMARK_INIT_VAR_impl(&PVAR_LOWWATERMARK_##name_, val_)
1046 
1047 #define MPIR_T_PVAR_UINT_LOWWATERMARK_UPDATE_impl(name_, val_) \
1048     MPIR_T_PVAR_UINT_LOWWATERMARK_UPDATE_VAR_impl(&PVAR_LOWWATERMARK_##name_, val_)
1049 #define MPIR_T_PVAR_ULONG_LOWWATERMARK_UPDATE_impl(name_, val_) \
1050     MPIR_T_PVAR_ULONG_LOWWATERMARK_UPDATE_VAR_impl(&PVAR_LOWWATERMARK_##name_, val_)
1051 #define MPIR_T_PVAR_ULONG2_LOWWATERMARK_UPDATE_impl(name_, val_) \
1052     MPIR_T_PVAR_ULONG2_LOWWATERMARK_UPDATE_VAR_impl(&PVAR_LOWWATERMARK_##name_, val_)
1053 #define MPIR_T_PVAR_DOUBLE_LOWWATERMARK_UPDATE_impl(name_, val_) \
1054     MPIR_T_PVAR_DOUBLE_LOWWATERMARK_UPDATE_VAR_impl(&PVAR_LOWWATERMARK_##name_, val_)
1055 
1056 /* Registration AND initialization for static pvar  */
1057 #define MPIR_T_PVAR_LOWWATERMARK_REGISTER_STATIC_impl(dtype_, name_, \
1058             initval_, verb_, bind_, flags_, cat_, desc_) \
1059     do { \
1060         void *addr_; \
1061         /* Allowable datatypes only */ \
1062         MPIR_Assert((dtype_) == MPI_UNSIGNED || (dtype_) == MPI_UNSIGNED_LONG || \
1063                     (dtype_) == MPI_UNSIGNED_LONG_LONG || (dtype_) == MPI_DOUBLE); \
1064         switch (dtype_) { \
1065         case MPI_UNSIGNED: \
1066             MPIR_T_PVAR_UINT_LOWWATERMARK_INIT_impl(name_, initval_); break; \
1067         case MPI_UNSIGNED_LONG: \
1068             MPIR_T_PVAR_ULONG_LOWWATERMARK_INIT_impl(name_, initval_); break; \
1069         case MPI_UNSIGNED_LONG_LONG: \
1070             MPIR_T_PVAR_ULONG2_LOWWATERMARK_INIT_impl(name_, initval_); break; \
1071         case MPI_DOUBLE: \
1072             MPIR_T_PVAR_DOUBLE_LOWWATERMARK_INIT_impl(name_, initval_); break; \
1073         default: \
1074             break; \
1075         }; \
1076         addr_ = &PVAR_LOWWATERMARK_##name_; \
1077         MPIR_T_PVAR_REGISTER_impl(MPI_T_PVAR_CLASS_LOWWATERMARK, dtype_, #name_, \
1078             addr_, 1, MPI_T_ENUM_NULL, verb_, bind_, flags_, NULL, NULL, cat_, desc_); \
1079     } while (0)
1080 
1081 /* Registration for dynamic pvar w/ or w/o callback. Init is left to users */
1082 #define MPIR_T_PVAR_LOWWATERMARK_REGISTER_DYNAMIC_impl(dtype_, name_, \
1083             addr_, count_, verb_, bind_, flags_, get_value_, get_count_, cat_, desc_) \
1084     do { \
1085         /* Allowable datatypes */ \
1086         MPIR_Assert((dtype_) == MPI_UNSIGNED || (dtype_) == MPI_UNSIGNED_LONG || \
1087                     (dtype_) == MPI_UNSIGNED_LONG_LONG || (dtype_) == MPI_DOUBLE); \
1088         MPIR_Assert((addr_) != NULL || (get_value_) != NULL); \
1089         MPIR_T_PVAR_REGISTER_impl(MPI_T_PVAR_CLASS_LOWWATERMARK, dtype_, #name_, \
1090             addr_, count_, MPI_T_ENUM_NULL, verb_, bind_, flags_, get_value_, \
1091             get_count_, cat_, desc_); \
1092     } while (0)
1093 
1094 /* Unregister a pvar by its index */
1095 #define MPIR_T_PVAR_UNREGISTER(idx_) \
1096     do { \
1097         if (pvar_table != NULL) { \
1098             pvar_table_entry_t *pvar = \
1099                 (pvar_table_entry_t *)utarray_eltptr(pvar_table, idx_); \
1100             if (pvar != NULL) { \
1101                 pvar->active = FALSE; \
1102                 /* Do not do MPL_free(pvar->info), since it may be re-activated */ \
1103             } \
1104         } \
1105     } while (0)
1106 
MPIR_T_pvar_is_readonly(MPIR_T_pvar_handle_t * handle)1107 static inline int MPIR_T_pvar_is_readonly(MPIR_T_pvar_handle_t * handle)
1108 {
1109     return handle->flags & MPIR_T_PVAR_FLAG_READONLY;
1110 }
1111 
MPIR_T_pvar_is_continuous(MPIR_T_pvar_handle_t * handle)1112 static inline int MPIR_T_pvar_is_continuous(MPIR_T_pvar_handle_t * handle)
1113 {
1114     return handle->flags & MPIR_T_PVAR_FLAG_CONTINUOUS;
1115 }
1116 
MPIR_T_pvar_is_atomic(MPIR_T_pvar_handle_t * handle)1117 static inline int MPIR_T_pvar_is_atomic(MPIR_T_pvar_handle_t * handle)
1118 {
1119     return handle->flags & MPIR_T_PVAR_FLAG_ATOMIC;
1120 }
1121 
MPIR_T_pvar_is_sum(MPIR_T_pvar_handle_t * handle)1122 static inline int MPIR_T_pvar_is_sum(MPIR_T_pvar_handle_t * handle)
1123 {
1124     return handle->flags & MPIR_T_PVAR_FLAG_SUM;
1125 }
1126 
MPIR_T_pvar_is_watermark(MPIR_T_pvar_handle_t * handle)1127 static inline int MPIR_T_pvar_is_watermark(MPIR_T_pvar_handle_t * handle)
1128 {
1129     return handle->flags & MPIR_T_PVAR_FLAG_WATERMARK;
1130 }
1131 
MPIR_T_pvar_is_started(MPIR_T_pvar_handle_t * handle)1132 static inline int MPIR_T_pvar_is_started(MPIR_T_pvar_handle_t * handle)
1133 {
1134     return handle->flags & MPIR_T_PVAR_FLAG_STARTED;
1135 }
1136 
MPIR_T_pvar_set_started(MPIR_T_pvar_handle_t * handle)1137 static inline void MPIR_T_pvar_set_started(MPIR_T_pvar_handle_t * handle)
1138 {
1139     handle->flags |= (MPIR_T_PVAR_FLAG_STARTED | MPIR_T_PVAR_FLAG_ONCESTARTED);
1140 }
1141 
MPIR_T_pvar_unset_started(MPIR_T_pvar_handle_t * handle)1142 static inline void MPIR_T_pvar_unset_started(MPIR_T_pvar_handle_t * handle)
1143 {
1144     handle->flags &= ~MPIR_T_PVAR_FLAG_STARTED;
1145 }
1146 
MPIR_T_pvar_is_oncestarted(MPIR_T_pvar_handle_t * handle)1147 static inline int MPIR_T_pvar_is_oncestarted(MPIR_T_pvar_handle_t * handle)
1148 {
1149     return handle->flags & MPIR_T_PVAR_FLAG_ONCESTARTED;
1150 }
1151 
MPIR_T_pvar_unset_oncestarted(MPIR_T_pvar_handle_t * handle)1152 static inline void MPIR_T_pvar_unset_oncestarted(MPIR_T_pvar_handle_t * handle)
1153 {
1154     handle->flags &= ~MPIR_T_PVAR_FLAG_ONCESTARTED;
1155 }
1156 
MPIR_T_pvar_is_first(MPIR_T_pvar_handle_t * handle)1157 static inline int MPIR_T_pvar_is_first(MPIR_T_pvar_handle_t * handle)
1158 {
1159     return handle->flags & MPIR_T_PVAR_FLAG_FIRST;
1160 }
1161 
MPIR_T_pvar_set_first(MPIR_T_pvar_handle_t * handle)1162 static inline int MPIR_T_pvar_set_first(MPIR_T_pvar_handle_t * handle)
1163 {
1164     return handle->flags |= MPIR_T_PVAR_FLAG_FIRST;
1165 }
1166 
MPIR_T_pvar_unset_first(MPIR_T_pvar_handle_t * handle)1167 static inline int MPIR_T_pvar_unset_first(MPIR_T_pvar_handle_t * handle)
1168 {
1169     return handle->flags &= ~MPIR_T_PVAR_FLAG_FIRST;
1170 }
1171 
1172 /* A counter that keeps track of the relative balance of calls to
1173  * MPI_T_init_thread and MPI_T_finalize */
1174 extern int MPIR_T_init_balance;
MPIR_T_is_initialized(void)1175 static inline int MPIR_T_is_initialized(void)
1176 {
1177     return MPIR_T_init_balance > 0;
1178 }
1179 
1180 /* A special strncpy to return strings in behavior defined by MPI_T */
1181 extern void MPIR_T_strncpy(char *dst, const char *src, int *len);
1182 
1183 /* Stuffs to support multithreaded MPI_T */
1184 extern int MPIR_T_is_threaded;
1185 #define MPIR_T_THREAD_CHECK_BEGIN if (MPIR_T_is_threaded) {
1186 #define MPIR_T_THREAD_CHECK_END }
1187 
1188 #ifdef MPICH_IS_THREADED
1189 extern MPID_Thread_mutex_t mpi_t_mutex;
1190 #define MPIR_T_THREAD_CS_INIT() \
1191     do { \
1192         int err_; \
1193         MPIR_T_THREAD_CHECK_BEGIN \
1194         MPID_Thread_init(&err_); \
1195         MPIR_Assert(err_ == 0); \
1196         MPID_Thread_mutex_create(&mpi_t_mutex, &err_); \
1197         MPIR_Assert(err_ == 0); \
1198         MPIR_T_THREAD_CHECK_END \
1199     } while (0)
1200 
1201 #define MPIR_T_THREAD_CS_FINALIZE() \
1202     do { \
1203         int err_; \
1204         MPIR_T_THREAD_CHECK_BEGIN \
1205         MPID_Thread_mutex_destroy(&mpi_t_mutex, &err_); \
1206         MPIR_Assert(err_ == 0); \
1207         MPID_Thread_finalize(&err_); \
1208         MPIR_Assert(err_ == 0); \
1209         MPIR_T_THREAD_CHECK_END \
1210     } while (0)
1211 
1212 #define MPIR_T_THREAD_CS_ENTER() \
1213     do { \
1214         int err;                              \
1215         MPIR_T_THREAD_CHECK_BEGIN             \
1216             MPID_Thread_mutex_lock(&mpi_t_mutex,&err);  \
1217         MPIR_T_THREAD_CHECK_END \
1218     } while (0)
1219 
1220 #define MPIR_T_THREAD_CS_EXIT() \
1221     do { \
1222         int err;                  \
1223         MPIR_T_THREAD_CHECK_BEGIN \
1224             MPID_Thread_mutex_unlock(&mpi_t_mutex,&err);  \
1225         MPIR_T_THREAD_CHECK_END \
1226     } while (0)
1227 #else /* !MPICH_IS_THREADED */
1228 #define MPIR_T_THREAD_CS_INIT()     do { /* nothing */ } while (0)
1229 #define MPIR_T_THREAD_CS_FINALIZE() do { /* nothing */ } while (0)
1230 #define MPIR_T_THREAD_CS_ENTER()    do { /* nothing */ } while (0)
1231 #define MPIR_T_THREAD_CS_EXIT()     do { /* nothing */ } while (0)
1232 #endif
1233 
1234 /* Init and finalize routines */
1235 extern int MPIR_T_env_init(void);
1236 extern void MPIR_T_env_finalize(void);
1237 
1238 #endif /* MPITIMPL_H_INCLUDED */
1239