1 /* -*- Mode: C; c-basic-offset:4 ; -*- */
2 /*
3 * (C) 2001 by Argonne National Laboratory.
4 * See COPYRIGHT in top-level directory.
5 */
6
7 #include "mpidi_ch3_impl.h"
8 #include "mpidrma.h"
9
10 static int enableShortACC=1;
11
12 #ifdef USE_MPIU_INSTR
13 MPIU_INSTR_DURATION_EXTERN_DECL(wincreate_allgather);
14 MPIU_INSTR_DURATION_EXTERN_DECL(winfree_rs);
15 MPIU_INSTR_DURATION_EXTERN_DECL(winfree_complete);
16 MPIU_INSTR_DURATION_EXTERN_DECL(rmaqueue_alloc);
17 MPIU_INSTR_DURATION_EXTERN_DECL(rmaqueue_set);
18 extern void MPIDI_CH3_RMA_InitInstr(void);
19 #endif
20
21 #define MPIDI_PASSIVE_TARGET_DONE_TAG 348297
22 #define MPIDI_PASSIVE_TARGET_RMA_TAG 563924
23
24 /*
25 * TODO:
26 * Explore use of alternate allocation mechanisms for the RMA queue elements
27 * (Because profiling has shown that queue element allocation/deallocation
28 * can take a significant amount of time in the RMA operations).
29 * 1: Current approach (uses perm memory malloc/free)
30 * 2: Preallocate and maintain list (use perm memory malloc, but
31 * free onto window; use first; free on window free)
32 * 3: Preallocate and maintain list (use separate memory, but free to
33 * thread/process; free in Finalize handler. Option to use for
34 * single-threaded to avoid thread overheads)
35 * Possible interface
36 * int MPIDI_RMAListAlloc(MPIDI_RMA_ops **a,MPID_Win *win)
37 * int MPIDI_RMAListFree(MPIDI_RMA_ops *a, MPID_Win *win)
38 * return value is error code (e.g., allocation failure).
39 */
40
41 #undef FUNCNAME
42 #define FUNCNAME MPIDI_Win_free
43 #undef FCNAME
44 #define FCNAME MPIDI_QUOTE(FUNCNAME)
MPIDI_Win_free(MPID_Win ** win_ptr)45 int MPIDI_Win_free(MPID_Win **win_ptr)
46 {
47 int mpi_errno=MPI_SUCCESS, total_pt_rma_puts_accs;
48 int in_use;
49 MPID_Comm *comm_ptr;
50 int errflag = FALSE;
51 MPIDI_STATE_DECL(MPID_STATE_MPIDI_WIN_FREE);
52
53 MPIDI_RMA_FUNC_ENTER(MPID_STATE_MPIDI_WIN_FREE);
54
55 comm_ptr = (*win_ptr)->comm_ptr;
56 MPIU_INSTR_DURATION_START(winfree_rs);
57 mpi_errno = MPIR_Reduce_scatter_block_impl((*win_ptr)->pt_rma_puts_accs,
58 &total_pt_rma_puts_accs, 1,
59 MPI_INT, MPI_SUM, comm_ptr, &errflag);
60 if (mpi_errno) { MPIU_ERR_POP(mpi_errno); }
61 MPIU_ERR_CHKANDJUMP(errflag, mpi_errno, MPI_ERR_OTHER, "**coll_fail");
62 MPIU_INSTR_DURATION_END(winfree_rs);
63
64 if (total_pt_rma_puts_accs != (*win_ptr)->my_pt_rma_puts_accs)
65 {
66 MPID_Progress_state progress_state;
67
68 /* poke the progress engine until the two are equal */
69 MPIU_INSTR_DURATION_START(winfree_complete);
70 MPID_Progress_start(&progress_state);
71 while (total_pt_rma_puts_accs != (*win_ptr)->my_pt_rma_puts_accs)
72 {
73 mpi_errno = MPID_Progress_wait(&progress_state);
74 /* --BEGIN ERROR HANDLING-- */
75 if (mpi_errno != MPI_SUCCESS)
76 {
77 MPID_Progress_end(&progress_state);
78 MPIU_ERR_SETANDJUMP(mpi_errno,MPI_ERR_OTHER,"**winnoprogress");
79 }
80 /* --END ERROR HANDLING-- */
81 }
82 MPID_Progress_end(&progress_state);
83 MPIU_INSTR_DURATION_END(winfree_complete);
84 }
85
86 mpi_errno = MPIR_Comm_free_impl(comm_ptr);
87 if (mpi_errno) MPIU_ERR_POP(mpi_errno);
88
89 MPIU_Free((*win_ptr)->base_addrs);
90 MPIU_Free((*win_ptr)->sizes);
91 MPIU_Free((*win_ptr)->disp_units);
92 MPIU_Free((*win_ptr)->all_win_handles);
93 MPIU_Free((*win_ptr)->pt_rma_puts_accs);
94
95 /* Free the attached buffer for windows created with MPI_Win_allocate() */
96 if ((*win_ptr)->create_flavor == MPIX_WIN_FLAVOR_ALLOCATE && (*win_ptr)->size > 0) {
97 MPIU_Free((*win_ptr)->base);
98 }
99
100 MPIU_Object_release_ref(*win_ptr, &in_use);
101 /* MPI windows don't have reference count semantics, so this should always be true */
102 MPIU_Assert(!in_use);
103 MPIU_Handle_obj_free( &MPID_Win_mem, *win_ptr );
104
105 fn_exit:
106 MPIDI_RMA_FUNC_EXIT(MPID_STATE_MPIDI_WIN_FREE);
107 return mpi_errno;
108
109 fn_fail:
110 goto fn_exit;
111 }
112
113
114 #undef FUNCNAME
115 #define FUNCNAME MPIDI_Put
116 #undef FCNAME
117 #define FCNAME MPIDI_QUOTE(FUNCNAME)
MPIDI_Put(const void * origin_addr,int origin_count,MPI_Datatype origin_datatype,int target_rank,MPI_Aint target_disp,int target_count,MPI_Datatype target_datatype,MPID_Win * win_ptr)118 int MPIDI_Put(const void *origin_addr, int origin_count, MPI_Datatype
119 origin_datatype, int target_rank, MPI_Aint target_disp,
120 int target_count, MPI_Datatype target_datatype, MPID_Win *win_ptr)
121 {
122 int mpi_errno = MPI_SUCCESS;
123 int dt_contig ATTRIBUTE((unused)), rank, predefined;
124 MPIDI_RMA_ops *new_ptr;
125 MPID_Datatype *dtp;
126 MPI_Aint dt_true_lb ATTRIBUTE((unused));
127 MPIDI_msg_sz_t data_sz;
128 MPIU_CHKPMEM_DECL(1);
129 MPIDI_STATE_DECL(MPID_STATE_MPIDI_PUT);
130
131 MPIDI_RMA_FUNC_ENTER(MPID_STATE_MPIDI_PUT);
132
133 MPIDI_Datatype_get_info(origin_count, origin_datatype,
134 dt_contig, data_sz, dtp,dt_true_lb);
135
136 if ((data_sz == 0) || (target_rank == MPI_PROC_NULL))
137 {
138 goto fn_exit;
139 }
140
141 rank = win_ptr->myrank;
142
143 /* If the put is a local operation, do it here */
144 if (target_rank == rank)
145 {
146 mpi_errno = MPIR_Localcopy(origin_addr, origin_count, origin_datatype,
147 (char *) win_ptr->base + win_ptr->disp_unit *
148 target_disp, target_count, target_datatype);
149 if (mpi_errno) { MPIU_ERR_POP(mpi_errno); }
150 }
151 else
152 {
153 /* queue it up */
154 /* FIXME: For short operations, should we use a (per-thread) pool? */
155 MPIU_INSTR_DURATION_START(rmaqueue_alloc);
156 MPIU_CHKPMEM_MALLOC(new_ptr, MPIDI_RMA_ops *, sizeof(MPIDI_RMA_ops),
157 mpi_errno, "RMA operation entry");
158 MPIU_INSTR_DURATION_END(rmaqueue_alloc);
159 if (win_ptr->rma_ops_list_tail)
160 win_ptr->rma_ops_list_tail->next = new_ptr;
161 else
162 win_ptr->rma_ops_list_head = new_ptr;
163 win_ptr->rma_ops_list_tail = new_ptr;
164
165 MPIU_INSTR_DURATION_START(rmaqueue_set);
166 /* FIXME: For contig and very short operations, use a streamlined op */
167 new_ptr->next = NULL;
168 new_ptr->type = MPIDI_RMA_PUT;
169 /* Cast away const'ness for the origin address, as the
170 * MPIDI_RMA_ops structure is used for both PUT and GET like
171 * operations */
172 new_ptr->origin_addr = (void *) origin_addr;
173 new_ptr->origin_count = origin_count;
174 new_ptr->origin_datatype = origin_datatype;
175 new_ptr->target_rank = target_rank;
176 new_ptr->target_disp = target_disp;
177 new_ptr->target_count = target_count;
178 new_ptr->target_datatype = target_datatype;
179 MPIU_INSTR_DURATION_END(rmaqueue_set);
180
181 /* if source or target datatypes are derived, increment their
182 reference counts */
183 MPIDI_CH3I_DATATYPE_IS_PREDEFINED(origin_datatype, predefined);
184 if (!predefined)
185 {
186 MPID_Datatype_get_ptr(origin_datatype, dtp);
187 MPID_Datatype_add_ref(dtp);
188 }
189 MPIDI_CH3I_DATATYPE_IS_PREDEFINED(target_datatype, predefined);
190 if (!predefined)
191 {
192 MPID_Datatype_get_ptr(target_datatype, dtp);
193 MPID_Datatype_add_ref(dtp);
194 }
195 }
196
197 fn_exit:
198 MPIDI_RMA_FUNC_EXIT(MPID_STATE_MPIDI_PUT);
199 return mpi_errno;
200
201 /* --BEGIN ERROR HANDLING-- */
202 fn_fail:
203 MPIU_CHKPMEM_REAP();
204 goto fn_exit;
205 /* --END ERROR HANDLING-- */
206 }
207
208
209
210 #undef FUNCNAME
211 #define FUNCNAME MPIDI_Get
212 #undef FCNAME
213 #define FCNAME MPIDI_QUOTE(FUNCNAME)
MPIDI_Get(void * origin_addr,int origin_count,MPI_Datatype origin_datatype,int target_rank,MPI_Aint target_disp,int target_count,MPI_Datatype target_datatype,MPID_Win * win_ptr)214 int MPIDI_Get(void *origin_addr, int origin_count, MPI_Datatype
215 origin_datatype, int target_rank, MPI_Aint target_disp,
216 int target_count, MPI_Datatype target_datatype, MPID_Win *win_ptr)
217 {
218 int mpi_errno = MPI_SUCCESS;
219 MPIDI_msg_sz_t data_sz;
220 int dt_contig ATTRIBUTE((unused)), rank, predefined;
221 MPI_Aint dt_true_lb ATTRIBUTE((unused));
222 MPIDI_RMA_ops *new_ptr;
223 MPID_Datatype *dtp;
224 MPIU_CHKPMEM_DECL(1);
225 MPIDI_STATE_DECL(MPID_STATE_MPIDI_GET);
226
227 MPIDI_RMA_FUNC_ENTER(MPID_STATE_MPIDI_GET);
228
229 MPIDI_Datatype_get_info(origin_count, origin_datatype,
230 dt_contig, data_sz, dtp, dt_true_lb);
231
232 if ((data_sz == 0) || (target_rank == MPI_PROC_NULL))
233 {
234 goto fn_exit;
235 }
236
237 rank = win_ptr->myrank;
238
239 /* If the get is a local operation, do it here */
240 if (target_rank == rank)
241 {
242 mpi_errno = MPIR_Localcopy((char *) win_ptr->base +
243 win_ptr->disp_unit * target_disp,
244 target_count, target_datatype,
245 origin_addr, origin_count,
246 origin_datatype);
247 if (mpi_errno) { MPIU_ERR_POP(mpi_errno); }
248 }
249 else
250 {
251 /* queue it up */
252 MPIU_INSTR_DURATION_START(rmaqueue_alloc);
253 MPIU_CHKPMEM_MALLOC(new_ptr, MPIDI_RMA_ops *, sizeof(MPIDI_RMA_ops),
254 mpi_errno, "RMA operation entry");
255 MPIU_INSTR_DURATION_END(rmaqueue_alloc);
256 if (win_ptr->rma_ops_list_tail)
257 win_ptr->rma_ops_list_tail->next = new_ptr;
258 else
259 win_ptr->rma_ops_list_head = new_ptr;
260 win_ptr->rma_ops_list_tail = new_ptr;
261
262 MPIU_INSTR_DURATION_START(rmaqueue_set);
263 /* FIXME: For contig and very short operations, use a streamlined op */
264 new_ptr->next = NULL;
265 new_ptr->type = MPIDI_RMA_GET;
266 new_ptr->origin_addr = origin_addr;
267 new_ptr->origin_count = origin_count;
268 new_ptr->origin_datatype = origin_datatype;
269 new_ptr->target_rank = target_rank;
270 new_ptr->target_disp = target_disp;
271 new_ptr->target_count = target_count;
272 new_ptr->target_datatype = target_datatype;
273 MPIU_INSTR_DURATION_END(rmaqueue_set);
274
275 /* if source or target datatypes are derived, increment their
276 reference counts */
277 MPIDI_CH3I_DATATYPE_IS_PREDEFINED(origin_datatype, predefined);
278 if (!predefined)
279 {
280 MPID_Datatype_get_ptr(origin_datatype, dtp);
281 MPID_Datatype_add_ref(dtp);
282 }
283 MPIDI_CH3I_DATATYPE_IS_PREDEFINED(target_datatype, predefined);
284 if (!predefined)
285 {
286 MPID_Datatype_get_ptr(target_datatype, dtp);
287 MPID_Datatype_add_ref(dtp);
288 }
289 }
290
291 fn_exit:
292 MPIDI_RMA_FUNC_EXIT(MPID_STATE_MPIDI_GET);
293 return mpi_errno;
294
295 /* --BEGIN ERROR HANDLING-- */
296 fn_fail:
297 MPIU_CHKPMEM_REAP();
298 goto fn_exit;
299 /* --END ERROR HANDLING-- */
300 }
301
302
303
304 #undef FUNCNAME
305 #define FUNCNAME MPIDI_Accumulate
306 #undef FCNAME
307 #define FCNAME MPIDI_QUOTE(FUNCNAME)
MPIDI_Accumulate(const void * origin_addr,int origin_count,MPI_Datatype origin_datatype,int target_rank,MPI_Aint target_disp,int target_count,MPI_Datatype target_datatype,MPI_Op op,MPID_Win * win_ptr)308 int MPIDI_Accumulate(const void *origin_addr, int origin_count, MPI_Datatype
309 origin_datatype, int target_rank, MPI_Aint target_disp,
310 int target_count, MPI_Datatype target_datatype, MPI_Op op,
311 MPID_Win *win_ptr)
312 {
313 int mpi_errno=MPI_SUCCESS;
314 MPIDI_msg_sz_t data_sz;
315 int dt_contig ATTRIBUTE((unused)), rank, origin_predefined, target_predefined;
316 MPI_Aint dt_true_lb ATTRIBUTE((unused));
317 MPIDI_RMA_ops *new_ptr;
318 MPID_Datatype *dtp;
319 MPIU_CHKLMEM_DECL(2);
320 MPIU_CHKPMEM_DECL(1);
321 MPIDI_STATE_DECL(MPID_STATE_MPIDI_ACCUMULATE);
322
323 MPIDI_RMA_FUNC_ENTER(MPID_STATE_MPIDI_ACCUMULATE);
324
325 MPIDI_Datatype_get_info(origin_count, origin_datatype,
326 dt_contig, data_sz, dtp, dt_true_lb);
327
328 if ((data_sz == 0) || (target_rank == MPI_PROC_NULL))
329 {
330 goto fn_exit;
331 }
332
333 rank = win_ptr->myrank;
334
335 MPIDI_CH3I_DATATYPE_IS_PREDEFINED(origin_datatype, origin_predefined);
336 MPIDI_CH3I_DATATYPE_IS_PREDEFINED(target_datatype, target_predefined);
337
338 /* Do =! rank first (most likely branch?) */
339 if (target_rank == rank)
340 {
341 MPI_User_function *uop;
342
343 if (op == MPI_REPLACE)
344 {
345 mpi_errno = MPIR_Localcopy(origin_addr, origin_count,
346 origin_datatype,
347 (char *) win_ptr->base + win_ptr->disp_unit *
348 target_disp, target_count, target_datatype);
349 if (mpi_errno) { MPIU_ERR_POP(mpi_errno); }
350 goto fn_exit;
351 }
352
353 MPIU_ERR_CHKANDJUMP1((HANDLE_GET_KIND(op) != HANDLE_KIND_BUILTIN),
354 mpi_errno, MPI_ERR_OP, "**opnotpredefined",
355 "**opnotpredefined %d", op );
356
357 /* get the function by indexing into the op table */
358 uop = MPIR_OP_HDL_TO_FN(op);
359
360 if (origin_predefined && target_predefined)
361 {
362 /* Cast away const'ness for origin_address in order to
363 * avoid changing the prototype for MPI_User_function */
364 (*uop)((void *) origin_addr, (char *) win_ptr->base + win_ptr->disp_unit *
365 target_disp, &target_count, &target_datatype);
366 }
367 else
368 {
369 /* derived datatype */
370
371 MPID_Segment *segp;
372 DLOOP_VECTOR *dloop_vec;
373 MPI_Aint first, last;
374 int vec_len, i, type_size, count;
375 MPI_Datatype type;
376 MPI_Aint true_lb, true_extent, extent;
377 void *tmp_buf=NULL, *target_buf;
378 const void *source_buf;
379
380 if (origin_datatype != target_datatype)
381 {
382 /* first copy the data into a temporary buffer with
383 the same datatype as the target. Then do the
384 accumulate operation. */
385
386 MPIR_Type_get_true_extent_impl(target_datatype, &true_lb, &true_extent);
387 MPID_Datatype_get_extent_macro(target_datatype, extent);
388
389 MPIU_CHKLMEM_MALLOC(tmp_buf, void *,
390 target_count * (MPIR_MAX(extent,true_extent)),
391 mpi_errno, "temporary buffer");
392 /* adjust for potential negative lower bound in datatype */
393 tmp_buf = (void *)((char*)tmp_buf - true_lb);
394
395 mpi_errno = MPIR_Localcopy(origin_addr, origin_count,
396 origin_datatype, tmp_buf,
397 target_count, target_datatype);
398 if (mpi_errno) { MPIU_ERR_POP(mpi_errno); }
399 }
400
401 if (target_predefined) {
402 /* target predefined type, origin derived datatype */
403
404 (*uop)(tmp_buf, (char *) win_ptr->base + win_ptr->disp_unit *
405 target_disp, &target_count, &target_datatype);
406 }
407 else {
408
409 segp = MPID_Segment_alloc();
410 MPIU_ERR_CHKANDJUMP1((!segp), mpi_errno, MPI_ERR_OTHER,
411 "**nomem","**nomem %s","MPID_Segment_alloc");
412 MPID_Segment_init(NULL, target_count, target_datatype, segp, 0);
413 first = 0;
414 last = SEGMENT_IGNORE_LAST;
415
416 MPID_Datatype_get_ptr(target_datatype, dtp);
417 vec_len = dtp->max_contig_blocks * target_count + 1;
418 /* +1 needed because Rob says so */
419 MPIU_CHKLMEM_MALLOC(dloop_vec, DLOOP_VECTOR *,
420 vec_len * sizeof(DLOOP_VECTOR),
421 mpi_errno, "dloop vector");
422
423 MPID_Segment_pack_vector(segp, first, &last, dloop_vec, &vec_len);
424
425 source_buf = (tmp_buf != NULL) ? tmp_buf : origin_addr;
426 target_buf = (char *) win_ptr->base +
427 win_ptr->disp_unit * target_disp;
428 type = dtp->eltype;
429 type_size = MPID_Datatype_get_basic_size(type);
430 for (i=0; i<vec_len; i++)
431 {
432 count = (dloop_vec[i].DLOOP_VECTOR_LEN)/type_size;
433 (*uop)((char *)source_buf + MPIU_PtrToAint(dloop_vec[i].DLOOP_VECTOR_BUF),
434 (char *)target_buf + MPIU_PtrToAint(dloop_vec[i].DLOOP_VECTOR_BUF),
435 &count, &type);
436 }
437
438 MPID_Segment_free(segp);
439 }
440 }
441 }
442 else
443 {
444 /* queue it up */
445 MPIU_INSTR_DURATION_START(rmaqueue_alloc);
446 MPIU_CHKPMEM_MALLOC(new_ptr, MPIDI_RMA_ops *, sizeof(MPIDI_RMA_ops),
447 mpi_errno, "RMA operation entry");
448 MPIU_INSTR_DURATION_END(rmaqueue_alloc);
449 if (win_ptr->rma_ops_list_tail)
450 win_ptr->rma_ops_list_tail->next = new_ptr;
451 else
452 win_ptr->rma_ops_list_head = new_ptr;
453 win_ptr->rma_ops_list_tail = new_ptr;
454
455 /* If predefined and contiguous, use a simplified element */
456 if (origin_predefined && target_predefined && enableShortACC) {
457 MPIU_INSTR_DURATION_START(rmaqueue_set);
458 new_ptr->next = NULL;
459 new_ptr->type = MPIDI_RMA_ACC_CONTIG;
460 /* Only the information needed for the contig/predefined acc */
461 /* Cast away const'ness for origin_address as
462 * MPIDI_RMA_ops contain both PUT and GET like ops */
463 new_ptr->origin_addr = (void *) origin_addr;
464 new_ptr->origin_count = origin_count;
465 new_ptr->origin_datatype = origin_datatype;
466 new_ptr->target_rank = target_rank;
467 new_ptr->target_disp = target_disp;
468 new_ptr->target_count = target_count;
469 new_ptr->target_datatype = target_datatype;
470 new_ptr->op = op;
471 MPIU_INSTR_DURATION_END(rmaqueue_set);
472 goto fn_exit;
473 }
474
475 MPIU_INSTR_DURATION_START(rmaqueue_set);
476 new_ptr->next = NULL;
477 new_ptr->type = MPIDI_RMA_ACCUMULATE;
478 /* Cast away const'ness for origin_address as MPIDI_RMA_ops
479 * contain both PUT and GET like ops */
480 new_ptr->origin_addr = (void *) origin_addr;
481 new_ptr->origin_count = origin_count;
482 new_ptr->origin_datatype = origin_datatype;
483 new_ptr->target_rank = target_rank;
484 new_ptr->target_disp = target_disp;
485 new_ptr->target_count = target_count;
486 new_ptr->target_datatype = target_datatype;
487 new_ptr->op = op;
488 MPIU_INSTR_DURATION_END(rmaqueue_set);
489
490 /* if source or target datatypes are derived, increment their
491 reference counts */
492 if (!origin_predefined)
493 {
494 MPID_Datatype_get_ptr(origin_datatype, dtp);
495 MPID_Datatype_add_ref(dtp);
496 }
497 if (!target_predefined)
498 {
499 MPID_Datatype_get_ptr(target_datatype, dtp);
500 MPID_Datatype_add_ref(dtp);
501 }
502 }
503
504 fn_exit:
505 MPIU_CHKLMEM_FREEALL();
506 MPIDI_RMA_FUNC_EXIT(MPID_STATE_MPIDI_ACCUMULATE);
507 return mpi_errno;
508
509 /* --BEGIN ERROR HANDLING-- */
510 fn_fail:
511 MPIU_CHKPMEM_REAP();
512 goto fn_exit;
513 /* --END ERROR HANDLING-- */
514 }
515
516
517 #undef FUNCNAME
518 #define FUNCNAME MPIDI_Alloc_mem
519 #undef FCNAME
520 #define FCNAME MPIDI_QUOTE(FUNCNAME)
MPIDI_Alloc_mem(size_t size,MPID_Info * info_ptr)521 void *MPIDI_Alloc_mem( size_t size, MPID_Info *info_ptr )
522 {
523 void *ap;
524 MPIDI_STATE_DECL(MPID_STATE_MPIDI_ALLOC_MEM);
525
526 MPIDI_FUNC_ENTER(MPID_STATE_MPIDI_ALLOC_MEM);
527
528 ap = MPIU_Malloc(size);
529
530 MPIDI_FUNC_EXIT(MPID_STATE_MPIDI_ALLOC_MEM);
531 return ap;
532 }
533
534
535 #undef FUNCNAME
536 #define FUNCNAME MPIDI_Free_mem
537 #undef FCNAME
538 #define FCNAME MPIDI_QUOTE(FUNCNAME)
MPIDI_Free_mem(void * ptr)539 int MPIDI_Free_mem( void *ptr )
540 {
541 int mpi_errno = MPI_SUCCESS;
542 MPIDI_STATE_DECL(MPID_STATE_MPIDI_FREE_MEM);
543
544 MPIDI_FUNC_ENTER(MPID_STATE_MPIDI_FREE_MEM);
545
546 MPIU_Free(ptr);
547
548 MPIDI_FUNC_EXIT(MPID_STATE_MPIDI_FREE_MEM);
549 return mpi_errno;
550 }
551