1 /* Copyright (c) 2014-2019. The SimGrid Team. All rights reserved. */
3 /* This program is free software; you can redistribute it and/or modify it
4 * under the terms of the license (GNU LGPL) which comes with this package. */
8 #include "smpi_comm.hpp"
9 #include "smpi_topo.hpp"
10 #include "xbt/sysdep.h"
14 /* static functions */
15 static int assignnodes(int ndim, int nfactor, int *pfacts,int **pdims);
16 static int getfactors(int num, int *nfators, int **factors);
22 /*******************************************************************************
23 * Cartesian topologies
24 ******************************************************************************/
26 Topo_Cart::Topo_Cart(int ndims) : ndims_(ndims), dims_(ndims), periodic_(ndims), position_(ndims)
30 /* reorder is ignored, don't know what would be the consequences of a dumb reordering but neither do I see the point of
32 Topo_Cart::Topo_Cart(MPI_Comm comm_old, int ndims, int dims[], int periods[], int reorder, MPI_Comm *comm_cart) : Topo_Cart(ndims) {
36 int rank = comm_old->rank();
40 for (int i = 0 ; i < ndims ; i++) {
44 *comm_cart = MPI_COMM_NULL;
47 oldGroup = comm_old->group();
48 newGroup = new Group(newSize);
49 for (int i = 0 ; i < newSize ; i++) {
50 newGroup->set_mapping(oldGroup->actor(i), i);
55 // FIXME : code duplication... See coords
57 for (int i=0; i<ndims; i++) {
59 periodic_[i] = periods[i];
60 nranks = nranks / dims[i];
61 /* FIXME: nranks could be zero (?) */
62 position_[i] = rank / nranks;
66 *comm_cart = new Comm(newGroup, this);
69 *comm_cart = new Comm(new Group(MPI_COMM_SELF->group()), this);
71 *comm_cart = MPI_COMM_NULL;
77 Topo_Cart* Topo_Cart::sub(const int remain_dims[], MPI_Comm *newcomm) {
78 int oldNDims = ndims_;
79 int *newDims = nullptr;
80 int *newPeriodic = nullptr;
82 if (remain_dims == nullptr && oldNDims != 0) {
86 for (int i = 0 ; i < oldNDims ; i++) {
92 newDims = new int[newNDims];
93 newPeriodic = new int[newNDims];
95 // that should not segfault
97 for (int i = 0 ; j < newNDims ; i++) {
100 newPeriodic[j] =periodic_[i];
105 Topo_Cart* res = new Topo_Cart(getComm(), newNDims, newDims, newPeriodic, 0, newcomm);
107 delete[] newPeriodic;
111 int Topo_Cart::coords(int rank, int maxdims, int coords[]) {
112 int nnodes = nnodes_;
113 for (int i = 0; i< ndims_; i++ ) {
114 nnodes = nnodes /dims_[i];
115 coords[i] = rank / nnodes;
116 rank = rank % nnodes;
121 int Topo_Cart::get(int maxdims, int* dims, int* periods, int* coords) {
122 int ndims=ndims_ < maxdims ?ndims_ : maxdims;
123 for(int i = 0 ; i < ndims ; i++) {
125 periods[i] =periodic_[i];
126 coords[i] =position_[i];
131 int Topo_Cart::rank(int* coords, int* rank) {
136 for (int i=ndims-1; i >=0; i-- ) {
137 int coord = coords[i];
139 /* The user can give us whatever coordinates he wants. If one of them is out of range, either this dimension is
140 * periodic, and we consider the equivalent coordinate inside the bounds, or it's not and then it's an error
142 if (coord >=dims_[i]) {
144 coord = coord %dims_[i];
146 // Should I do that ?
150 } else if (coord < 0) {
152 coord = coord %dims_[i];
154 coord =dims_[i] + coord;
161 *rank += multiplier * coord;
162 multiplier *=dims_[i];
167 int Topo_Cart::shift(int direction, int disp, int *rank_source, int *rank_dest) {
169 int position[ndims_];
174 if (ndims_ < direction) {
178 this->coords(getComm()->rank(), ndims_, position);
179 position[direction] += disp;
181 if(position[direction] < 0 ||
182 position[direction] >=dims_[direction]) {
183 if(periodic_[direction]) {
184 position[direction] %=dims_[direction];
185 this->rank(position, rank_dest);
187 *rank_dest = MPI_PROC_NULL;
190 this->rank(position, rank_dest);
193 position[direction] = position_[direction] - disp;
194 if(position[direction] < 0 || position[direction] >=dims_[direction]) {
195 if(periodic_[direction]) {
196 position[direction] %=dims_[direction];
197 this->rank(position, rank_source);
199 *rank_source = MPI_PROC_NULL;
202 this->rank(position, rank_source);
208 int Topo_Cart::dim_get(int *ndims) {
213 // Everything below has been taken from ompi, but could be easily rewritten (and partially was to follow sonar rules).
216 * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana
217 * University Research and Technology
218 * Corporation. All rights reserved.
219 * Copyright (c) 2004-2005 The University of Tennessee and The University
220 * of Tennessee Research Foundation. All rights
222 * Copyright (c) 2004-2014 High Performance Computing Center Stuttgart,
223 * University of Stuttgart. All rights reserved.
224 * Copyright (c) 2004-2005 The Regents of the University of California.
225 * All rights reserved.
226 * Copyright (c) 2012 Los Alamos National Security, LLC. All rights
228 * Copyright (c) 2014 Intel, Inc. All rights reserved
231 * Additional copyrights may follow
237 * This is a utility function, no need to have anything in the lower layer for this at all
239 int Topo_Cart::Dims_create(int nnodes, int ndims, int dims[])
241 /* Get # of free-to-be-assigned processes and # of free dimensions */
242 int freeprocs = nnodes;
245 for (int i = 0; i < ndims; ++i) {
248 } else if ((*p < 0) || ((nnodes % *p) != 0)) {
258 if (freeprocs == 1) {
264 if (freeprocs == 1) {
265 for (int i = 0; i < ndims; ++i) {
274 /* Factor the number of free processes */
277 int err = getfactors(freeprocs, &nfactors, &factors);
278 if (MPI_SUCCESS != err)
281 /* Assign free processes to free dimensions */
283 err = assignnodes(freedims, nfactors, factors, &procs);
284 if (MPI_SUCCESS != err)
287 /* Return assignment results */
289 for (int i = 0; i < ndims; ++i) {
309 * Function: - assign processes to dimensions
310 * - get "best-balanced" grid
311 * - greedy bin-packing algorithm used
312 * - sort dimensions in decreasing order
313 * - dimensions array dynamically allocated
314 * Accepts: - # of dimensions
315 * - # of prime factors
316 * - array of prime factors
317 * - ptr to array of dimensions (returned value)
318 * Returns: - 0 or ERROR
320 static int assignnodes(int ndim, int nfactor, int *pfacts, int **pdims)
328 /* Allocate and initialize the bins */
329 int *bins = new int[ndim];
334 for (int i = 0 ; i < ndim; ++i) {
338 /* Loop assigning factors from the highest to the lowest */
339 for (int j = nfactor - 1; j >= 0; --j) {
341 /* Assign a factor to the smallest bin */
344 for (int i = 1; i < ndim; ++i) {
353 /* Sort dimensions in decreasing order (O(n^2) for now) */
355 for (int i = 0; i < ndim - 1; ++i) {
357 for (int j = i + 1; j < ndim; ++j) {
374 * Function: - factorize a number
377 * - array of prime factors
378 * Returns: - MPI_SUCCESS or ERROR
380 static int getfactors(int num, int *nfactors, int **factors) {
383 (*factors) = nullptr;
386 /* Allocate the array of prime factors which cannot exceed log_2(num) entries */
387 int sqrtnum = ceil(sqrt(num));
388 int size = ceil(log(num) / log(2));
389 *factors = new int[size];
392 /* determine all occurrences of factor 2 */
393 while((num % 2) == 0) {
397 /* determine all occurrences of uneven prime numbers up to sqrt(num) */
398 for(int d = 3; (num > 1) && (d < sqrtnum); d += 2) {
399 while((num % d) == 0) {
404 /* as we looped only up to sqrt(num) one factor > sqrt(num) may be left over */
406 (*factors)[i++] = num;