2 This source code file is part of thread_mpi.
3 Written by Sander Pronk, Erik Lindahl, and possibly others.
5 Copyright (c) 2009, Sander Pronk, Erik Lindahl.
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are met:
10 1) Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 2) Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15 3) Neither the name of the copyright holders nor the
16 names of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY US ''AS IS'' AND ANY
20 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 DISCLAIMED. IN NO EVENT SHALL WE BE LIABLE FOR ANY
23 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 If you want to redistribute modifications, please consider that
31 scientific software is very special. Version control is crucial -
32 bugs must be traceable. We will be happy to consider code for
33 inclusion in the official distribution, but derived work should not
34 be called official thread_mpi. Details are found in the README & COPYING
38 #ifdef HAVE_TMPI_CONFIG_H
39 #include "tmpi_config.h"
61 /* topology functions */
62 int tMPI_Topo_test(tMPI_Comm comm
, int *status
)
65 tMPI_Trace_print("tMPI_Topo_test(%p, %p)", comm
, status
);
70 return tMPI_Error(TMPI_COMM_WORLD
, TMPI_ERR_COMM
);
75 /*else if (comm->graph)
78 *status
=TMPI_UNDEFINED
;
83 int tMPI_Cartdim_get(tMPI_Comm comm
, int *ndims
)
86 tMPI_Trace_print("tMPI_Cartdim_get(%p, %p)", comm
, ndims
);
90 return tMPI_Error(TMPI_COMM_WORLD
, TMPI_ERR_COMM
);
92 if (!comm
->cart
|| comm
->cart
->ndims
==0)
96 *ndims
=comm
->cart
->ndims
;
101 int tMPI_Cart_get(tMPI_Comm comm
, int maxdims
, int *dims
, int *periods
,
105 int myrank
=tMPI_Comm_seek_rank(comm
, tMPI_Get_current());
108 tMPI_Trace_print("tMPI_Cart_get(%p, %d, %p, %p, %p)", comm
, maxdims
,
109 dims
, periods
, coords
);
113 return tMPI_Error(TMPI_COMM_WORLD
, TMPI_ERR_COMM
);
115 if (!comm
->cart
|| comm
->cart
->ndims
==0)
118 tMPI_Cart_coords(comm
, myrank
, maxdims
, coords
);
120 for(i
=0;i
<comm
->cart
->ndims
;i
++)
124 return tMPI_Error(comm
, TMPI_ERR_DIMS
);
126 dims
[i
]=comm
->cart
->dims
[i
];
127 periods
[i
]=comm
->cart
->periods
[i
];
133 int tMPI_Cart_rank(tMPI_Comm comm
, int *coords
, int *rank
)
138 tMPI_Trace_print("tMPI_Cart_get(%p, %p, %p)", comm
, coords
, rank
);
142 return tMPI_Error(TMPI_COMM_WORLD
, TMPI_ERR_COMM
);
144 if (!comm
->cart
|| comm
->cart
->ndims
==0)
147 /* because of row-major ordering, we count the dimensions down */
148 for(i
=comm
->cart
->ndims
-1;i
>=0;i
--)
150 int rcoord
=coords
[i
];
151 if (comm
->cart
->periods
[i
])
153 /* apply periodic boundary conditions */
154 rcoord
= rcoord
% comm
->cart
->dims
[i
];
156 rcoord
+= comm
->cart
->dims
[i
];
160 if (rcoord
< 0 || rcoord
>= comm
->cart
->dims
[i
])
162 return tMPI_Error(comm
, TMPI_ERR_DIMS
);
166 mul
*= comm
->cart
->dims
[i
];
172 int tMPI_Cart_coords(tMPI_Comm comm
, int rank
, int maxdims
, int *coords
)
178 tMPI_Trace_print("tMPI_Cart_coords(%p, %d, %d, %p)", comm
, rank
, maxdims
,
183 return tMPI_Error(TMPI_COMM_WORLD
, TMPI_ERR_COMM
);
185 if (!comm
->cart
|| comm
->cart
->ndims
==0)
187 if (maxdims
< comm
->cart
->ndims
)
189 return tMPI_Error(comm
, TMPI_ERR_DIMS
);
192 /* again, row-major ordering */
193 for(i
=comm
->cart
->ndims
-1;i
>=0;i
--)
195 coords
[i
]=rank_left
%comm
->cart
->dims
[i
];
196 rank_left
/= comm
->cart
->dims
[i
];
204 int tMPI_Cart_map(tMPI_Comm comm
, int ndims
, int *dims
, int *periods
,
207 /* this function doesn't actually do anything beyond returning the current
208 rank (or TMPI_UNDEFINED if it doesn't fit in the new topology */
209 int myrank
=tMPI_Comm_seek_rank(comm
, tMPI_Get_current());
214 tMPI_Trace_print("tMPI_Cart_map(%p, %d, %p, %p, %p)", comm
, ndims
, dims
,
219 return tMPI_Error(TMPI_COMM_WORLD
, TMPI_ERR_COMM
);
223 return tMPI_Error(comm
, TMPI_ERR_DIMS
);
226 /* calculate the total number of procs in cartesian comm */
234 *newrank
=TMPI_UNDEFINED
;
245 /* initialize Cartesian topology info in comm. If ndims==0, dims and periods
246 are not referenced */
247 static void tMPI_Cart_init(tMPI_Comm
*comm_cart
, int ndims
, int *dims
,
255 tMPI_Comm_rank(*comm_cart
, &newrank
);
260 (*comm_cart
)->cart
=(struct cart_topol
*)tMPI_Malloc(
261 sizeof(struct cart_topol
));
262 (*comm_cart
)->cart
->dims
=(int*)tMPI_Malloc(ndims
*sizeof(int));
263 (*comm_cart
)->cart
->periods
=(int*)tMPI_Malloc(ndims
*sizeof(int));
264 (*comm_cart
)->cart
->ndims
=ndims
;
267 (*comm_cart
)->cart
->dims
[i
]=dims
[i
];
268 (*comm_cart
)->cart
->periods
[i
]=periods
[i
];
272 /* and we add a barrier to make sure the cart object is seen by
273 every thread that is part of the new communicator */
276 tMPI_Spinlock_barrier_wait( &( (*comm_cart
)->barrier
) );
280 void tMPI_Cart_destroy(struct cart_topol
*cart
)
289 int tMPI_Cart_create(tMPI_Comm comm_old
, int ndims
, int *dims
, int *periods
,
290 int reorder
, tMPI_Comm
*comm_cart
)
292 int myrank
=tMPI_Comm_seek_rank(comm_old
, tMPI_Get_current());
300 tMPI_Trace_print("tMPI_Cart_create(%p, %d, %p, %p, %d, %p)", comm_old
,
301 ndims
, dims
, periods
, reorder
, comm_cart
);
305 return tMPI_Error(comm_old
, TMPI_ERR_COMM
);
307 /* calculate the total number of procs in cartesian comm */
312 /* refuse to create if there's not enough procs */
313 if (comm_old
->grp
.N
< Ntot
)
315 *comm_cart
=TMPI_COMM_NULL
;
317 return tMPI_Error(comm_old
, TMPI_ERR_CART_CREATE_NPROCS
);
326 tMPI_Cart_map(comm_old
, ndims
, dims
, periods
, &key
);
329 if (key
==TMPI_UNDEFINED
)
331 color
=TMPI_UNDEFINED
;
334 tMPI_Comm_split(comm_old
, color
, key
, comm_cart
);
336 tMPI_Cart_init(comm_cart
, ndims
, dims
, periods
);
342 int tMPI_Cart_sub(tMPI_Comm comm
, int *remain_dims
, tMPI_Comm
*newcomm
)
354 tMPI_Trace_print("tMPI_Cart_sub(%p, %p, %p)", comm
, remain_dims
, newcomm
);
356 tMPI_Comm_rank(comm
, &myrank
);
359 oldcoords
=(int*)tMPI_Malloc(sizeof(int)*comm
->cart
->ndims
);
360 dims
=(int*)tMPI_Malloc(sizeof(int)*comm
->cart
->ndims
);
361 periods
=(int*)tMPI_Malloc(sizeof(int)*comm
->cart
->ndims
);
363 /* get old coordinates */
364 tMPI_Cart_coords(comm
, myrank
, comm
->cart
->ndims
, oldcoords
);
366 for(i
=0;i
<comm
->cart
->ndims
;i
++)
370 /* for the remaining dimensions, copy dimensionality data */
371 dims
[ndims
]=comm
->cart
->dims
[i
];
372 periods
[ndims
]=comm
->cart
->periods
[i
];
377 /* base color on not used coordinates. We keep a
378 ndims_notused index multiplier.*/
379 color_notused
+= oldcoords
[i
]*ndims_notused
;
380 ndims_notused
*= comm
->cart
->dims
[i
];
385 /* key=myrank, because we want the order to remain the same */
386 tMPI_Comm_split(comm
, color_notused
, myrank
, newcomm
);
387 tMPI_Cart_init(newcomm
, ndims
, dims
, periods
);