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-2005 The University of Tennessee and The University
7 * of Tennessee Research Foundation. All rights
8 * reserved.
9 * Copyright (c) 2004-2008 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) 2009 Sun Microsystmes, Inc. All rights reserved.
14 * Copyright (c) 2011 Sandia National Laboratories. All rights reserved.
15 * Copyright (c) 2014-2015 Los Alamos National Security, LLC. All rights
16 * reserved.
17 * Copyright (c) 2015 Research Organization for Information Science
18 * and Technology (RIST). All rights reserved.
19 * $COPYRIGHT$
20 *
21 * Additional copyrights may follow
22 *
23 * $HEADER$
24 */
25 #include "ompi_config.h"
26 #include <stdio.h>
27 #include "ompi/mpi/c/bindings.h"
28 #include "ompi/runtime/params.h"
29 #include "ompi/communicator/communicator.h"
30 #include "ompi/errhandler/errhandler.h"
31 #include "ompi/win/win.h"
32 #include "ompi/mca/osc/osc.h"
33 #include "ompi/op/op.h"
34 #include "ompi/datatype/ompi_datatype.h"
35 #include "ompi/datatype/ompi_datatype_internal.h"
36 #include "ompi/memchecker.h"
37
38 #if OMPI_BUILD_MPI_PROFILING
39 #if OPAL_HAVE_WEAK_SYMBOLS
40 #pragma weak MPI_Get_accumulate = PMPI_Get_accumulate
41 #endif
42 #define MPI_Get_accumulate PMPI_Get_accumulate
43 #endif
44
45 static const char FUNC_NAME[] = "MPI_Get_accumulate";
46
47 int MPI_Get_accumulate(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype,
48 void *result_addr, int result_count, MPI_Datatype result_datatype,
49 int target_rank, MPI_Aint target_disp, int target_count,
50 MPI_Datatype target_datatype, MPI_Op op, MPI_Win win)
51 {
52 int rc;
53 ompi_win_t *ompi_win = (ompi_win_t*) win;
54
55 MEMCHECKER(
56 memchecker_datatype(origin_datatype);
57 memchecker_datatype(target_datatype);
58 memchecker_call(&opal_memchecker_base_isdefined, (void *) origin_addr, origin_count, origin_datatype);
59 );
60
61 if (MPI_PARAM_CHECK) {
62 rc = OMPI_SUCCESS;
63
64 OMPI_ERR_INIT_FINALIZE(FUNC_NAME);
65
66 if (ompi_win_invalid(win)) {
67 return OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, MPI_ERR_WIN, FUNC_NAME);
68 } else if (origin_count < 0 || target_count < 0) {
69 rc = MPI_ERR_COUNT;
70 } else if (ompi_win_peer_invalid(win, target_rank) &&
71 (MPI_PROC_NULL != target_rank)) {
72 rc = MPI_ERR_RANK;
73 } else if (MPI_OP_NULL == op) {
74 rc = MPI_ERR_OP;
75 } else if (!ompi_op_is_intrinsic(op)) {
76 rc = MPI_ERR_OP;
77 } else if ( MPI_WIN_FLAVOR_DYNAMIC != win->w_flavor && target_disp < 0 ) {
78 rc = MPI_ERR_DISP;
79 } else {
80 /* the origin datatype is meaningless when using MPI_OP_NO_OP */
81 if (&ompi_mpi_op_no_op.op != op) {
82 OMPI_CHECK_DATATYPE_FOR_ONE_SIDED(rc, origin_datatype, origin_count);
83 } else {
84 rc = OMPI_SUCCESS;
85 }
86 if (OMPI_SUCCESS == rc) {
87 OMPI_CHECK_DATATYPE_FOR_ONE_SIDED(rc, target_datatype, target_count);
88 }
89 if (OMPI_SUCCESS == rc) {
90 /* While technically the standard probably requires that the
91 datatypes used with MPI_REPLACE conform to all the rules
92 for other reduction operators, we don't require such
93 behavior, as checking for it is expensive here and we don't
94 care in implementation.. */
95 if (op != &ompi_mpi_op_replace.op && op != &ompi_mpi_op_no_op.op) {
96 ompi_datatype_t *op_check_dt, *origin_check_dt;
97 char *msg;
98
99 /* GET_ACCUMULATE, unlike REDUCE, can use with derived
100 datatypes with predefinied operations, with some
101 restrictions outlined in MPI-3:11.3.4. The derived
102 datatype must be composed entierly from one predefined
103 datatype (so you can do all the construction you want,
104 but at the bottom, you can only use one datatype, say,
105 MPI_INT). If the datatype at the target isn't
106 predefined, then make sure it's composed of only one
107 datatype, and check that datatype against
108 ompi_op_is_valid(). */
109 origin_check_dt = ompi_datatype_get_single_predefined_type_from_args(origin_datatype);
110 op_check_dt = ompi_datatype_get_single_predefined_type_from_args(target_datatype);
111
112 if( !((origin_check_dt == op_check_dt) & (NULL != op_check_dt)) ) {
113 OMPI_ERRHANDLER_RETURN(MPI_ERR_ARG, win, MPI_ERR_ARG, FUNC_NAME);
114 }
115
116 /* check to make sure primitive type is valid for
117 reduction. Should do this on the target, but
118 then can't get the errcode back for this
119 call */
120 if (!ompi_op_is_valid(op, op_check_dt, &msg, FUNC_NAME)) {
121 int ret = OMPI_ERRHANDLER_INVOKE(win, MPI_ERR_OP, msg);
122 free(msg);
123 return ret;
124 }
125 }
126 }
127 }
128 OMPI_ERRHANDLER_CHECK(rc, win, rc, FUNC_NAME);
129 }
130
131 if (MPI_PROC_NULL == target_rank) {
132 return MPI_SUCCESS;
133 }
134
135 OPAL_CR_ENTER_LIBRARY();
136
137 rc = ompi_win->w_osc_module->osc_get_accumulate(origin_addr,
138 origin_count,
139 origin_datatype,
140 result_addr,
141 result_count,
142 result_datatype,
143 target_rank,
144 target_disp,
145 target_count,
146 target_datatype,
147 op, win);
148 OMPI_ERRHANDLER_RETURN(rc, win, rc, FUNC_NAME);
149 }