-/* Copyright (c) 2014-2019. The SimGrid Team. All rights reserved. */
+/* Copyright (c) 2014-2022. The SimGrid Team. All rights reserved. */
/* This program is free software; you can redistribute it and/or modify it
* under the terms of the license (GNU LGPL) which comes with this package. */
#include "smpi_comm.hpp"
#include "smpi_topo.hpp"
#include "xbt/sysdep.h"
-#include <cmath>
+
+#include <algorithm>
#include <vector>
/* static functions */
-static int assignnodes(int ndim, int nfactor, int *pfacts,int **pdims);
-static int getfactors(int num, int *nfators, int **factors);
-
+static int assignnodes(int ndim, const std::vector<int>& factors, std::vector<int>& dims);
+static int getfactors(int num, std::vector<int>& factors);
namespace simgrid{
namespace smpi{
-Topo_Graph::~Topo_Graph()
-{
- delete[] index_;
- delete[] edges_;
-}
-
-Topo_Dist_Graph::~Topo_Dist_Graph()
+void Topo::setComm(MPI_Comm comm)
{
- delete[] in_;
- delete[] in_weights_;
- delete[] out_;
- delete[] out_weights_;
+ xbt_assert(not comm_);
+ comm_ = comm;
}
/*******************************************************************************
* Cartesian topologies
******************************************************************************/
-Topo_Cart::~Topo_Cart()
-{
- delete[] dims_;
- delete[] periodic_;
- delete[] position_;
-}
-Topo_Cart::Topo_Cart(int ndims) : ndims_(ndims)
+Topo_Cart::Topo_Cart(int ndims) : ndims_(ndims), dims_(ndims), periodic_(ndims), position_(ndims)
{
- dims_ = new int[ndims];
- periodic_ = new int[ndims];
- position_ = new int[ndims];
}
/* reorder is ignored, don't know what would be the consequences of a dumb reordering but neither do I see the point of
* reordering*/
-Topo_Cart::Topo_Cart(MPI_Comm comm_old, int ndims, int dims[], int periods[], int reorder, MPI_Comm *comm_cart) : Topo_Cart(ndims) {
- MPI_Group newGroup;
- MPI_Group oldGroup;
-
+Topo_Cart::Topo_Cart(MPI_Comm comm_old, int ndims, const int dims[], const int periods[], int /*reorder*/, MPI_Comm* comm_cart)
+ : Topo_Cart(ndims)
+{
int rank = comm_old->rank();
if(ndims != 0) {
newSize *= dims[i];
}
if(rank >= newSize) {
- *comm_cart = MPI_COMM_NULL;
+ if(comm_cart != nullptr)
+ *comm_cart = MPI_COMM_NULL;
return;
}
- oldGroup = comm_old->group();
- newGroup = new Group(newSize);
- for (int i = 0 ; i < newSize ; i++) {
- newGroup->set_mapping(oldGroup->actor(i), i);
- }
nnodes_ = newSize;
rank = rank % nranks;
}
- *comm_cart = new Comm(newGroup, this);
+ if(comm_cart != nullptr){
+ const Group* oldGroup = comm_old->group();
+ auto* newGroup = new Group(newSize);
+ for (int i = 0 ; i < newSize ; i++) {
+ newGroup->set_mapping(oldGroup->actor(i), i);
+ }
+ *comm_cart = new Comm(newGroup, std::shared_ptr<Topo>(this));
+ }
} else {
- if (rank == 0) {
- *comm_cart = new Comm(new Group(MPI_COMM_SELF->group()), this);
- } else {
- *comm_cart = MPI_COMM_NULL;
+ if(comm_cart != nullptr){
+ if (rank == 0) {
+ auto* group = new Group(MPI_COMM_SELF->group());
+ *comm_cart = new Comm(group, std::shared_ptr<Topo>(this));
+ } else {
+ *comm_cart = MPI_COMM_NULL;
+ }
}
}
- setComm(*comm_cart);
+ if(comm_cart != nullptr){
+ setComm(*comm_cart);
+ }
}
Topo_Cart* Topo_Cart::sub(const int remain_dims[], MPI_Comm *newcomm) {
int oldNDims = ndims_;
- int *newDims = nullptr;
- int *newPeriodic = nullptr;
+ std::vector<int> newDims;
+ std::vector<int> newPeriodic;
if (remain_dims == nullptr && oldNDims != 0) {
return nullptr;
}
if (newNDims > 0) {
- newDims = new int[newNDims];
- newPeriodic = new int[newNDims];
+ newDims.resize(newNDims);
+ newPeriodic.resize(newNDims);
// that should not segfault
int j = 0;
- for (int i = 0 ; j < newNDims ; i++) {
+ for (int i = 0; i < oldNDims; i++) {
if(remain_dims[i]) {
newDims[j] =dims_[i];
newPeriodic[j] =periodic_[i];
}
}
}
- Topo_Cart* res = new Topo_Cart(getComm(), newNDims, newDims, newPeriodic, 0, newcomm);
- delete[] newDims;
- delete[] newPeriodic;
+
+ //split into several communicators
+ int color = 0;
+ for (int i = 0; i < oldNDims; i++) {
+ if (not remain_dims[i]) {
+ color = (color * dims_[i] + position_[i]);
+ }
+ }
+ Topo_Cart* res;
+ if (newNDims == 0){
+ res = new Topo_Cart(getComm(), newNDims, newDims.data(), newPeriodic.data(), 0, newcomm);
+ } else {
+ *newcomm = getComm()->split(color, getComm()->rank());
+ auto topo = std::make_shared<Topo_Cart>(getComm(), newNDims, newDims.data(), newPeriodic.data(), 0, nullptr);
+ res = topo.get();
+ res->setComm(*newcomm);
+ (*newcomm)->set_topo(topo);
+ }
return res;
}
-int Topo_Cart::coords(int rank, int maxdims, int coords[]) {
+int Topo_Cart::coords(int rank, int /*maxdims*/, int coords[])
+{
int nnodes = nnodes_;
for (int i = 0; i< ndims_; i++ ) {
nnodes = nnodes /dims_[i];
return MPI_SUCCESS;
}
-int Topo_Cart::rank(int* coords, int* rank) {
+int Topo_Cart::rank(const int* coords, int* rank) {
int ndims =ndims_;
*rank = 0;
int multiplier = 1;
return MPI_SUCCESS;
}
-int Topo_Cart::shift(int direction, int disp, int *rank_source, int *rank_dest) {
-
- int position[ndims_];
-
+int Topo_Cart::shift(int direction, int disp, int* rank_source, int* rank_dest)
+{
if(ndims_ == 0) {
return MPI_ERR_ARG;
}
return MPI_ERR_DIMS;
}
- this->coords(getComm()->rank(), ndims_, position);
+ std::vector<int> position(ndims_);
+ this->coords(getComm()->rank(), ndims_, position.data());
position[direction] += disp;
if(position[direction] < 0 ||
position[direction] >=dims_[direction]) {
if(periodic_[direction]) {
position[direction] %=dims_[direction];
- this->rank(position, rank_dest);
+ this->rank(position.data(), rank_dest);
} else {
*rank_dest = MPI_PROC_NULL;
}
} else {
- this->rank(position, rank_dest);
+ this->rank(position.data(), rank_dest);
}
position[direction] = position_[direction] - disp;
if(position[direction] < 0 || position[direction] >=dims_[direction]) {
if(periodic_[direction]) {
position[direction] %=dims_[direction];
- this->rank(position, rank_source);
+ this->rank(position.data(), rank_source);
} else {
*rank_source = MPI_PROC_NULL;
}
} else {
- this->rank(position, rank_source);
+ this->rank(position.data(), rank_source);
}
-
return MPI_SUCCESS;
}
-int Topo_Cart::dim_get(int *ndims) {
+int Topo_Cart::dim_get(int* ndims) const
+{
*ndims =ndims_;
return MPI_SUCCESS;
}
/* Get # of free-to-be-assigned processes and # of free dimensions */
int freeprocs = nnodes;
int freedims = 0;
- int *p = dims;
for (int i = 0; i < ndims; ++i) {
- if (*p == 0) {
+ if (dims[i] == 0) {
++freedims;
- } else if ((*p < 0) || ((nnodes % *p) != 0)) {
+ } else if ((dims[i] < 0) || ((nnodes % dims[i]) != 0)) {
return MPI_ERR_DIMS;
} else {
- freeprocs /= *p;
+ freeprocs /= dims[i];
}
- p++;
}
if (freedims == 0) {
if (freeprocs == 1) {
for (int i = 0; i < ndims; ++i) {
- if (*dims == 0) {
- *dims = 1;
+ if (dims[i] == 0) {
+ dims[i] = 1;
}
- dims++;
}
return MPI_SUCCESS;
}
/* Factor the number of free processes */
- int nfactors;
- int *factors;
- int err = getfactors(freeprocs, &nfactors, &factors);
+ std::vector<int> factors;
+ int err = getfactors(freeprocs, factors);
if (MPI_SUCCESS != err)
return err;
/* Assign free processes to free dimensions */
- int *procs;
- err = assignnodes(freedims, nfactors, factors, &procs);
+ std::vector<int> procs;
+ err = assignnodes(freedims, factors, procs);
if (MPI_SUCCESS != err)
return err;
/* Return assignment results */
- p = procs;
+ auto p = procs.begin();
for (int i = 0; i < ndims; ++i) {
- if (*dims == 0) {
- *dims = *p++;
+ if (dims[i] == 0) {
+ dims[i] = *p++;
}
- dims++;
}
- delete[] factors;
- delete[] procs;
-
/* all done */
return MPI_SUCCESS;
}
* - sort dimensions in decreasing order
* - dimensions array dynamically allocated
* Accepts: - # of dimensions
- * - # of prime factors
- * - array of prime factors
- * - ptr to array of dimensions (returned value)
+ * - std::vector of prime factors
+ * - reference to std::vector of dimensions (returned value)
* Returns: - 0 or ERROR
*/
-static int assignnodes(int ndim, int nfactor, int *pfacts, int **pdims)
+static int assignnodes(int ndim, const std::vector<int>& factors, std::vector<int>& dims)
{
- int *pmin;
-
if (0 >= ndim) {
return MPI_ERR_DIMS;
}
/* Allocate and initialize the bins */
- int *bins = new int[ndim];
+ dims.clear();
+ dims.resize(ndim, 1);
- *pdims = bins;
- int *p = bins;
-
- for (int i = 0 ; i < ndim; ++i) {
- *p = 1;
- p++;
- }
/* Loop assigning factors from the highest to the lowest */
- for (int j = nfactor - 1; j >= 0; --j) {
- int f = pfacts[j];
+ for (auto pfact = factors.crbegin(); pfact != factors.crend(); ++pfact) {
/* Assign a factor to the smallest bin */
- pmin = bins;
- p = pmin + 1;
- for (int i = 1; i < ndim; ++i) {
- if (*p < *pmin) {
- pmin = p;
- }
- p++;
- }
- *pmin *= f;
+ auto pmin = std::min_element(dims.begin(), dims.end());
+ *pmin *= *pfact;
}
- /* Sort dimensions in decreasing order (O(n^2) for now) */
- pmin = bins;
- for (int i = 0; i < ndim - 1; ++i) {
- p = pmin + 1;
- for (int j = i + 1; j < ndim; ++j) {
- if (*p > *pmin) {
- int n = *p;
- *p = *pmin;
- *pmin = n;
- }
- p++;
- }
- pmin++;
- }
+ /* Sort dimensions in decreasing order */
+ std::sort(dims.begin(), dims.end(), std::greater<>());
return MPI_SUCCESS;
}
*
* Function: - factorize a number
* Accepts: - number
- * - # prime factors
- * - array of prime factors
+ * - reference to std::vector of prime factors
* Returns: - MPI_SUCCESS or ERROR
*/
-static int getfactors(int num, int *nfactors, int **factors) {
- if(num < 2) {
- (*nfactors) = 0;
- (*factors) = nullptr;
+static int getfactors(int num, std::vector<int>& factors)
+{
+ factors.clear();
+ if (num < 2) {
return MPI_SUCCESS;
}
- /* Allocate the array of prime factors which cannot exceed log_2(num) entries */
- int sqrtnum = ceil(sqrt(num));
- int size = ceil(log(num) / log(2));
- *factors = new int[size];
- int i = 0;
/* determine all occurrences of factor 2 */
while((num % 2) == 0) {
num /= 2;
- (*factors)[i++] = 2;
+ factors.push_back(2);
}
/* determine all occurrences of uneven prime numbers up to sqrt(num) */
- for(int d = 3; (num > 1) && (d < sqrtnum); d += 2) {
+ int d = 3;
+ while ((num > 1) && (d * d < num)) {
while((num % d) == 0) {
num /= d;
- (*factors)[i++] = d;
+ factors.push_back(d);
}
+ d += 2;
}
/* as we looped only up to sqrt(num) one factor > sqrt(num) may be left over */
if(num != 1) {
- (*factors)[i++] = num;
+ factors.push_back(num);
}
- (*nfactors) = i;
return MPI_SUCCESS;
}
-