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-2018 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) 2010      University of Houston.  All rights reserved.
14  * Copyright (c) 2012 Cisco Systems, Inc.  All rights reserved.
15  * Copyright (c) 2012-2016 Los Alamos National Security, LLC.  All rights
16  *                         reserved.
17  * Copyright (c) 2015-2017 Research Organization for Information Science
18  *                         and Technology (RIST). All rights reserved.
19  * Copyright (c) 2017      IBM Corporation.  All rights reserved.
20  * $COPYRIGHT$
21  *
22  * Additional copyrights may follow
23  *
24  * $HEADER$
25  */
26 
27 #include "ompi_config.h"
28 #include <stdio.h>
29 
30 #include "ompi/mpi/c/bindings.h"
31 #include "ompi/runtime/params.h"
32 #include "ompi/communicator/communicator.h"
33 #include "ompi/errhandler/errhandler.h"
34 #include "ompi/datatype/ompi_datatype.h"
35 #include "ompi/mca/topo/base/base.h"
36 #include "ompi/memchecker.h"
37 #include "ompi/mca/topo/topo.h"
38 #include "ompi/mca/topo/base/base.h"
39 #include "ompi/runtime/ompi_spc.h"
40 
41 #if OMPI_BUILD_MPI_PROFILING
42 #if OPAL_HAVE_WEAK_SYMBOLS
43 #pragma weak MPI_Neighbor_allgatherv = PMPI_Neighbor_allgatherv
44 #endif
45 #define MPI_Neighbor_allgatherv PMPI_Neighbor_allgatherv
46 #endif
47 
48 static const char FUNC_NAME[] = "MPI_Neighbor_allgatherv";
49 
50 
MPI_Neighbor_allgatherv(const void * sendbuf,int sendcount,MPI_Datatype sendtype,void * recvbuf,const int recvcounts[],const int displs[],MPI_Datatype recvtype,MPI_Comm comm)51 int MPI_Neighbor_allgatherv(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
52                             void *recvbuf, const int recvcounts[], const int displs[],
53                             MPI_Datatype recvtype, MPI_Comm comm)
54 {
55     int in_size, out_size, err;
56 
57     SPC_RECORD(OMPI_SPC_NEIGHBOR_ALLGATHERV, 1);
58 
59     MEMCHECKER(
60         int rank;
61         ptrdiff_t ext;
62 
63         rank = ompi_comm_rank(comm);
64         mca_topo_base_neighbor_count (comm, &in_size, &out_size);
65         ompi_datatype_type_extent(recvtype, &ext);
66 
67         memchecker_datatype(recvtype);
68         memchecker_comm (comm);
69         /* check whether the receive buffer is addressable. */
70         for (int i = 0; i < in_size; ++i) {
71             memchecker_call(&opal_memchecker_base_isaddressable,
72                             (char *)(recvbuf)+displs[i]*ext,
73                             recvcounts[i], recvtype);
74         }
75 
76         /* check whether the actual send buffer is defined. */
77         if (MPI_IN_PLACE != sendbuf) {
78             memchecker_datatype(sendtype);
79             memchecker_call(&opal_memchecker_base_isdefined, sendbuf, sendcount, sendtype);
80         }
81     );
82 
83     if (MPI_PARAM_CHECK) {
84 
85         /* Unrooted operation -- same checks for all ranks on both
86            intracommunicators and intercommunicators */
87 
88         err = MPI_SUCCESS;
89         OMPI_ERR_INIT_FINALIZE(FUNC_NAME);
90         if (ompi_comm_invalid(comm) || OMPI_COMM_IS_INTER(comm)) {
91             return OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, MPI_ERR_COMM,
92                                           FUNC_NAME);
93         } else if (! OMPI_COMM_IS_TOPO(comm)) {
94             return OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, MPI_ERR_TOPOLOGY,
95                                           FUNC_NAME);
96         } else if (MPI_IN_PLACE == sendbuf || MPI_IN_PLACE == recvbuf) {
97             return OMPI_ERRHANDLER_INVOKE(comm, MPI_ERR_ARG, FUNC_NAME);
98         } else if (MPI_DATATYPE_NULL == recvtype) {
99             return OMPI_ERRHANDLER_INVOKE(comm, MPI_ERR_TYPE, FUNC_NAME);
100         }
101 
102         OMPI_CHECK_DATATYPE_FOR_SEND(err, sendtype, sendcount);
103         OMPI_ERRHANDLER_CHECK(err, comm, err, FUNC_NAME);
104 
105       /* We always define the remote group to be the same as the local
106          group in the case of an intracommunicator, so it's safe to
107          get the size of the remote group here for both intra- and
108          intercommunicators */
109 
110         mca_topo_base_neighbor_count (comm, &in_size, &out_size);
111         for (int i = 0; i < in_size; ++i) {
112           if (recvcounts[i] < 0) {
113             return OMPI_ERRHANDLER_INVOKE(comm, MPI_ERR_COUNT, FUNC_NAME);
114           }
115         }
116 
117         if (NULL == displs) {
118           return OMPI_ERRHANDLER_INVOKE(comm, MPI_ERR_BUFFER, FUNC_NAME);
119         }
120 
121         if( OMPI_COMM_IS_CART(comm) ) {
122             const mca_topo_base_comm_cart_2_2_0_t *cart = comm->c_topo->mtc.cart;
123             if( 0 > cart->ndims ) {
124                 return OMPI_ERRHANDLER_INVOKE(comm, MPI_ERR_ARG, FUNC_NAME);
125             }
126         }
127         else if( OMPI_COMM_IS_GRAPH(comm) ) {
128             int degree;
129             mca_topo_base_graph_neighbors_count(comm, ompi_comm_rank(comm), &degree);
130             if( 0 > degree ) {
131                 return OMPI_ERRHANDLER_INVOKE(comm, MPI_ERR_ARG, FUNC_NAME);
132             }
133         }
134         else if( OMPI_COMM_IS_DIST_GRAPH(comm) ) {
135             const mca_topo_base_comm_dist_graph_2_2_0_t *dist_graph = comm->c_topo->mtc.dist_graph;
136             int indegree  = dist_graph->indegree;
137             int outdegree = dist_graph->outdegree;
138             if( indegree <  0 || outdegree <  0 ) {
139                 return OMPI_ERRHANDLER_INVOKE(comm, MPI_ERR_ARG, FUNC_NAME);
140             }
141         }
142     }
143 
144     OPAL_CR_ENTER_LIBRARY();
145 
146     /* Invoke the coll component to perform the back-end operation */
147     err = comm->c_coll->coll_neighbor_allgatherv(sendbuf, sendcount, sendtype,
148                                                 recvbuf, recvcounts, displs,
149                                                 recvtype, comm, comm->c_coll->coll_neighbor_allgatherv_module);
150     OMPI_ERRHANDLER_RETURN(err, comm, err, FUNC_NAME);
151 }
152