1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
2 /*
3  * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
4  *                         University Research and Technology
5  *                         Corporation.  All rights reserved.
6  * Copyright (c) 2004-2013 The University of Tennessee and The University
7  *                         of Tennessee Research Foundation.  All rights
8  *                         reserved.
9  * Copyright (c) 2004-2005 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) 2008      Cisco Systems, Inc.  All rights reserved.
14  * Copyright (c) 2012-2013 Inria.  All rights reserved.
15  * Copyright (c) 2014      Los Alamos National Security, LLC. All rights
16  *                         reserved.
17  * Copyright (c) 2014-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 
26 #include "ompi_config.h"
27 #include "ompi/mca/topo/base/base.h"
28 #include "ompi/communicator/communicator.h"
29 
30 /*
31  * function - partitions a communicator into subgroups which
32  *            form lower-dimensional cartesian subgrids
33  *
34  * @param comm communicator with cartesian structure (handle)
35  * @param remain_dims the 'i'th entry of 'remain_dims' specifies whether
36  *                the 'i'th dimension is kept in the subgrid (true)
37  *                or is dropped (false) (logical vector)
38  * @param new_comm communicator containing the subgrid that includes the
39  *                 calling process (handle)
40  *
41  * @retval MPI_SUCCESS
42  * @retval MPI_ERR_TOPOLOGY
43  * @retval MPI_ERR_COMM
44  */
mca_topo_base_cart_sub(ompi_communicator_t * comm,const int * remain_dims,ompi_communicator_t ** new_comm)45 int mca_topo_base_cart_sub (ompi_communicator_t* comm,
46                             const int *remain_dims,
47                             ompi_communicator_t** new_comm)
48 {
49     struct ompi_communicator_t *temp_comm;
50     mca_topo_base_comm_cart_2_2_0_t *old_cart;
51     int errcode, colour, key, colfactor, keyfactor;
52     int ndim, dim, i;
53     int *d, *dorig = NULL, *dold, *c, *p, *porig = NULL, *pold;
54     mca_topo_base_module_t* topo;
55     mca_topo_base_comm_cart_2_2_0_t* cart;
56 
57     *new_comm = MPI_COMM_NULL;
58     old_cart = comm->c_topo->mtc.cart;
59 
60     /*
61      * Compute colour and key used in splitting the communicator.
62      */
63     colour = key = 0;
64     colfactor = keyfactor = 1;
65     ndim = 0;
66 
67     i = old_cart->ndims - 1;
68     d = old_cart->dims + i;
69     c = comm->c_topo->mtc.cart->coords + i;
70 
71     for (; i >= 0; --i, --d, --c) {
72         dim = *d;
73         if (remain_dims[i] == 0) {
74             colour += colfactor * (*c);
75             colfactor *= dim;
76         } else {
77             ++ndim;
78             key += keyfactor * (*c);
79             keyfactor *= dim;
80         }
81     }
82     /* Special case: if all of remain_dims were false, we need to make
83        a 0-dimension cartesian communicator with just ourselves in it
84        (you can't have a communicator unless you're in it). */
85     if (0 == ndim) {
86         colour = ompi_comm_rank (comm);
87     }
88     /* Split the communicator. */
89     errcode = ompi_comm_split(comm, colour, key, &temp_comm, false);
90     if (errcode != OMPI_SUCCESS) {
91         return errcode;
92     }
93 
94     /* Fill the communicator with topology information. */
95     if (temp_comm != MPI_COMM_NULL) {
96 
97         assert( NULL == temp_comm->c_topo );
98         if (OMPI_SUCCESS != (errcode = mca_topo_base_comm_select(temp_comm,
99                                                                  comm->c_topo,
100                                                                  &topo,
101                                                                  OMPI_COMM_CART))) {
102             ompi_comm_free(&temp_comm);
103             return OMPI_ERR_OUT_OF_RESOURCE;
104         }
105         if (ndim >= 1) {
106             /* Copy the dimensions */
107             dorig = d = (int*)malloc(ndim * sizeof(int));
108             dold = old_cart->dims;
109             /* Copy the periods */
110             porig = p = (int*)malloc(ndim * sizeof(int));
111             pold = old_cart->periods;
112             for (i = 0; i < old_cart->ndims; ++i, ++dold, ++pold) {
113                 if (remain_dims[i]) {
114                     *d++ = *dold;
115                     *p++ = *pold;
116                 }
117             }
118         }
119         cart = OBJ_NEW(mca_topo_base_comm_cart_2_2_0_t);
120         if( NULL == cart ) {
121             ompi_comm_free(&temp_comm);
122             if (NULL != dorig) {
123                 free(dorig);
124             }
125             if (NULL != porig) {
126                 free(porig);
127             }
128             return OMPI_ERR_OUT_OF_RESOURCE;
129         }
130         cart->ndims = ndim;
131         cart->dims = dorig;
132         cart->periods = porig;
133 
134         /* NTH: protect against a 0-byte alloc in the ndims = 0 case */
135         if (ndim > 0) {
136             cart->coords = (int*)malloc(sizeof(int) * ndim);
137             if (NULL == cart->coords) {
138                 free(cart->periods);
139                 if(NULL != cart->dims) free(cart->dims);
140                 OBJ_RELEASE(cart);
141                 return OMPI_ERR_OUT_OF_RESOURCE;
142             }
143             {  /* setup the cartesian topology */
144                 int nprocs = temp_comm->c_local_group->grp_proc_count,
145                     rank   = temp_comm->c_local_group->grp_my_rank;
146 
147                 for (i = 0; i < ndim; ++i) {
148                     nprocs /= cart->dims[i];
149                     cart->coords[i] = rank / nprocs;
150                     rank %= nprocs;
151                 }
152             }
153         }
154 
155         temp_comm->c_topo           = topo;
156         temp_comm->c_topo->mtc.cart = cart;
157         temp_comm->c_topo->reorder  = false;
158         temp_comm->c_flags         |= OMPI_COMM_CART;
159     }
160 
161     *new_comm = temp_comm;
162 
163     return MPI_SUCCESS;
164 }
165