1 /*
2  * Copyright (C) by Argonne National Laboratory
3  *     See COPYRIGHT in top-level directory
4  */
5 
6 #include "mpiimpl.h"
7 
8 /* -- Begin Profiling Symbol Block for routine MPI_T_pvar_read */
9 #if defined(HAVE_PRAGMA_WEAK)
10 #pragma weak MPI_T_pvar_read = PMPI_T_pvar_read
11 #elif defined(HAVE_PRAGMA_HP_SEC_DEF)
12 #pragma _HP_SECONDARY_DEF PMPI_T_pvar_read  MPI_T_pvar_read
13 #elif defined(HAVE_PRAGMA_CRI_DUP)
14 #pragma _CRI duplicate MPI_T_pvar_read as PMPI_T_pvar_read
15 #elif defined(HAVE_WEAK_ATTRIBUTE)
16 int MPI_T_pvar_read(MPI_T_pvar_session session, MPI_T_pvar_handle handle, void *buf)
17     __attribute__ ((weak, alias("PMPI_T_pvar_read")));
18 #endif
19 /* -- End Profiling Symbol Block */
20 
21 /* Define MPICH_MPI_FROM_PMPI if weak symbols are not supported to build
22    the MPI routines */
23 #ifndef MPICH_MPI_FROM_PMPI
24 #undef MPI_T_pvar_read
25 #define MPI_T_pvar_read PMPI_T_pvar_read
26 
27 /* any non-MPI functions go here, especially non-static ones */
28 
MPIR_T_pvar_read_impl(MPI_T_pvar_session session,MPI_T_pvar_handle handle,void * restrict buf)29 int MPIR_T_pvar_read_impl(MPI_T_pvar_session session, MPI_T_pvar_handle handle, void *restrict buf)
30 {
31     int i, mpi_errno = MPI_SUCCESS;
32 
33     /* Reading a never started pvar, or a stopped and then reset wartermark,
34      * will run into this nasty situation. MPI-3.0 did not define what error
35      * code should be returned. We returned a generic MPI error code. With MPI-3.1
36      * approved, we changed it to MPI_T_ERR_INVALID.
37      */
38     if (!MPIR_T_pvar_is_oncestarted(handle)) {
39         mpi_errno = MPI_T_ERR_INVALID;
40         goto fn_fail;
41     }
42 
43     /* For SUM pvars, return accum value + current value - offset value */
44     if (MPIR_T_pvar_is_sum(handle) && MPIR_T_pvar_is_started(handle)) {
45         if (handle->get_value == NULL) {
46             /* A running SUM without callback. Read its current value directly */
47             switch (handle->datatype) {
48                 case MPI_UNSIGNED_LONG_LONG:
49                     /* Put long long and double at front, since they are common */
50                     for (i = 0; i < handle->count; i++) {
51                         ((unsigned long long *) buf)[i] = ((unsigned long long *) handle->accum)[i]
52                             + ((unsigned long long *) handle->addr)[i]
53                             - ((unsigned long long *) handle->offset)[i];
54                     }
55                     break;
56                 case MPI_DOUBLE:
57                     for (i = 0; i < handle->count; i++) {
58                         ((double *) buf)[i] = ((double *) handle->accum)[i]
59                             + ((double *) handle->addr)[i]
60                             - ((double *) handle->offset)[i];
61                     }
62                     break;
63                 case MPI_UNSIGNED:
64                     for (i = 0; i < handle->count; i++) {
65                         ((unsigned *) buf)[i] = ((unsigned *) handle->accum)[i]
66                             + ((unsigned *) handle->addr)[i]
67                             - ((unsigned *) handle->offset)[i];
68                     }
69                     break;
70                 case MPI_UNSIGNED_LONG:
71                     for (i = 0; i < handle->count; i++) {
72                         ((unsigned long *) buf)[i] = ((unsigned long *) handle->accum)[i]
73                             + ((unsigned long *) handle->addr)[i]
74                             - ((unsigned long *) handle->offset)[i];
75                     }
76                     break;
77                 default:
78                     /* Code should never come here */
79                     mpi_errno = MPI_ERR_INTERN;
80                     goto fn_fail;
81                     break;
82             }
83         } else {
84             /* A running SUM with callback. Read its current value into handle */
85             handle->get_value(handle->addr, handle->obj_handle, handle->count, handle->current);
86 
87             switch (handle->datatype) {
88                 case MPI_UNSIGNED_LONG_LONG:
89                     for (i = 0; i < handle->count; i++) {
90                         ((unsigned long long *) buf)[i] = ((unsigned long long *) handle->accum)[i]
91                             + ((unsigned long *) handle->current)[i]
92                             - ((unsigned long long *) handle->offset)[i];
93                     }
94                     break;
95                 case MPI_DOUBLE:
96                     for (i = 0; i < handle->count; i++) {
97                         ((double *) buf)[i] = ((double *) handle->accum)[i]
98                             + ((double *) handle->current)[i]
99                             - ((double *) handle->offset)[i];
100                     }
101                     break;
102                 case MPI_UNSIGNED:
103                     for (i = 0; i < handle->count; i++) {
104                         ((unsigned *) buf)[i] = ((unsigned *) handle->accum)[i]
105                             + ((unsigned *) handle->current)[i]
106                             - ((unsigned *) handle->offset)[i];
107                     }
108                     break;
109                 case MPI_UNSIGNED_LONG:
110                     for (i = 0; i < handle->count; i++) {
111                         ((unsigned long *) buf)[i] = ((unsigned long *) handle->accum)[i]
112                             + ((unsigned long *) handle->current)[i]
113                             - ((unsigned long *) handle->offset)[i];
114                     }
115                     break;
116                 default:
117                     /* Code should never come here */
118                     mpi_errno = MPI_ERR_INTERN;
119                     goto fn_fail;
120                     break;
121             }
122         }
123     } else if (MPIR_T_pvar_is_sum(handle) && !MPIR_T_pvar_is_started(handle)) {
124         /* A SUM is stopped. Return accum directly */
125         MPIR_Memcpy(buf, handle->accum, handle->bytes * handle->count);
126     } else if (MPIR_T_pvar_is_watermark(handle)) {
127         /* Callback and array are not allowed for watermarks, since they
128          * can not gurantee correct semantics of watermarks.
129          */
130         MPIR_Assert(handle->get_value == NULL && handle->count == 1);
131 
132         if (MPIR_T_pvar_is_first(handle)) {
133             /* Current value of the first handle of a watermark is stored at
134              * a special location nearby the watermark itself.
135              */
136             switch (handle->datatype) {
137                 case MPI_UNSIGNED_LONG_LONG:
138                     *(unsigned long long *) buf =
139                         ((MPIR_T_pvar_watermark_t *) handle->addr)->watermark.ull;
140                     break;
141                 case MPI_DOUBLE:
142                     *(double *) buf = ((MPIR_T_pvar_watermark_t *) handle->addr)->watermark.f;
143                     break;
144                 case MPI_UNSIGNED:
145                     *(unsigned *) buf = ((MPIR_T_pvar_watermark_t *) handle->addr)->watermark.u;
146                     break;
147                 case MPI_UNSIGNED_LONG:
148                     *(unsigned long *) buf =
149                         ((MPIR_T_pvar_watermark_t *) handle->addr)->watermark.ul;
150                     break;
151                 default:
152                     /* Code should never come here */
153                     mpi_errno = MPI_ERR_INTERN;
154                     goto fn_fail;
155                     break;
156             }
157         } else {
158             /* For remaining handles, their current value are in the handle */
159             switch (handle->datatype) {
160                 case MPI_UNSIGNED_LONG_LONG:
161                     *(unsigned long long *) buf = handle->watermark.ull;
162                     break;
163                 case MPI_DOUBLE:
164                     *(double *) buf = handle->watermark.f;
165                     break;
166                 case MPI_UNSIGNED:
167                     *(unsigned *) buf = handle->watermark.u;
168                     break;
169                 case MPI_UNSIGNED_LONG:
170                     *(unsigned long *) buf = handle->watermark.ul;
171                     break;
172                 default:
173                     /* Code should never come here */
174                     mpi_errno = MPI_ERR_INTERN;
175                     goto fn_fail;
176                     break;
177             }
178         }
179     } else {
180         /* For STATE, LEVEL, SIZE, PERCENTAGE, no caching is needed */
181         if (handle->get_value == NULL)
182             MPIR_Memcpy(buf, handle->addr, handle->bytes * handle->count);
183         else
184             handle->get_value(handle->addr, handle->obj_handle, handle->count, buf);
185     }
186 
187   fn_exit:
188     return mpi_errno;
189   fn_fail:
190     goto fn_exit;
191 }
192 
193 #endif /* MPICH_MPI_FROM_PMPI */
194 
195 /*@
196 MPI_T_pvar_read - Read the value of a performance variable
197 
198 Input Parameters:
199 + session - identifier of performance experiment session (handle)
200 - handle - handle of a performance variable (handle)
201 
202 Output Parameters:
203 . buf - initial address of storage location for variable value (choice)
204 
205 Notes:
206 The MPI_T_pvar_read() call queries the value of the performance variable with the
207 handle "handle" in the session identified by the parameter session and stores the result
208 in the buffer identified by the parameter buf. The user is responsible to ensure that the
209 buffer is of the appropriate size to hold the entire value of the performance variable
210 (based on the datatype and count returned by the corresponding previous calls to
211 MPI_T_pvar_get_info() and MPI_T_pvar_handle_alloc(), respectively).
212 
213 The constant MPI_T_PVAR_ALL_HANDLES cannot be used as an argument for the function
214 MPI_T_pvar_read().
215 
216 .N ThreadSafe
217 
218 .N Errors
219 .N MPI_SUCCESS
220 .N MPI_T_ERR_NOT_INITIALIZED
221 .N MPI_T_ERR_INVALID_SESSION
222 .N MPI_T_ERR_INVALID_HANDLE
223 @*/
MPI_T_pvar_read(MPI_T_pvar_session session,MPI_T_pvar_handle handle,void * buf)224 int MPI_T_pvar_read(MPI_T_pvar_session session, MPI_T_pvar_handle handle, void *buf)
225 {
226     int mpi_errno = MPI_SUCCESS;
227 
228     MPIR_FUNC_TERSE_STATE_DECL(MPID_STATE_MPI_T_PVAR_READ);
229     MPIR_ERRTEST_MPIT_INITIALIZED(mpi_errno);
230     MPIR_T_THREAD_CS_ENTER();
231     MPIR_FUNC_TERSE_ENTER(MPID_STATE_MPI_T_PVAR_READ);
232 
233     /* Validate parameters */
234 #ifdef HAVE_ERROR_CHECKING
235     {
236         MPID_BEGIN_ERROR_CHECKS;
237         {
238             MPIR_ERRTEST_PVAR_SESSION(session, mpi_errno);
239             MPIR_ERRTEST_PVAR_HANDLE(handle, mpi_errno);
240             MPIR_ERRTEST_ARGNULL(buf, "buf", mpi_errno);
241             if (handle == MPI_T_PVAR_ALL_HANDLES || session != handle->session
242                 || !MPIR_T_pvar_is_oncestarted(handle)) {
243                 mpi_errno = MPI_T_ERR_INVALID_HANDLE;
244                 goto fn_fail;
245             }
246         }
247         MPID_END_ERROR_CHECKS;
248     }
249 #endif /* HAVE_ERROR_CHECKING */
250 
251     /* ... body of routine ...  */
252 
253     mpi_errno = MPIR_T_pvar_read_impl(session, handle, buf);
254     if (mpi_errno)
255         goto fn_fail;
256 
257     /* ... end of body of routine ... */
258 
259   fn_exit:
260     MPIR_FUNC_TERSE_EXIT(MPID_STATE_MPI_T_PVAR_READ);
261     MPIR_T_THREAD_CS_EXIT();
262     return mpi_errno;
263 
264   fn_fail:
265     /* --BEGIN ERROR HANDLING-- */
266 #ifdef HAVE_ERROR_CHECKING
267     {
268         mpi_errno =
269             MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, __func__, __LINE__, MPI_ERR_OTHER,
270                                  "**mpi_t_pvar_read", "**mpi_t_pvar_read %p %p %p", session, handle,
271                                  buf);
272     }
273 #endif
274     mpi_errno = MPIR_Err_return_comm(NULL, __func__, mpi_errno);
275     goto fn_exit;
276     /* --END ERROR HANDLING-- */
277 }
278